Merge "Prevent race condition by foregroundAppPackageName" into tm-qpr-dev
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 65b2511..c10c380 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -26,6 +26,8 @@
 
 hidden_api_txt_exclude_hook = ${REPO_ROOT}/frameworks/base/tools/hiddenapi/exclude.sh ${PREUPLOAD_COMMIT} ${REPO_ROOT}
 
+ktfmt_hook = ${REPO_ROOT}/external/ktfmt/ktfmt.py --check -i ${REPO_ROOT}/frameworks/base/ktfmt_includes.txt ${PREUPLOAD_FILES}
+
 ktlint_hook = ${REPO_ROOT}/prebuilts/ktlint/ktlint.py -f ${PREUPLOAD_FILES}
 
 owners_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "OWNERS$"
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
index c92c634..fb62920 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
@@ -153,9 +153,9 @@
             final IWindowSession session = WindowManagerGlobal.getWindowSession();
             while (state.keepRunning()) {
                 session.relayout(mWindow, mParams, mWidth, mHeight,
-                        mViewVisibility.getAsInt(), mFlags, mOutFrames,
-                        mOutMergedConfiguration, mOutSurfaceControl, mOutInsetsState, mOutControls,
-                        new Bundle());
+                        mViewVisibility.getAsInt(), mFlags, 0 /* seq */, 0 /* lastSyncSeqId */,
+                        mOutFrames, mOutMergedConfiguration, mOutSurfaceControl, mOutInsetsState,
+                        mOutControls, new Bundle());
             }
         }
     }
diff --git a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/UiDevice.java b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/UiDevice.java
index b1b432b..6fd2bf2 100644
--- a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/UiDevice.java
+++ b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/UiDevice.java
@@ -380,7 +380,7 @@
         Tracer.trace();
         Display display = getAutomatorBridge().getDefaultDisplay();
         Point p = new Point();
-        display.getSize(p);
+        display.getRealSize(p);
         return p.x;
     }
 
@@ -394,7 +394,7 @@
         Tracer.trace();
         Display display = getAutomatorBridge().getDefaultDisplay();
         Point p = new Point();
-        display.getSize(p);
+        display.getRealSize(p);
         return p.y;
     }
 
diff --git a/core/java/Android.bp b/core/java/Android.bp
index 77589a2..a7d4342b 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -15,14 +15,6 @@
         "**/*.java",
         "**/*.aidl",
     ],
-    exclude_srcs: [
-        // Remove election toolbar code from build time
-        "android/service/selectiontoolbar/*.aidl",
-        "android/service/selectiontoolbar/*.java",
-        "android/view/selectiontoolbar/*.aidl",
-        "android/view/selectiontoolbar/*.java",
-        "com/android/internal/widget/floatingtoolbar/RemoteFloatingToolbarPopup.java",
-    ],
     visibility: ["//frameworks/base"],
 }
 
diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java
index 58ddd49..13934e5 100644
--- a/core/java/android/app/PropertyInvalidatedCache.java
+++ b/core/java/android/app/PropertyInvalidatedCache.java
@@ -310,6 +310,21 @@
     public static final String MODULE_TELEPHONY = "telephony";
 
     /**
+     * Constants that affect retries when the process is unable to write the property.
+     * The first constant is the number of times the process will attempt to set the
+     * property.  The second constant is the delay between attempts.
+     */
+
+    /**
+     * Wait 200ms between retry attempts and the retry limit is 5.  That gives a total possible
+     * delay of 1s, which should be less than ANR timeouts.  The goal is to have the system crash
+     * because the property could not be set (which is a condition that is easily recognized) and
+     * not crash because of an ANR (which can be confusing to debug).
+     */
+    private static final int PROPERTY_FAILURE_RETRY_DELAY_MILLIS = 200;
+    private static final int PROPERTY_FAILURE_RETRY_LIMIT = 5;
+
+    /**
      * Construct a system property that matches the rules described above.  The module is
      * one of the permitted values above.  The API is a string that is a legal Java simple
      * identifier.  The api is modified to conform to the system property style guide by
@@ -670,7 +685,33 @@
                 }
             }
         }
-        SystemProperties.set(name, Long.toString(val));
+        RuntimeException failure = null;
+        for (int attempt = 0; attempt < PROPERTY_FAILURE_RETRY_LIMIT; attempt++) {
+            try {
+                SystemProperties.set(name, Long.toString(val));
+                if (attempt > 0) {
+                    // This log is not guarded.  Based on known bug reports, it should
+                    // occur once a week or less.  The purpose of the log message is to
+                    // identify the retries as a source of delay that might be otherwise
+                    // be attributed to the cache itself.
+                    Log.w(TAG, "Nonce set after " + attempt + " tries");
+                }
+                return;
+            } catch (RuntimeException e) {
+                if (failure == null) {
+                    failure = e;
+                }
+                try {
+                    Thread.sleep(PROPERTY_FAILURE_RETRY_DELAY_MILLIS);
+                } catch (InterruptedException x) {
+                    // Ignore this exception.  The desired delay is only approximate and
+                    // there is no issue if the sleep sometimes terminates early.
+                }
+            }
+        }
+        // This point is reached only if SystemProperties.set() fails at least once.
+        // Rethrow the first exception that was received.
+        throw failure;
     }
 
     // Set the nonce in a static context.  No handle is available.
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 4019283..6615374 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -230,6 +230,8 @@
 import android.view.contentcapture.IContentCaptureManager;
 import android.view.displayhash.DisplayHashManager;
 import android.view.inputmethod.InputMethodManager;
+import android.view.selectiontoolbar.ISelectionToolbarManager;
+import android.view.selectiontoolbar.SelectionToolbarManager;
 import android.view.textclassifier.TextClassificationManager;
 import android.view.textservice.TextServicesManager;
 import android.view.translation.ITranslationManager;
@@ -363,6 +365,15 @@
                 return new TextClassificationManager(ctx);
             }});
 
+        registerService(Context.SELECTION_TOOLBAR_SERVICE, SelectionToolbarManager.class,
+                new CachedServiceFetcher<SelectionToolbarManager>() {
+                    @Override
+                    public SelectionToolbarManager createService(ContextImpl ctx) {
+                        IBinder b = ServiceManager.getService(Context.SELECTION_TOOLBAR_SERVICE);
+                        return new SelectionToolbarManager(ctx.getOuterContext(),
+                                ISelectionToolbarManager.Stub.asInterface(b));
+                    }});
+
         registerService(Context.FONT_SERVICE, FontManager.class,
                 new CachedServiceFetcher<FontManager>() {
             @Override
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index a3d595ef..0bbe8c4 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1109,6 +1109,16 @@
     public static final float OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE = 16 / 9f;
 
     /**
+     * Enables the use of split screen aspect ratio. This allows an app to use all the available
+     * space in split mode avoiding letterboxing.
+     * @hide
+     */
+    @ChangeId
+    @Disabled
+    @Overridable
+    public static final long OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN = 208648326L;
+
+    /**
      * Compares activity window layout min width/height with require space for multi window to
      * determine if it can be put into multi window mode.
      */
@@ -1317,8 +1327,8 @@
      * Returns true if the activity has maximum or minimum aspect ratio.
      * @hide
      */
-    public boolean hasFixedAspectRatio(@ScreenOrientation int orientation) {
-        return getMaxAspectRatio() != 0 || getMinAspectRatio(orientation) != 0;
+    public boolean hasFixedAspectRatio() {
+        return getMaxAspectRatio() != 0 || getMinAspectRatio() != 0;
     }
 
     /**
@@ -1460,30 +1470,10 @@
     }
 
     /**
-     * Returns the min aspect ratio of this activity.
-     *
-     * This takes into account the minimum aspect ratio as defined in the app's manifest and
-     * possible overrides as per OVERRIDE_MIN_ASPECT_RATIO.
-     *
-     * In the rare cases where the manifest minimum aspect ratio is required, use
-     * {@code getManifestMinAspectRatio}.
+     * Returns the min aspect ratio of this activity as defined in the manifest file.
      * @hide
      */
-    public float getMinAspectRatio(@ScreenOrientation int orientation) {
-        if (applicationInfo == null || !isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO) || (
-                isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY)
-                        && !isFixedOrientationPortrait(orientation))) {
-            return mMinAspectRatio;
-        }
-
-        if (isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_LARGE)) {
-            return Math.max(OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE, mMinAspectRatio);
-        }
-
-        if (isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_MEDIUM)) {
-            return Math.max(OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE, mMinAspectRatio);
-        }
-
+    public float getMinAspectRatio() {
         return mMinAspectRatio;
     }
 
@@ -1512,7 +1502,13 @@
         }
     }
 
-    private boolean isChangeEnabled(long changeId) {
+    /**
+     * Checks if a changeId is enabled for the current user
+     * @param changeId The changeId to verify
+     * @return True of the changeId is enabled
+     * @hide
+     */
+    public boolean isChangeEnabled(long changeId) {
         return CompatChanges.isChangeEnabled(changeId, applicationInfo.packageName,
                 UserHandle.getUserHandleForUid(applicationInfo.uid));
     }
@@ -1633,12 +1629,9 @@
         if (getMaxAspectRatio() != 0) {
             pw.println(prefix + "maxAspectRatio=" + getMaxAspectRatio());
         }
-        final float minAspectRatio = getMinAspectRatio(screenOrientation);
+        final float minAspectRatio = getMinAspectRatio();
         if (minAspectRatio != 0) {
             pw.println(prefix + "minAspectRatio=" + minAspectRatio);
-            if (getManifestMinAspectRatio() !=  minAspectRatio) {
-                pw.println(prefix + "getManifestMinAspectRatio=" + getManifestMinAspectRatio());
-            }
         }
         if (supportsSizeChanges) {
             pw.println(prefix + "supportsSizeChanges=true");
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 0f1b39c..df1c0d7 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -892,7 +892,7 @@
      * <tr><th colspan="7">Preview stabilization guaranteed stream configurations</th></tr>
      * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th rowspan="2">Sample use case(s)</th> </tr>
      * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr>
-     * <tr> <td>{@code PRIV / YUV}</td><td id="rb">{@code s1440p}</td><td colspan="4" id="rb"></td> <td>Stabilized preview, GPU video processing, or no-preview stabilized video recording.</td> </tr>
+     * <tr> <td>{@code PRIV / YUV}</td><td id="rb">{@code s1440p}</td><td colspan="2" id="rb"></td> <td>Stabilized preview, GPU video processing, or no-preview stabilized video recording.</td> </tr>
      * <tr> <td>{@code PRIV / YUV}</td><td id="rb">{@code s1440p}</td> <td>{@code JPEG / YUV}</td><td id="rb">{@code MAXIMUM }</td><td>Standard still imaging with stabilized preview.</td> </tr>
      * <tr> <td>{@code PRIV / YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV / YUV}</td><td id="rb">{@code s1440p }</td><td>High-resolution recording with stabilized preview and recording stream.</td> </tr>
      * </table><br>
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 8e67705..ce7b5e1 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -148,6 +148,7 @@
 import com.android.internal.inputmethod.InputMethodNavButtonFlags;
 import com.android.internal.inputmethod.InputMethodPrivilegedOperations;
 import com.android.internal.inputmethod.InputMethodPrivilegedOperationsRegistry;
+import com.android.internal.inputmethod.SoftInputShowHideReason;
 import com.android.internal.util.RingBuffer;
 import com.android.internal.view.IInlineSuggestionsRequestCallback;
 import com.android.internal.view.IInputContext;
@@ -2962,9 +2963,13 @@
      * @param flags Provides additional operating flags.
      */
     public void requestHideSelf(int flags) {
+        requestHideSelf(flags, SoftInputShowHideReason.HIDE_SOFT_INPUT_FROM_IME);
+    }
+
+    private void requestHideSelf(int flags, @SoftInputShowHideReason int reason) {
         ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestHideSelf", mDumper,
                 null /* icProto */);
-        mPrivOps.hideMySoftInput(flags);
+        mPrivOps.hideMySoftInput(flags, reason);
     }
 
     /**
@@ -2985,7 +2990,9 @@
         if (mShowInputRequested) {
             // If the soft input area is shown, back closes it and we
             // consume the back key.
-            if (doIt) requestHideSelf(0);
+            if (doIt) {
+                requestHideSelf(0 /* flags */, SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_BACK_KEY);
+            }
             return true;
         } else if (mDecorViewVisible) {
             if (mCandidatesVisibility == View.VISIBLE) {
@@ -3136,7 +3143,8 @@
     private void onToggleSoftInput(int showFlags, int hideFlags) {
         if (DEBUG) Log.v(TAG, "toggleSoftInput()");
         if (isInputViewShown()) {
-            requestHideSelf(hideFlags);
+            requestHideSelf(
+                    hideFlags, SoftInputShowHideReason.HIDE_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT);
         } else {
             requestShowSelf(showFlags);
         }
@@ -3571,7 +3579,8 @@
      */
     public void onExtractingInputChanged(EditorInfo ei) {
         if (ei.inputType == InputType.TYPE_NULL) {
-            requestHideSelf(InputMethodManager.HIDE_NOT_ALWAYS);
+            requestHideSelf(InputMethodManager.HIDE_NOT_ALWAYS,
+                    SoftInputShowHideReason.HIDE_SOFT_INPUT_EXTRACT_INPUT_CHANGED);
         }
     }
 
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 13a3ec8..fd4b94a 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -623,7 +623,7 @@
     private static final List<String> PUBLIC_NAMESPACES =
             Arrays.asList(NAMESPACE_TEXTCLASSIFIER, NAMESPACE_RUNTIME, NAMESPACE_STATSD_JAVA,
                     NAMESPACE_STATSD_JAVA_BOOT, NAMESPACE_SELECTION_TOOLBAR, NAMESPACE_AUTOFILL,
-                    NAMESPACE_DEVICE_POLICY_MANAGER);
+                    NAMESPACE_DEVICE_POLICY_MANAGER, NAMESPACE_CONTENT_CAPTURE);
     /**
      * Privacy related properties definitions.
      *
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ce35461..a76524a 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5482,6 +5482,15 @@
         public static final String MULTI_AUDIO_FOCUS_ENABLED = "multi_audio_focus_enabled";
 
         /**
+         * Whether desktop mode is enabled or not.
+         * 0 = off
+         * 1 = on
+         * @hide
+         */
+        @Readable
+        public static final String DESKTOP_MODE = "desktop_mode";
+
+        /**
          * IMPORTANT: If you add a new public settings you also have to add it to
          * PUBLIC_SETTINGS below. If the new setting is hidden you have to add
          * it to PRIVATE_SETTINGS below. Also add a validator that can validate
@@ -5610,6 +5619,7 @@
             PRIVATE_SETTINGS.add(SHOW_BATTERY_PERCENT);
             PRIVATE_SETTINGS.add(DISPLAY_COLOR_MODE);
             PRIVATE_SETTINGS.add(DISPLAY_COLOR_MODE_VENDOR_HINT);
+            PRIVATE_SETTINGS.add(DESKTOP_MODE);
         }
 
         /**
diff --git a/core/java/android/service/selectiontoolbar/DefaultSelectionToolbarRenderService.java b/core/java/android/service/selectiontoolbar/DefaultSelectionToolbarRenderService.java
index f028ed3..ad73a53 100644
--- a/core/java/android/service/selectiontoolbar/DefaultSelectionToolbarRenderService.java
+++ b/core/java/android/service/selectiontoolbar/DefaultSelectionToolbarRenderService.java
@@ -69,7 +69,7 @@
 
         if (mToolbarCache.indexOfKey(callingUid) < 0) {
             RemoteSelectionToolbar toolbar = new RemoteSelectionToolbar(this,
-                    widgetToken, showInfo.getHostInputToken(),
+                    widgetToken, showInfo,
                     callbackWrapper, this::transferTouch);
             mToolbarCache.put(callingUid, new Pair<>(widgetToken, toolbar));
         }
diff --git a/core/java/android/service/selectiontoolbar/RemoteSelectionToolbar.java b/core/java/android/service/selectiontoolbar/RemoteSelectionToolbar.java
index d75fbc0..95bcda5 100644
--- a/core/java/android/service/selectiontoolbar/RemoteSelectionToolbar.java
+++ b/core/java/android/service/selectiontoolbar/RemoteSelectionToolbar.java
@@ -22,7 +22,6 @@
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.content.Context;
-import android.content.res.TypedArray;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.drawable.AnimatedVectorDrawable;
@@ -162,15 +161,14 @@
     private final Rect mTempContentRectForRoot = new Rect();
     private final int[] mTempCoords = new int[2];
 
-    RemoteSelectionToolbar(Context context, long selectionToolbarToken, IBinder hostInputToken,
+    RemoteSelectionToolbar(Context context, long selectionToolbarToken, ShowInfo showInfo,
             SelectionToolbarRenderService.RemoteCallbackWrapper callbackWrapper,
             SelectionToolbarRenderService.TransferTouchListener transferTouchListener) {
-        mContext = applyDefaultTheme(context);
+        mContext = applyDefaultTheme(context, showInfo.isIsLightTheme());
         mSelectionToolbarToken = selectionToolbarToken;
         mCallbackWrapper = callbackWrapper;
         mTransferTouchListener = transferTouchListener;
-        mHostInputToken = hostInputToken;
-
+        mHostInputToken = showInfo.getHostInputToken();
         mContentContainer = createContentContainer(mContext);
         mMarginHorizontal = mContext.getResources()
                 .getDimensionPixelSize(R.dimen.floating_toolbar_horizontal_margin);
@@ -1359,12 +1357,9 @@
     /**
      * Returns a re-themed context with controlled look and feel for views.
      */
-    private static Context applyDefaultTheme(Context originalContext) {
-        TypedArray a = originalContext.obtainStyledAttributes(new int[]{R.attr.isLightTheme});
-        boolean isLightTheme = a.getBoolean(0, true);
+    private static Context applyDefaultTheme(Context originalContext, boolean isLightTheme) {
         int themeId =
                 isLightTheme ? R.style.Theme_DeviceDefault_Light : R.style.Theme_DeviceDefault;
-        a.recycle();
         return new ContextThemeWrapper(originalContext, themeId);
     }
 
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 90e4e94..14cfe6a 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -1154,8 +1154,8 @@
                         mLayout.surfaceInsets.set(0, 0, 0, 0);
                     }
                     final int relayoutResult = mSession.relayout(mWindow, mLayout, mWidth, mHeight,
-                            View.VISIBLE, 0, mWinFrames, mMergedConfiguration, mSurfaceControl,
-                            mInsetsState, mTempControls, mSyncSeqIdBundle);
+                            View.VISIBLE, 0, 0, 0, mWinFrames, mMergedConfiguration,
+                            mSurfaceControl, mInsetsState, mTempControls, mSyncSeqIdBundle);
 
                     final int transformHint = SurfaceControl.rotationToBufferTransform(
                             (mDisplayInstallOrientation + mDisplay.getRotation()) % 4);
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 3016473..afcec66 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -75,41 +75,42 @@
      * @param requestedWidth The width the window wants to be.
      * @param requestedHeight The height the window wants to be.
      * @param viewVisibility Window root view's visibility.
-     * @param flags Request flags: {@link WindowManagerGlobal#RELAYOUT_INSETS_PENDING},
-     * {@link WindowManagerGlobal#RELAYOUT_DEFER_SURFACE_DESTROY}.
-     * @param outFrame Rect in which is placed the new position/size on
-     * screen.
-     * @param outContentInsets Rect in which is placed the offsets from
-     * <var>outFrame</var> in which the content of the window should be
-     * placed.  This can be used to modify the window layout to ensure its
-     * contents are visible to the user, taking into account system windows
-     * like the status bar or a soft keyboard.
-     * @param outVisibleInsets Rect in which is placed the offsets from
-     * <var>outFrame</var> in which the window is actually completely visible
-     * to the user.  This can be used to temporarily scroll the window's
-     * contents to make sure the user can see it.  This is different than
-     * <var>outContentInsets</var> in that these insets change transiently,
-     * so complex relayout of the window should not happen based on them.
-     * @param outOutsets Rect in which is placed the dead area of the screen that we would like to
-     * treat as real display. Example of such area is a chin in some models of wearable devices.
-     * @param outBackdropFrame Rect which is used draw the resizing background during a resize
-     * operation.
+     * @param flags Request flags: {@link WindowManagerGlobal#RELAYOUT_INSETS_PENDING}.
+     * @param seq The calling sequence of {@link #relayout} and {@link #relayoutAsync}.
+     * @param lastSyncSeqId The last SyncSeqId that the client applied.
+     * @param outFrames The window frames used by the client side for layout.
      * @param outMergedConfiguration New config container that holds global, override and merged
-     * config for window, if it is now becoming visible and the merged configuration has changed
-     * since it was last displayed.
-     * @param outSurface Object in which is placed the new display surface.
+     *                               config for window, if it is now becoming visible and the merged
+     *                               config has changed since it was last displayed.
+     * @param outSurfaceControl Object in which is placed the new display surface.
      * @param insetsState The current insets state in the system.
-     *
-     * @return int Result flags: {@link WindowManagerGlobal#RELAYOUT_SHOW_FOCUS},
-     * {@link WindowManagerGlobal#RELAYOUT_FIRST_TIME}.
+     * @param activeControls Objects which allow controlling {@link InsetsSource}s.
+     * @param bundle A temporary object to obtain the latest SyncSeqId.
+     * @return int Result flags, defined in {@link WindowManagerGlobal}.
      */
     int relayout(IWindow window, in WindowManager.LayoutParams attrs,
             int requestedWidth, int requestedHeight, int viewVisibility,
-            int flags, out ClientWindowFrames outFrames,
+            int flags, int seq, int lastSyncSeqId, out ClientWindowFrames outFrames,
             out MergedConfiguration outMergedConfiguration, out SurfaceControl outSurfaceControl,
             out InsetsState insetsState, out InsetsSourceControl[] activeControls,
             out Bundle bundle);
 
+    /**
+     * Similar to {@link #relayout} but this is an oneway method which doesn't return anything.
+     *
+     * @param window The window being modified.
+     * @param attrs If non-null, new attributes to apply to the window.
+     * @param requestedWidth The width the window wants to be.
+     * @param requestedHeight The height the window wants to be.
+     * @param viewVisibility Window root view's visibility.
+     * @param flags Request flags: {@link WindowManagerGlobal#RELAYOUT_INSETS_PENDING}.
+     * @param seq The calling sequence of {@link #relayout} and {@link #relayoutAsync}.
+     * @param lastSyncSeqId The last SyncSeqId that the client applied.
+     */
+    oneway void relayoutAsync(IWindow window, in WindowManager.LayoutParams attrs,
+            int requestedWidth, int requestedHeight, int viewVisibility, int flags, int seq,
+            int lastSyncSeqId);
+
     /*
      * Notify the window manager that an application is relaunching and
      * windows should be prepared for replacement.
diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java
index d75ff2f..5721fa6 100644
--- a/core/java/android/view/SurfaceControlViewHost.java
+++ b/core/java/android/view/SurfaceControlViewHost.java
@@ -422,7 +422,7 @@
     public void relayout(WindowManager.LayoutParams attrs,
             WindowlessWindowManager.ResizeCompleteCallback callback) {
         mViewRoot.setLayoutParams(attrs, false);
-        mViewRoot.setReportNextDraw(true /* syncBuffer */);
+        mViewRoot.setReportNextDraw(true /* syncBuffer */, "scvh_relayout");
         mWm.setCompletionCallback(mViewRoot.mWindow.asBinder(), callback);
     }
 
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 536a0ac..0927bc7 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -724,9 +724,9 @@
 
     private void releaseSurfaces(boolean releaseSurfacePackage) {
         mSurfaceAlpha = 1f;
-        mSurface.destroy();
 
         synchronized (mSurfaceControlLock) {
+            mSurface.destroy();
             if (mBlastBufferQueue != null) {
                 mBlastBufferQueue.destroy();
                 mBlastBufferQueue = null;
@@ -775,99 +775,105 @@
             Transaction surfaceUpdateTransaction) {
         boolean realSizeChanged = false;
 
-        mDrawingStopped = !mVisible;
+        mSurfaceLock.lock();
+        try {
+            mDrawingStopped = !mVisible;
 
-        if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
-                + "Cur surface: " + mSurface);
+            if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+                    + "Cur surface: " + mSurface);
 
-        // If we are creating the surface control or the parent surface has not
-        // changed, then set relative z. Otherwise allow the parent
-        // SurfaceChangedCallback to update the relative z. This is needed so that
-        // we do not change the relative z before the server is ready to swap the
-        // parent surface.
-        if (creating) {
-            updateRelativeZ(surfaceUpdateTransaction);
-            if (mSurfacePackage != null) {
-                reparentSurfacePackage(surfaceUpdateTransaction, mSurfacePackage);
+            // If we are creating the surface control or the parent surface has not
+            // changed, then set relative z. Otherwise allow the parent
+            // SurfaceChangedCallback to update the relative z. This is needed so that
+            // we do not change the relative z before the server is ready to swap the
+            // parent surface.
+            if (creating) {
+                updateRelativeZ(surfaceUpdateTransaction);
+                if (mSurfacePackage != null) {
+                    reparentSurfacePackage(surfaceUpdateTransaction, mSurfacePackage);
+                }
             }
-        }
-        mParentSurfaceSequenceId = viewRoot.getSurfaceSequenceId();
+            mParentSurfaceSequenceId = viewRoot.getSurfaceSequenceId();
 
-        if (mViewVisibility) {
-            surfaceUpdateTransaction.show(mSurfaceControl);
-        } else {
-            surfaceUpdateTransaction.hide(mSurfaceControl);
-        }
-
-
-
-        updateBackgroundVisibility(surfaceUpdateTransaction);
-        updateBackgroundColor(surfaceUpdateTransaction);
-        if (mUseAlpha) {
-            float alpha = getFixedAlpha();
-            surfaceUpdateTransaction.setAlpha(mSurfaceControl, alpha);
-            mSurfaceAlpha = alpha;
-        }
-
-        surfaceUpdateTransaction.setCornerRadius(mSurfaceControl, mCornerRadius);
-        if ((sizeChanged || hintChanged) && !creating) {
-            setBufferSize(surfaceUpdateTransaction);
-        }
-        if (sizeChanged || creating || !isHardwareAccelerated()) {
-            // Set a window crop when creating the surface or changing its size to
-            // crop the buffer to the surface size since the buffer producer may
-            // use SCALING_MODE_SCALE and submit a larger size than the surface
-            // size.
-            if (mClipSurfaceToBounds && mClipBounds != null) {
-                surfaceUpdateTransaction.setWindowCrop(mSurfaceControl, mClipBounds);
+            if (mViewVisibility) {
+                surfaceUpdateTransaction.show(mSurfaceControl);
             } else {
-                surfaceUpdateTransaction.setWindowCrop(mSurfaceControl, mSurfaceWidth,
-                        mSurfaceHeight);
+                surfaceUpdateTransaction.hide(mSurfaceControl);
             }
 
-            surfaceUpdateTransaction.setDesintationFrame(mBlastSurfaceControl, mSurfaceWidth,
-                        mSurfaceHeight);
 
-            if (isHardwareAccelerated()) {
-                // This will consume the passed in transaction and the transaction will be
-                // applied on a render worker thread.
-                replacePositionUpdateListener(mSurfaceWidth, mSurfaceHeight);
+
+            updateBackgroundVisibility(surfaceUpdateTransaction);
+            updateBackgroundColor(surfaceUpdateTransaction);
+            if (mUseAlpha) {
+                float alpha = getFixedAlpha();
+                surfaceUpdateTransaction.setAlpha(mSurfaceControl, alpha);
+                mSurfaceAlpha = alpha;
+            }
+
+            surfaceUpdateTransaction.setCornerRadius(mSurfaceControl, mCornerRadius);
+            if ((sizeChanged || hintChanged) && !creating) {
+                setBufferSize(surfaceUpdateTransaction);
+            }
+            if (sizeChanged || creating || !isHardwareAccelerated()) {
+
+                // Set a window crop when creating the surface or changing its size to
+                // crop the buffer to the surface size since the buffer producer may
+                // use SCALING_MODE_SCALE and submit a larger size than the surface
+                // size.
+                if (mClipSurfaceToBounds && mClipBounds != null) {
+                    surfaceUpdateTransaction.setWindowCrop(mSurfaceControl, mClipBounds);
+                } else {
+                    surfaceUpdateTransaction.setWindowCrop(mSurfaceControl, mSurfaceWidth,
+                            mSurfaceHeight);
+                }
+
+                surfaceUpdateTransaction.setDesintationFrame(mBlastSurfaceControl, mSurfaceWidth,
+                            mSurfaceHeight);
+
+                if (isHardwareAccelerated()) {
+                    // This will consume the passed in transaction and the transaction will be
+                    // applied on a render worker thread.
+                    replacePositionUpdateListener(mSurfaceWidth, mSurfaceHeight);
+                } else {
+                    onSetSurfacePositionAndScale(surfaceUpdateTransaction, mSurfaceControl,
+                            mScreenRect.left /*positionLeft*/,
+                            mScreenRect.top /*positionTop*/,
+                            mScreenRect.width() / (float) mSurfaceWidth /*postScaleX*/,
+                            mScreenRect.height() / (float) mSurfaceHeight /*postScaleY*/);
+                }
+                if (DEBUG_POSITION) {
+                    Log.d(TAG, String.format(
+                            "%d performSurfaceTransaction %s "
+                                + "position = [%d, %d, %d, %d] surfaceSize = %dx%d",
+                            System.identityHashCode(this),
+                            isHardwareAccelerated() ? "RenderWorker" : "UI Thread",
+                            mScreenRect.left, mScreenRect.top, mScreenRect.right,
+                            mScreenRect.bottom, mSurfaceWidth, mSurfaceHeight));
+                }
+            }
+            applyTransactionOnVriDraw(surfaceUpdateTransaction);
+            updateEmbeddedAccessibilityMatrix(false);
+
+            mSurfaceFrame.left = 0;
+            mSurfaceFrame.top = 0;
+            if (translator == null) {
+                mSurfaceFrame.right = mSurfaceWidth;
+                mSurfaceFrame.bottom = mSurfaceHeight;
             } else {
-                onSetSurfacePositionAndScale(surfaceUpdateTransaction, mSurfaceControl,
-                        mScreenRect.left /*positionLeft*/,
-                        mScreenRect.top /*positionTop*/,
-                        mScreenRect.width() / (float) mSurfaceWidth /*postScaleX*/,
-                        mScreenRect.height() / (float) mSurfaceHeight /*postScaleY*/);
+                float appInvertedScale = translator.applicationInvertedScale;
+                mSurfaceFrame.right = (int) (mSurfaceWidth * appInvertedScale + 0.5f);
+                mSurfaceFrame.bottom = (int) (mSurfaceHeight * appInvertedScale + 0.5f);
             }
-            if (DEBUG_POSITION) {
-                Log.d(TAG, String.format(
-                        "%d performSurfaceTransaction %s "
-                            + "position = [%d, %d, %d, %d] surfaceSize = %dx%d",
-                        System.identityHashCode(this),
-                        isHardwareAccelerated() ? "RenderWorker" : "UI Thread",
-                        mScreenRect.left, mScreenRect.top, mScreenRect.right,
-                        mScreenRect.bottom, mSurfaceWidth, mSurfaceHeight));
-            }
+            final int surfaceWidth = mSurfaceFrame.right;
+            final int surfaceHeight = mSurfaceFrame.bottom;
+            realSizeChanged = mLastSurfaceWidth != surfaceWidth
+                    || mLastSurfaceHeight != surfaceHeight;
+            mLastSurfaceWidth = surfaceWidth;
+            mLastSurfaceHeight = surfaceHeight;
+        } finally {
+            mSurfaceLock.unlock();
         }
-        applyTransactionOnVriDraw(surfaceUpdateTransaction);
-        updateEmbeddedAccessibilityMatrix(false);
-         mSurfaceFrame.left = 0;
-        mSurfaceFrame.top = 0;
-        if (translator == null) {
-            mSurfaceFrame.right = mSurfaceWidth;
-            mSurfaceFrame.bottom = mSurfaceHeight;
-        } else {
-            float appInvertedScale = translator.applicationInvertedScale;
-            mSurfaceFrame.right = (int) (mSurfaceWidth * appInvertedScale + 0.5f);
-            mSurfaceFrame.bottom = (int) (mSurfaceHeight * appInvertedScale + 0.5f);
-        }
-        final int surfaceWidth = mSurfaceFrame.right;
-        final int surfaceHeight = mSurfaceFrame.bottom;
-        realSizeChanged = mLastSurfaceWidth != surfaceWidth
-                || mLastSurfaceHeight != surfaceHeight;
-        mLastSurfaceWidth = surfaceWidth;
-        mLastSurfaceHeight = surfaceHeight;
-
         return realSizeChanged;
     }
 
@@ -1133,30 +1139,21 @@
      *                          Surface for compatibility reasons.
      */
     private void copySurface(boolean surfaceControlCreated, boolean bufferSizeChanged) {
-        // Some legacy applications use the underlying native {@link Surface} object
-        // as a key to whether anything has changed. In these cases, updates to the
-        // existing {@link Surface} will be ignored when the size changes.
-        // Therefore, we must explicitly recreate the {@link Surface} in these
-        // cases.
-        boolean needsWorkaround = bufferSizeChanged &&
-            getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.O;
-       if (!surfaceControlCreated && !needsWorkaround) {
-           return;
-       }
-       mSurfaceLock.lock();
-       try {
-           if (surfaceControlCreated) {
-               mSurface.copyFrom(mBlastBufferQueue);
-           }
+        if (surfaceControlCreated) {
+            mSurface.copyFrom(mBlastBufferQueue);
+        }
 
-           if (needsWorkaround) {
-               if (mBlastBufferQueue != null) {
-                   mSurface.transferFrom(mBlastBufferQueue.createSurfaceWithHandle());
-               }
-           }
-       } finally {
-           mSurfaceLock.unlock();
-       }
+        if (bufferSizeChanged && getContext().getApplicationInfo().targetSdkVersion
+                < Build.VERSION_CODES.O) {
+            // Some legacy applications use the underlying native {@link Surface} object
+            // as a key to whether anything has changed. In these cases, updates to the
+            // existing {@link Surface} will be ignored when the size changes.
+            // Therefore, we must explicitly recreate the {@link Surface} in these
+            // cases.
+            if (mBlastBufferQueue != null) {
+                mSurface.transferFrom(mBlastBufferQueue.createSurfaceWithHandle());
+            }
+        }
     }
 
     private void setBufferSize(Transaction transaction) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index fa37ca1..af57f3b 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -75,6 +75,7 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
@@ -586,8 +587,21 @@
     int mContentCaptureEnabled = CONTENT_CAPTURE_ENABLED_NOT_CHECKED;
     boolean mPerformContentCapture;
 
-
     boolean mReportNextDraw;
+    /** Set only while mReportNextDraw=true, indicating the last reason that was triggered */
+    String mLastReportNextDrawReason;
+    /** The reaason the last call to performDraw() returned false */
+    String mLastPerformDrawSkippedReason;
+    /** The reason the last call to performTraversals() returned without drawing */
+    String mLastPerformTraversalsSkipDrawReason;
+    /** The state of the local sync, if one is in progress. Can be one of the states below. */
+    int mLocalSyncState;
+
+    // The possible states of the local sync, see createSyncIfNeeded()
+    private final int LOCAL_SYNC_NONE = 0;
+    private final int LOCAL_SYNC_PENDING = 1;
+    private final int LOCAL_SYNC_RETURNED = 2;
+    private final int LOCAL_SYNC_MERGED = 3;
 
     /**
      * Set whether the draw should send the buffer to system server. When set to true, VRI will
@@ -693,6 +707,8 @@
     final Rect mPendingBackDropFrame = new Rect();
 
     boolean mPendingAlwaysConsumeSystemBars;
+    private int mRelayoutSeq;
+    private final Rect mWinFrameInScreen = new Rect();
     private final InsetsState mTempInsets = new InsetsState();
     private final InsetsSourceControl[] mTempControls = new InsetsSourceControl[SIZE];
     private final WindowConfiguration mTempWinConfig = new WindowConfiguration();
@@ -1811,7 +1827,7 @@
         mSyncSeqId = args.argi4 > mSyncSeqId ? args.argi4 : mSyncSeqId;
 
         if (msg == MSG_RESIZED_REPORT) {
-            reportNextDraw();
+            reportNextDraw("resized");
         }
 
         if (mView != null && (frameChanged || configChanged)) {
@@ -2716,6 +2732,8 @@
     }
 
     private void performTraversals() {
+        mLastPerformTraversalsSkipDrawReason = null;
+
         // cache mView since it is used so much below...
         final View host = mView;
         if (DBG) {
@@ -2725,12 +2743,14 @@
         }
 
         if (host == null || !mAdded) {
+            mLastPerformTraversalsSkipDrawReason = host == null ? "no_host" : "not_added";
             return;
         }
 
         mIsInTraversal = true;
         mWillDrawSoon = true;
         boolean cancelDraw = false;
+        String cancelReason = null;
         boolean isSyncRequest = false;
 
         boolean windowSizeMayChange = false;
@@ -3013,13 +3033,14 @@
                 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
                 cancelDraw = (relayoutResult & RELAYOUT_RES_CANCEL_AND_REDRAW)
                         == RELAYOUT_RES_CANCEL_AND_REDRAW;
+                cancelReason = "relayout";
                 final boolean dragResizing = mPendingDragResizing;
                 if (mSyncSeqId > mLastSyncSeqId) {
                     mLastSyncSeqId = mSyncSeqId;
                     if (DEBUG_BLAST) {
                         Log.d(mTag, "Relayout called with blastSync");
                     }
-                    reportNextDraw();
+                    reportNextDraw("relayout");
                     mSyncBuffer = true;
                     isSyncRequest = true;
                     if (!cancelDraw) {
@@ -3117,6 +3138,7 @@
                             }
                         } catch (OutOfResourcesException e) {
                             handleOutOfResourcesException(e);
+                            mLastPerformTraversalsSkipDrawReason = "oom_initialize_renderer";
                             return;
                         }
                     }
@@ -3154,6 +3176,7 @@
                         mAttachInfo.mThreadedRenderer.updateSurface(mSurface);
                     } catch (OutOfResourcesException e) {
                         handleOutOfResourcesException(e);
+                        mLastPerformTraversalsSkipDrawReason = "oom_update_surface";
                         return;
                     }
                 }
@@ -3313,19 +3336,6 @@
                 }
             }
         } else {
-            // If a relayout isn't going to happen, we still need to check if this window can draw
-            // when mCheckIfCanDraw is set. This is because it means we had a sync in the past, but
-            // have not been told by WMS that the sync is complete and that we can continue to draw
-            if (mCheckIfCanDraw) {
-                try {
-                    cancelDraw = mWindowSession.cancelDraw(mWindow);
-                    if (DEBUG_BLAST) {
-                        Log.d(mTag, "cancelDraw returned " + cancelDraw);
-                    }
-                } catch (RemoteException e) {
-                }
-            }
-
             // Not the first pass and no window/insets/visibility change but the window
             // may have moved and we need check that and if so to update the left and right
             // in the attach info. We translate only the window frame since on window move
@@ -3334,6 +3344,20 @@
             maybeHandleWindowMove(frame);
         }
 
+        if (!mRelayoutRequested && mCheckIfCanDraw) {
+            // We had a sync previously, but we didn't call IWindowSession#relayout in this
+            // traversal. So we don't know if the sync is complete that we can continue to draw.
+            // Here invokes cancelDraw to obtain the information.
+            try {
+                cancelDraw = mWindowSession.cancelDraw(mWindow);
+                cancelReason = "wm_sync";
+                if (DEBUG_BLAST) {
+                    Log.d(mTag, "cancelDraw returned " + cancelDraw);
+                }
+            } catch (RemoteException e) {
+            }
+        }
+
         if (surfaceSizeChanged || surfaceReplaced || surfaceCreated || windowAttributesChanged) {
             // If the surface has been replaced, there's a chance the bounds layer is not parented
             // to the new layer. When updating bounds layer, also reparent to the main VRI
@@ -3541,19 +3565,21 @@
         mImeFocusController.onTraversal(hasWindowFocus, mWindowAttributes);
 
         if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
-            reportNextDraw();
+            reportNextDraw("first_relayout");
         }
 
         mCheckIfCanDraw = isSyncRequest || cancelDraw;
 
-        boolean cancelAndRedraw =
-                mAttachInfo.mTreeObserver.dispatchOnPreDraw() || (cancelDraw && mDrewOnceForSync);
+        boolean cancelDueToPreDrawListener = mAttachInfo.mTreeObserver.dispatchOnPreDraw();
+        boolean cancelAndRedraw = cancelDueToPreDrawListener
+                 || (cancelDraw && mDrewOnceForSync);
         if (!cancelAndRedraw) {
             createSyncIfNeeded();
             mDrewOnceForSync = true;
         }
 
         if (!isViewVisible) {
+            mLastPerformTraversalsSkipDrawReason = "view_not_visible";
             if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
                 for (int i = 0; i < mPendingTransitions.size(); ++i) {
                     mPendingTransitions.get(i).endChangingAnimations();
@@ -3565,6 +3591,9 @@
                 mSyncBufferCallback.onBufferReady(null);
             }
         } else if (cancelAndRedraw) {
+            mLastPerformTraversalsSkipDrawReason = cancelDueToPreDrawListener
+                ? "predraw_" + mAttachInfo.mTreeObserver.getLastDispatchOnPreDrawCanceledReason()
+                : "cancel_" + cancelReason;
             // Try again
             scheduleTraversals();
         } else {
@@ -3588,11 +3617,13 @@
 
         if (!cancelAndRedraw) {
             mReportNextDraw = false;
+            mLastReportNextDrawReason = null;
             mSyncBufferCallback = null;
             mSyncBuffer = false;
             if (isInLocalSync()) {
                 mSurfaceSyncer.markSyncReady(mSyncId);
                 mSyncId = UNSET_SYNC_ID;
+                mLocalSyncState = LOCAL_SYNC_NONE;
             }
         }
     }
@@ -3604,9 +3635,12 @@
         }
 
         final int seqId = mSyncSeqId;
+        mLocalSyncState = LOCAL_SYNC_PENDING;
         mSyncId = mSurfaceSyncer.setupSync(transaction -> {
+            mLocalSyncState = LOCAL_SYNC_RETURNED;
             // Callback will be invoked on executor thread so post to main thread.
             mHandler.postAtFrontOfQueue(() -> {
+                mLocalSyncState = LOCAL_SYNC_MERGED;
                 mSurfaceChangedTransaction.merge(transaction);
                 reportDrawFinished(seqId);
             });
@@ -4321,9 +4355,12 @@
     }
 
     private boolean performDraw() {
+        mLastPerformDrawSkippedReason = null;
         if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {
+            mLastPerformDrawSkippedReason = "screen_off";
             return false;
         } else if (mView == null) {
+            mLastPerformDrawSkippedReason = "no_root_view";
             return false;
         }
 
@@ -8048,7 +8085,43 @@
 
     private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
             boolean insetsPending) throws RemoteException {
-        mRelayoutRequested = true;
+        final WindowConfiguration winConfigFromAm = getConfiguration().windowConfiguration;
+        final WindowConfiguration winConfigFromWm =
+                mLastReportedMergedConfiguration.getGlobalConfiguration().windowConfiguration;
+        final WindowConfiguration winConfig = getCompatWindowConfiguration();
+        final int measuredWidth = mView.getMeasuredWidth();
+        final int measuredHeight = mView.getMeasuredHeight();
+        final boolean relayoutAsync;
+        if (LOCAL_LAYOUT && !mFirst && viewVisibility == mViewVisibility
+                && mWindowAttributes.type != TYPE_APPLICATION_STARTING
+                && mSyncSeqId <= mLastSyncSeqId
+                && winConfigFromAm.diff(winConfigFromWm, false /* compareUndefined */) == 0) {
+            final InsetsState state = mInsetsController.getState();
+            final Rect displayCutoutSafe = mTempRect;
+            state.getDisplayCutoutSafe(displayCutoutSafe);
+            mWindowLayout.computeFrames(mWindowAttributes.forRotation(winConfig.getRotation()),
+                    state, displayCutoutSafe, winConfig.getBounds(), winConfig.getWindowingMode(),
+                    measuredWidth, measuredHeight, mInsetsController.getRequestedVisibilities(),
+                    1f /* compatScale */, mTmpFrames);
+            mWinFrameInScreen.set(mTmpFrames.frame);
+            if (mTranslator != null) {
+                mTranslator.translateRectInAppWindowToScreen(mWinFrameInScreen);
+            }
+
+            // If the position and the size of the frame are both changed, it will trigger a BLAST
+            // sync, and we still need to call relayout to obtain the syncSeqId. Otherwise, we just
+            // need to send attributes via relayoutAsync.
+            final Rect oldFrame = mWinFrame;
+            final Rect newFrame = mTmpFrames.frame;
+            final boolean positionChanged =
+                    newFrame.top != oldFrame.top || newFrame.left != oldFrame.left;
+            final boolean sizeChanged =
+                    newFrame.width() != oldFrame.width() || newFrame.height() != oldFrame.height();
+            relayoutAsync = !positionChanged || !sizeChanged;
+        } else {
+            relayoutAsync = false;
+        }
+
         float appScale = mAttachInfo.mApplicationScale;
         boolean restore = false;
         if (params != null && mTranslator != null) {
@@ -8070,26 +8143,47 @@
             }
         }
 
-        final int requestedWidth = (int) (mView.getMeasuredWidth() * appScale + 0.5f);
-        final int requestedHeight = (int) (mView.getMeasuredHeight() * appScale + 0.5f);
+        final int requestedWidth = (int) (measuredWidth * appScale + 0.5f);
+        final int requestedHeight = (int) (measuredHeight * appScale + 0.5f);
+        int relayoutResult = 0;
+        mRelayoutSeq++;
+        if (relayoutAsync) {
+            mWindowSession.relayoutAsync(mWindow, params,
+                    requestedWidth, requestedHeight, viewVisibility,
+                    insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, mRelayoutSeq,
+                    mLastSyncSeqId);
+        } else {
+            relayoutResult = mWindowSession.relayout(mWindow, params,
+                    requestedWidth, requestedHeight, viewVisibility,
+                    insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, mRelayoutSeq,
+                    mLastSyncSeqId, mTmpFrames, mPendingMergedConfiguration, mSurfaceControl,
+                    mTempInsets, mTempControls, mRelayoutBundle);
+            mRelayoutRequested = true;
+            final int maybeSyncSeqId = mRelayoutBundle.getInt("seqid");
+            if (maybeSyncSeqId > 0) {
+                mSyncSeqId = maybeSyncSeqId;
+            }
+            mWinFrameInScreen.set(mTmpFrames.frame);
+            if (mTranslator != null) {
+                mTranslator.translateRectInScreenToAppWindow(mTmpFrames.frame);
+                mTranslator.translateRectInScreenToAppWindow(mTmpFrames.displayFrame);
+                mTranslator.translateRectInScreenToAppWindow(mTmpFrames.attachedFrame);
+                mTranslator.translateInsetsStateInScreenToAppWindow(mTempInsets);
+                mTranslator.translateSourceControlsInScreenToAppWindow(mTempControls);
+            }
+            mInvSizeCompatScale = 1f / mTmpFrames.sizeCompatScale;
+            mInsetsController.onStateChanged(mTempInsets);
+            mInsetsController.onControlsChanged(mTempControls);
 
-        int relayoutResult = mWindowSession.relayout(mWindow, params,
-                requestedWidth, requestedHeight, viewVisibility,
-                insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
-                mTmpFrames, mPendingMergedConfiguration, mSurfaceControl, mTempInsets,
-                mTempControls, mRelayoutBundle);
-        final int maybeSyncSeqId = mRelayoutBundle.getInt("seqid");
-        if (maybeSyncSeqId > 0) {
-            mSyncSeqId = maybeSyncSeqId;
+            mPendingAlwaysConsumeSystemBars =
+                    (relayoutResult & RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS) != 0;
         }
-        mInvSizeCompatScale = 1f / mTmpFrames.sizeCompatScale;
 
         final int transformHint = SurfaceControl.rotationToBufferTransform(
                 (mDisplayInstallOrientation + mDisplay.getRotation()) % 4);
 
-        final WindowConfiguration winConfig = getCompatWindowConfiguration();
         WindowLayout.computeSurfaceSize(mWindowAttributes, winConfig.getMaxBounds(), requestedWidth,
-                requestedHeight, mTmpFrames.frame, mPendingDragResizing, mSurfaceSize);
+                requestedHeight, mWinFrameInScreen, mPendingDragResizing, mSurfaceSize);
 
         final boolean transformHintChanged = transformHint != mLastTransformHint;
         final boolean sizeChanged = !mLastSurfaceSize.equals(mSurfaceSize);
@@ -8136,23 +8230,11 @@
             destroySurface();
         }
 
-        mPendingAlwaysConsumeSystemBars =
-                (relayoutResult & RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS) != 0;
-
         if (restore) {
             params.restore();
         }
 
-        if (mTranslator != null) {
-            mTranslator.translateRectInScreenToAppWindow(mTmpFrames.frame);
-            mTranslator.translateRectInScreenToAppWindow(mTmpFrames.displayFrame);
-            mTranslator.translateRectInScreenToAppWindow(mTmpFrames.attachedFrame);
-            mTranslator.translateInsetsStateInScreenToAppWindow(mTempInsets);
-            mTranslator.translateSourceControlsInScreenToAppWindow(mTempControls);
-        }
         setFrame(mTmpFrames.frame);
-        mInsetsController.onStateChanged(mTempInsets);
-        mInsetsController.onControlsChanged(mTempControls);
         return relayoutResult;
     }
 
@@ -8390,6 +8472,21 @@
         if (mTraversalScheduled) {
             writer.println(innerPrefix + " (barrier=" + mTraversalBarrier + ")");
         }
+        writer.println(innerPrefix + "mReportNextDraw=" + mReportNextDraw);
+        if (mReportNextDraw) {
+            writer.println(innerPrefix + " (reason=" + mLastReportNextDrawReason + ")");
+        }
+        if (mLastPerformTraversalsSkipDrawReason != null) {
+            writer.println(innerPrefix + "mLastPerformTraversalsFailedReason="
+                + mLastPerformTraversalsSkipDrawReason);
+        }
+        if (mLastPerformDrawSkippedReason != null) {
+            writer.println(innerPrefix + "mLastPerformDrawFailedReason="
+                + mLastPerformDrawSkippedReason);
+        }
+        if (mLocalSyncState != LOCAL_SYNC_NONE) {
+            writer.println(innerPrefix + "mLocalSyncState=" + mLocalSyncState);
+        }
         writer.println(innerPrefix + "mIsAmbientMode="  + mIsAmbientMode);
         writer.println(innerPrefix + "mUnbufferedInputSource="
                 + Integer.toHexString(mUnbufferedInputSource));
@@ -9890,11 +9987,12 @@
         }
     }
 
-    private void reportNextDraw() {
+    private void reportNextDraw(String reason) {
         if (DEBUG_BLAST) {
             Log.d(mTag, "reportNextDraw " + Debug.getCallers(5));
         }
         mReportNextDraw = true;
+        mLastReportNextDrawReason = reason;
     }
 
     /**
@@ -9907,11 +10005,12 @@
      * @param syncBuffer If true, the transaction that contains the buffer from the draw should be
      *                   sent to system to be synced. If false, VRI will not try to sync the buffer,
      *                   but only report back that a buffer was drawn.
+     * @param reason A debug string indicating the reason for reporting the next draw
      * @hide
      */
-    public void setReportNextDraw(boolean syncBuffer) {
+    public void setReportNextDraw(boolean syncBuffer, String reason) {
         mSyncBuffer = syncBuffer;
-        reportNextDraw();
+        reportNextDraw(reason);
         invalidate();
     }
 
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index e246634..2c2ae06 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -45,6 +45,30 @@
 public abstract class ViewStructure {
 
     /**
+     * Key used for writing active child view information to the content capture bundle.
+     *
+     * The value stored under this key will be an ordered list of Autofill IDs of child views.
+     *
+     * TODO(b/241498401): Add @TestApi in Android U
+     * @hide
+     */
+    public static final String EXTRA_ACTIVE_CHILDREN_IDS =
+            "android.view.ViewStructure.extra.ACTIVE_CHILDREN_IDS";
+
+    /**
+     * Key used for writing the first active child's position to the content capture bundle.
+     *
+     * When active child view information is provided under the
+     * {@link #EXTRA_ACTIVE_CHILDREN_IDS}, the value stored under this key will be the
+     * 0-based position of the first child view in the list relative to the positions of child views
+     * in the containing View's dataset.
+     *
+     * TODO(b/241498401): Add @TestApi in Android U
+     * @hide */
+    public static final String EXTRA_FIRST_ACTIVE_POSITION =
+            "android.view.ViewStructure.extra.FIRST_ACTIVE_POSITION";
+
+    /**
      * Set the identifier for this view.
      *
      * @param id The view's identifier, as per {@link View#getId View.getId()}.
diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java
index ed8350a..fd62ecd 100644
--- a/core/java/android/view/ViewTreeObserver.java
+++ b/core/java/android/view/ViewTreeObserver.java
@@ -74,6 +74,9 @@
      * that the listener will be immediately called. */
     private boolean mWindowShown;
 
+    // The reason that the last call to dispatchOnPreDraw() returned true to cancel and redraw
+    private String mLastDispatchOnPreDrawCanceledReason;
+
     private boolean mAlive = true;
 
     /**
@@ -1167,6 +1170,7 @@
      */
     @SuppressWarnings("unchecked")
     public final boolean dispatchOnPreDraw() {
+        mLastDispatchOnPreDrawCanceledReason = null;
         boolean cancelDraw = false;
         final CopyOnWriteArray<OnPreDrawListener> listeners = mOnPreDrawListeners;
         if (listeners != null && listeners.size() > 0) {
@@ -1174,7 +1178,11 @@
             try {
                 int count = access.size();
                 for (int i = 0; i < count; i++) {
-                    cancelDraw |= !(access.get(i).onPreDraw());
+                    final OnPreDrawListener preDrawListener = access.get(i);
+                    cancelDraw |= !(preDrawListener.onPreDraw());
+                    if (cancelDraw) {
+                        mLastDispatchOnPreDrawCanceledReason = preDrawListener.getClass().getName();
+                    }
                 }
             } finally {
                 listeners.end();
@@ -1184,6 +1192,15 @@
     }
 
     /**
+     * @return the reason that the last call to dispatchOnPreDraw() returned true to cancel the
+     *         current draw, or null if the last call did not cancel.
+     * @hide
+     */
+    final String getLastDispatchOnPreDrawCanceledReason() {
+        return mLastDispatchOnPreDrawCanceledReason;
+    }
+
+    /**
      * Notifies registered listeners that the window is now shown
      * @hide
      */
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 63d42c0..67352c0 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -4396,15 +4396,42 @@
                 changes |= LAYOUT_CHANGED;
             }
 
-            if (!Arrays.equals(paramsForRotation, o.paramsForRotation)) {
+            if (paramsForRotation != o.paramsForRotation) {
+                if ((changes & LAYOUT_CHANGED) == 0) {
+                    if (paramsForRotation != null && o.paramsForRotation != null
+                            && paramsForRotation.length == o.paramsForRotation.length) {
+                        for (int i = paramsForRotation.length - 1; i >= 0; i--) {
+                            if (hasLayoutDiff(paramsForRotation[i], o.paramsForRotation[i])) {
+                                changes |= LAYOUT_CHANGED;
+                                break;
+                            }
+                        }
+                    } else {
+                        changes |= LAYOUT_CHANGED;
+                    }
+                }
                 paramsForRotation = o.paramsForRotation;
                 checkNonRecursiveParams();
-                changes |= LAYOUT_CHANGED;
             }
 
             return changes;
         }
 
+        /**
+         * Returns {@code true} if the 2 params may have difference results of
+         * {@link WindowLayout#computeFrames}.
+         */
+        private static boolean hasLayoutDiff(LayoutParams a, LayoutParams b) {
+            return a.width != b.width || a.height != b.height || a.x != b.x || a.y != b.y
+                    || a.horizontalMargin != b.horizontalMargin
+                    || a.verticalMargin != b.verticalMargin
+                    || a.layoutInDisplayCutoutMode != b.layoutInDisplayCutoutMode
+                    || a.gravity != b.gravity || !Arrays.equals(a.providedInsets, b.providedInsets)
+                    || a.mFitInsetsTypes != b.mFitInsetsTypes
+                    || a.mFitInsetsSides != b.mFitInsetsSides
+                    || a.mFitInsetsIgnoringVisibility != b.mFitInsetsIgnoringVisibility;
+        }
+
         @Override
         public String debug(String output) {
             output += "Contents of " + this + ":";
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index d55c838..1ec17d0 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -286,10 +286,11 @@
 
     @Override
     public int relayout(IWindow window, WindowManager.LayoutParams inAttrs,
-            int requestedWidth, int requestedHeight, int viewFlags, int flags,
-            ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
-            SurfaceControl outSurfaceControl, InsetsState outInsetsState,
-            InsetsSourceControl[] outActiveControls, Bundle outSyncSeqIdBundle) {
+            int requestedWidth, int requestedHeight, int viewFlags, int flags, int seq,
+            int lastSyncSeqId, ClientWindowFrames outFrames,
+            MergedConfiguration outMergedConfiguration, SurfaceControl outSurfaceControl,
+            InsetsState outInsetsState, InsetsSourceControl[] outActiveControls,
+            Bundle outSyncSeqIdBundle) {
         final State state;
         synchronized (this) {
             state = mStateForWindow.get(window.asBinder());
@@ -309,15 +310,23 @@
 
         if (viewFlags == View.VISIBLE) {
             t.setOpaque(sc, isOpaque(attrs)).show(sc).apply();
-            outSurfaceControl.copyFrom(sc, "WindowlessWindowManager.relayout");
+            if (outSurfaceControl != null) {
+                outSurfaceControl.copyFrom(sc, "WindowlessWindowManager.relayout");
+            }
         } else {
             t.hide(sc).apply();
-            outSurfaceControl.release();
+            if (outSurfaceControl != null) {
+                outSurfaceControl.release();
+            }
         }
-        outFrames.frame.set(0, 0, attrs.width, attrs.height);
-        outFrames.displayFrame.set(outFrames.frame);
+        if (outFrames != null) {
+            outFrames.frame.set(0, 0, attrs.width, attrs.height);
+            outFrames.displayFrame.set(outFrames.frame);
+        }
 
-        mergedConfiguration.setConfiguration(mConfiguration, mConfiguration);
+        if (outMergedConfiguration != null) {
+            outMergedConfiguration.setConfiguration(mConfiguration, mConfiguration);
+        }
 
         if ((attrChanges & WindowManager.LayoutParams.FLAGS_CHANGED) != 0
                 && state.mInputChannelToken != null) {
@@ -335,7 +344,7 @@
             }
         }
 
-        if (mInsetsState != null) {
+        if (outInsetsState != null && mInsetsState != null) {
             outInsetsState.set(mInsetsState);
         }
 
@@ -343,6 +352,16 @@
     }
 
     @Override
+    public void relayoutAsync(IWindow window, WindowManager.LayoutParams inAttrs,
+            int requestedWidth, int requestedHeight, int viewFlags, int flags, int seq,
+            int lastSyncSeqId) {
+        relayout(window, inAttrs, requestedWidth, requestedHeight, viewFlags, flags, seq,
+                lastSyncSeqId, null /* outFrames */, null /* outMergedConfiguration */,
+                null /* outSurfaceControl */, null /* outInsetsState */,
+                null /* outActiveControls */, null /* outSyncSeqIdBundle */);
+    }
+
+    @Override
     public void prepareToReplaceWindows(android.os.IBinder appToken, boolean childrenOnly) {
     }
 
diff --git a/core/java/android/view/contentcapture/ContentCaptureEvent.java b/core/java/android/view/contentcapture/ContentCaptureEvent.java
index ba4176f..db4ac5d 100644
--- a/core/java/android/view/contentcapture/ContentCaptureEvent.java
+++ b/core/java/android/view/contentcapture/ContentCaptureEvent.java
@@ -55,6 +55,15 @@
     /**
      * Called when a node has been added to the screen and is visible to the user.
      *
+     * On API level 33, this event may be re-sent with additional information if a view's children
+     * have changed, e.g. scrolling Views inside of a ListView. This information will be stored in
+     * the extras Bundle associated with the event's ViewNode. Within the Bundle, the
+     * "android.view.ViewStructure.extra.ACTIVE_CHILDREN_IDS" key may be used to get a list of
+     * Autofill IDs of active child views, and the
+     * "android.view.ViewStructure.extra.FIRST_ACTIVE_POSITION" key may be used to get the 0-based
+     * position of the first active child view in the list relative to the positions of child views
+     * in the container View's dataset.
+     *
      * <p>The metadata of the node is available through {@link #getViewNode()}.
      */
     public static final int TYPE_VIEW_APPEARED = 1;
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 48d2970..1664637 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -280,6 +280,15 @@
             "service_explicitly_enabled";
 
     /**
+     * Device config property used by {@code android.widget.AbsListView} to determine whether or
+     * not it should report the positions of its children to Content Capture.
+     *
+     * @hide
+     */
+    public static final String DEVICE_CONFIG_PROPERTY_REPORT_LIST_VIEW_CHILDREN =
+            "report_list_view_children";
+
+    /**
      * Maximum number of events that are buffered before sent to the app.
      *
      * @hide
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index a0a3b4f..cae4868 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -2596,7 +2596,7 @@
                 try {
                     mService.hideSoftInput(mClient, windowToken, 0 /* flags */,
                             null /* resultReceiver */,
-                            SoftInputShowHideReason.HIDE_SOFT_INPUT);
+                            SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API);
                 } catch (RemoteException e) {
                     throw e.rethrowFromSystemServer();
                 }
@@ -2989,7 +2989,8 @@
      */
     @Deprecated
     public void hideSoftInputFromInputMethod(IBinder token, int flags) {
-        InputMethodPrivilegedOperationsRegistry.get(token).hideMySoftInput(flags);
+        InputMethodPrivilegedOperationsRegistry.get(token).hideMySoftInput(
+                flags, SoftInputShowHideReason.HIDE_SOFT_INPUT_IMM_DEPRECATION);
     }
 
     /**
diff --git a/core/java/android/view/selectiontoolbar/ShowInfo.java b/core/java/android/view/selectiontoolbar/ShowInfo.java
index 594b6bc..08d6db5 100644
--- a/core/java/android/view/selectiontoolbar/ShowInfo.java
+++ b/core/java/android/view/selectiontoolbar/ShowInfo.java
@@ -75,6 +75,11 @@
     @NonNull
     private final IBinder mHostInputToken;
 
+    /**
+     * If the host application uses light theme.
+     */
+    private final boolean mIsLightTheme;
+
 
 
     // Code below generated by codegen v1.0.23.
@@ -109,6 +114,8 @@
      * @param hostInputToken
      *   The host application's input token, this allows the remote render service to transfer
      *   the touch focus to the host application.
+     * @param isLightTheme
+     *   If the host application uses light theme.
      */
     @DataClass.Generated.Member
     public ShowInfo(
@@ -118,7 +125,8 @@
             @NonNull Rect contentRect,
             int suggestedWidth,
             @NonNull Rect viewPortOnScreen,
-            @NonNull IBinder hostInputToken) {
+            @NonNull IBinder hostInputToken,
+            boolean isLightTheme) {
         this.mWidgetToken = widgetToken;
         this.mLayoutRequired = layoutRequired;
         this.mMenuItems = menuItems;
@@ -134,6 +142,7 @@
         this.mHostInputToken = hostInputToken;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mHostInputToken);
+        this.mIsLightTheme = isLightTheme;
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -196,6 +205,14 @@
         return mHostInputToken;
     }
 
+    /**
+     * If the host application uses light theme.
+     */
+    @DataClass.Generated.Member
+    public boolean isIsLightTheme() {
+        return mIsLightTheme;
+    }
+
     @Override
     @DataClass.Generated.Member
     public String toString() {
@@ -209,7 +226,8 @@
                 "contentRect = " + mContentRect + ", " +
                 "suggestedWidth = " + mSuggestedWidth + ", " +
                 "viewPortOnScreen = " + mViewPortOnScreen + ", " +
-                "hostInputToken = " + mHostInputToken +
+                "hostInputToken = " + mHostInputToken + ", " +
+                "isLightTheme = " + mIsLightTheme +
         " }";
     }
 
@@ -232,7 +250,8 @@
                 && java.util.Objects.equals(mContentRect, that.mContentRect)
                 && mSuggestedWidth == that.mSuggestedWidth
                 && java.util.Objects.equals(mViewPortOnScreen, that.mViewPortOnScreen)
-                && java.util.Objects.equals(mHostInputToken, that.mHostInputToken);
+                && java.util.Objects.equals(mHostInputToken, that.mHostInputToken)
+                && mIsLightTheme == that.mIsLightTheme;
     }
 
     @Override
@@ -249,6 +268,7 @@
         _hash = 31 * _hash + mSuggestedWidth;
         _hash = 31 * _hash + java.util.Objects.hashCode(mViewPortOnScreen);
         _hash = 31 * _hash + java.util.Objects.hashCode(mHostInputToken);
+        _hash = 31 * _hash + Boolean.hashCode(mIsLightTheme);
         return _hash;
     }
 
@@ -258,9 +278,10 @@
         // You can override field parcelling by defining methods like:
         // void parcelFieldName(Parcel dest, int flags) { ... }
 
-        byte flg = 0;
+        int flg = 0;
         if (mLayoutRequired) flg |= 0x2;
-        dest.writeByte(flg);
+        if (mIsLightTheme) flg |= 0x80;
+        dest.writeInt(flg);
         dest.writeLong(mWidgetToken);
         dest.writeParcelableList(mMenuItems, flags);
         dest.writeTypedObject(mContentRect, flags);
@@ -280,8 +301,9 @@
         // You can override field unparcelling by defining methods like:
         // static FieldType unparcelFieldName(Parcel in) { ... }
 
-        byte flg = in.readByte();
+        int flg = in.readInt();
         boolean layoutRequired = (flg & 0x2) != 0;
+        boolean isLightTheme = (flg & 0x80) != 0;
         long widgetToken = in.readLong();
         List<ToolbarMenuItem> menuItems = new java.util.ArrayList<>();
         in.readParcelableList(menuItems, ToolbarMenuItem.class.getClassLoader());
@@ -305,6 +327,7 @@
         this.mHostInputToken = hostInputToken;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mHostInputToken);
+        this.mIsLightTheme = isLightTheme;
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -324,10 +347,10 @@
     };
 
     @DataClass.Generated(
-            time = 1643186262604L,
+            time = 1645108384245L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/core/java/android/view/selectiontoolbar/ShowInfo.java",
-            inputSignatures = "private final  long mWidgetToken\nprivate final  boolean mLayoutRequired\nprivate final @android.annotation.NonNull java.util.List<android.view.selectiontoolbar.ToolbarMenuItem> mMenuItems\nprivate final @android.annotation.NonNull android.graphics.Rect mContentRect\nprivate final  int mSuggestedWidth\nprivate final @android.annotation.NonNull android.graphics.Rect mViewPortOnScreen\nprivate final @android.annotation.NonNull android.os.IBinder mHostInputToken\nclass ShowInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genEqualsHashCode=true)")
+            inputSignatures = "private final  long mWidgetToken\nprivate final  boolean mLayoutRequired\nprivate final @android.annotation.NonNull java.util.List<android.view.selectiontoolbar.ToolbarMenuItem> mMenuItems\nprivate final @android.annotation.NonNull android.graphics.Rect mContentRect\nprivate final  int mSuggestedWidth\nprivate final @android.annotation.NonNull android.graphics.Rect mViewPortOnScreen\nprivate final @android.annotation.NonNull android.os.IBinder mHostInputToken\nprivate final  boolean mIsLightTheme\nclass ShowInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genEqualsHashCode=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/view/translation/TranslationManager.java b/core/java/android/view/translation/TranslationManager.java
index db1c606..fbaf711 100644
--- a/core/java/android/view/translation/TranslationManager.java
+++ b/core/java/android/view/translation/TranslationManager.java
@@ -40,11 +40,11 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.SyncResultReceiver;
 
+import java.security.SecureRandom;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Map;
 import java.util.Objects;
-import java.util.Random;
 import java.util.Set;
 import java.util.concurrent.Executor;
 import java.util.concurrent.TimeoutException;
@@ -92,7 +92,8 @@
     private final Map<Consumer<TranslationCapability>, IRemoteCallback> mCapabilityCallbacks =
             new ArrayMap<>();
 
-    private static final Random ID_GENERATOR = new Random();
+    // TODO(b/158778794): make the session ids truly globally unique across processes
+    private static final SecureRandom ID_GENERATOR = new SecureRandom();
     private final Object mLock = new Object();
 
     @NonNull
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 231ae08..0b0bfb1 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -20,6 +20,7 @@
 import android.annotation.DrawableRes;
 import android.annotation.NonNull;
 import android.annotation.TestApi;
+import android.app.ActivityThread;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
@@ -37,6 +38,7 @@
 import android.os.Parcelable;
 import android.os.StrictMode;
 import android.os.Trace;
+import android.provider.DeviceConfig;
 import android.text.Editable;
 import android.text.InputType;
 import android.text.TextUtils;
@@ -65,6 +67,7 @@
 import android.view.ViewGroup;
 import android.view.ViewHierarchyEncoder;
 import android.view.ViewParent;
+import android.view.ViewStructure;
 import android.view.ViewTreeObserver;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
@@ -73,6 +76,9 @@
 import android.view.accessibility.AccessibilityNodeInfo.CollectionInfo;
 import android.view.animation.Interpolator;
 import android.view.animation.LinearInterpolator;
+import android.view.autofill.AutofillId;
+import android.view.contentcapture.ContentCaptureManager;
+import android.view.contentcapture.ContentCaptureSession;
 import android.view.inputmethod.BaseInputConnection;
 import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.CorrectionInfo;
@@ -634,6 +640,23 @@
     private int mLastScrollState = OnScrollListener.SCROLL_STATE_IDLE;
 
     /**
+     * Indicates that reporting positions of child views to content capture is enabled via
+     * DeviceConfig.
+     */
+    private static boolean sContentCaptureReportingEnabledByDeviceConfig = false;
+
+    /**
+     * Listens for changes to DeviceConfig properties and updates stored values accordingly.
+     */
+    private static DeviceConfig.OnPropertiesChangedListener sDeviceConfigChangeListener = null;
+
+    /**
+     * Indicates that child positions of views should be reported to Content Capture the next time
+     * that active views are refreshed.
+     */
+    private boolean mReportChildrenToContentCaptureOnNextUpdate = true;
+
+    /**
      * Helper object that renders and controls the fast scroll thumb.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768941)
@@ -850,8 +873,44 @@
         public void adjustListItemSelectionBounds(Rect bounds);
     }
 
+    private static class DeviceConfigChangeListener
+            implements DeviceConfig.OnPropertiesChangedListener {
+        @Override
+        public void onPropertiesChanged(
+                @NonNull DeviceConfig.Properties properties) {
+            if (!DeviceConfig.NAMESPACE_CONTENT_CAPTURE.equals(properties.getNamespace())) {
+                return;
+            }
+
+            for (String key : properties.getKeyset()) {
+                if (!ContentCaptureManager.DEVICE_CONFIG_PROPERTY_REPORT_LIST_VIEW_CHILDREN
+                        .equals(key)) {
+                    continue;
+                }
+
+                sContentCaptureReportingEnabledByDeviceConfig = properties.getBoolean(key,
+                        false);
+            }
+        }
+    }
+
+    private static void setupDeviceConfigProperties() {
+        if (sDeviceConfigChangeListener == null) {
+            sContentCaptureReportingEnabledByDeviceConfig = DeviceConfig.getBoolean(
+                    DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+                    ContentCaptureManager.DEVICE_CONFIG_PROPERTY_REPORT_LIST_VIEW_CHILDREN,
+                    false);
+            sDeviceConfigChangeListener = new DeviceConfigChangeListener();
+            DeviceConfig.addOnPropertiesChangedListener(
+                    DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+                    ActivityThread.currentApplication().getMainExecutor(),
+                    sDeviceConfigChangeListener);
+        }
+    }
+
     public AbsListView(Context context) {
         super(context);
+        setupDeviceConfigProperties();
         mEdgeGlowBottom = new EdgeEffect(context);
         mEdgeGlowTop = new EdgeEffect(context);
         initAbsListView();
@@ -874,6 +933,7 @@
 
     public AbsListView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
+        setupDeviceConfigProperties();
         mEdgeGlowBottom = new EdgeEffect(context, attrs);
         mEdgeGlowTop = new EdgeEffect(context, attrs);
         initAbsListView();
@@ -4699,6 +4759,14 @@
                 mOnScrollListener.onScrollStateChanged(this, newState);
             }
         }
+
+        // When scrolling, we want to report changes in the active children to Content Capture,
+        // so set the flag to report on the next update only when scrolling has stopped or a fling
+        // scroll is performed.
+        if (newState == OnScrollListener.SCROLL_STATE_IDLE
+                || newState == OnScrollListener.SCROLL_STATE_FLING) {
+            mReportChildrenToContentCaptureOnNextUpdate = true;
+        }
     }
 
     /**
@@ -6654,10 +6722,77 @@
         mRecycler.mRecyclerListener = listener;
     }
 
+    /**
+     * {@inheritDoc}
+     *
+     * This method will initialize the fields of the {@link ViewStructure}
+     * using the base implementation in {@link View}. On API level 33 and higher, it may also
+     * write information about the positions of active views to the extras bundle provided by the
+     * {@link ViewStructure}.
+     *
+     * NOTE: When overriding this method on API level 33, if not calling super() or if changing the
+     * logic for child views, be sure to provide values for the first active child view position and
+     * the list of active child views in the {@link ViewStructure}'s extras {@link Bundle} using the
+     * "android.view.ViewStructure.extra.ACTIVE_CHILDREN_IDS" and
+     * "android.view.ViewStructure.extra.FIRST_ACTIVE_POSITION" keys.
+     *
+     * @param structure {@link ViewStructure} to be filled in with structured view data.
+     * @param flags optional flags.
+     *
+     * @see View#AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
+     */
+    @Override
+    public void onProvideContentCaptureStructure(
+            @NonNull ViewStructure structure, int flags) {
+        super.onProvideContentCaptureStructure(structure, flags);
+        if (!sContentCaptureReportingEnabledByDeviceConfig) {
+            return;
+        }
+
+        Bundle extras = structure.getExtras();
+
+        if (extras == null) {
+            Log.wtf(TAG, "Unexpected null extras Bundle in ViewStructure");
+            return;
+        }
+
+        int childCount = getChildCount();
+        ArrayList<AutofillId> idsList = new ArrayList<>(childCount);
+
+        for (int i = 0; i < childCount; ++i) {
+            View activeView = getChildAt(i);
+            if (activeView == null) {
+                continue;
+            }
+
+            idsList.add(activeView.getAutofillId());
+        }
+
+        extras.putParcelableArrayList(ViewStructure.EXTRA_ACTIVE_CHILDREN_IDS,
+                idsList);
+
+        extras.putInt(ViewStructure.EXTRA_FIRST_ACTIVE_POSITION,
+                getFirstVisiblePosition());
+    }
+
+    private void reportActiveViewsToContentCapture() {
+        if (!sContentCaptureReportingEnabledByDeviceConfig) {
+            return;
+        }
+
+        ContentCaptureSession session = getContentCaptureSession();
+        if (session != null) {
+            ViewStructure structure = session.newViewStructure(this);
+            onProvideContentCaptureStructure(structure, /* flags= */ 0);
+            session.notifyViewAppeared(structure);
+        }
+    }
+
     class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver {
         @Override
         public void onChanged() {
             super.onChanged();
+            mReportChildrenToContentCaptureOnNextUpdate = true;
             if (mFastScroll != null) {
                 mFastScroll.onSectionsChanged();
             }
@@ -6666,6 +6801,7 @@
         @Override
         public void onInvalidated() {
             super.onInvalidated();
+            mReportChildrenToContentCaptureOnNextUpdate = true;
             if (mFastScroll != null) {
                 mFastScroll.onSectionsChanged();
             }
@@ -6984,6 +7120,11 @@
                     lp.scrappedFromPosition = firstActivePosition + i;
                 }
             }
+
+            if (mReportChildrenToContentCaptureOnNextUpdate && childCount > 0) {
+                AbsListView.this.reportActiveViewsToContentCapture();
+                mReportChildrenToContentCaptureOnNextUpdate = false;
+            }
         }
 
         /**
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 5eec054..a339062 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -1587,7 +1587,13 @@
 
         public BitmapCache(Parcel source) {
             mBitmaps = source.createTypedArrayList(Bitmap.CREATOR);
-            mBitmapHashes = source.readSparseIntArray();
+            mBitmapHashes = new SparseIntArray();
+            for (int i = 0; i < mBitmaps.size(); i++) {
+                Bitmap b = mBitmaps.get(i);
+                if (b != null) {
+                    mBitmapHashes.put(b.hashCode(), i);
+                }
+            }
         }
 
         public int getBitmapId(Bitmap b) {
@@ -1603,7 +1609,7 @@
                         b = b.asShared();
                     }
                     mBitmaps.add(b);
-                    mBitmapHashes.put(mBitmaps.size() - 1, hash);
+                    mBitmapHashes.put(hash, mBitmaps.size() - 1);
                     mBitmapMemory = -1;
                     return (mBitmaps.size() - 1);
                 }
@@ -1620,7 +1626,6 @@
 
         public void writeBitmapsToParcel(Parcel dest, int flags) {
             dest.writeTypedList(mBitmaps, flags);
-            dest.writeSparseIntArray(mBitmapHashes);
         }
 
         public int getBitmapMemory() {
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index 3bffa89..567b164 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -269,6 +269,20 @@
     }
 
     /**
+     * Sets whether a task should be translucent. When {@code false}, the existing translucent of
+     * the task applies, but when {@code true} the task will be forced to be translucent.
+     * @hide
+     */
+    @NonNull
+    public WindowContainerTransaction setForceTranslucent(
+            @NonNull WindowContainerToken container, boolean forceTranslucent) {
+        Change chg = getOrCreateChange(container.asBinder());
+        chg.mForceTranslucent = forceTranslucent;
+        chg.mChangeMask |= Change.CHANGE_FORCE_TRANSLUCENT;
+        return this;
+    }
+
+    /**
      * Used in conjunction with a shell-transition call (usually finishTransition). This is
      * basically a message to the transition system that a particular task should NOT go into
      * PIP even though it normally would. This is to deal with some edge-case situations where
@@ -679,7 +693,39 @@
                         .build();
         mHierarchyOps.add(hierarchyOp);
         return this;
+    }
 
+    /**
+     * Sets/removes the always on top flag for this {@code windowContainer}. See
+     * {@link com.android.server.wm.ConfigurationContainer#setAlwaysOnTop(boolean)}.
+     * Please note that this method is only intended to be used for a
+     * {@link com.android.server.wm.DisplayArea}.
+     *
+     * <p>
+     *     Setting always on top to {@code True} will also make the {@code windowContainer} to move
+     *     to the top.
+     * </p>
+     * <p>
+     *     Setting always on top to {@code False} will make this {@code windowContainer} to move
+     *     below the other always on top sibling containers.
+     * </p>
+     *
+     * @param windowContainer the container which the flag need to be updated for.
+     * @param alwaysOnTop denotes whether or not always on top flag should be set.
+     * @hide
+     */
+    @NonNull
+    public WindowContainerTransaction setAlwaysOnTop(
+            @NonNull WindowContainerToken windowContainer,
+            boolean alwaysOnTop) {
+        final HierarchyOp hierarchyOp =
+                new HierarchyOp.Builder(
+                        HierarchyOp.HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP)
+                        .setContainer(windowContainer.asBinder())
+                        .setAlwaysOnTop(alwaysOnTop)
+                        .build();
+        mHierarchyOps.add(hierarchyOp);
+        return this;
     }
 
     /**
@@ -834,11 +880,13 @@
         public static final int CHANGE_BOUNDS_TRANSACTION_RECT = 1 << 4;
         public static final int CHANGE_IGNORE_ORIENTATION_REQUEST = 1 << 5;
         public static final int CHANGE_FORCE_NO_PIP = 1 << 6;
+        public static final int CHANGE_FORCE_TRANSLUCENT = 1 << 7;
 
         private final Configuration mConfiguration = new Configuration();
         private boolean mFocusable = true;
         private boolean mHidden = false;
         private boolean mIgnoreOrientationRequest = false;
+        private boolean mForceTranslucent = false;
 
         private int mChangeMask = 0;
         private @ActivityInfo.Config int mConfigSetMask = 0;
@@ -858,6 +906,7 @@
             mFocusable = in.readBoolean();
             mHidden = in.readBoolean();
             mIgnoreOrientationRequest = in.readBoolean();
+            mForceTranslucent = in.readBoolean();
             mChangeMask = in.readInt();
             mConfigSetMask = in.readInt();
             mWindowSetMask = in.readInt();
@@ -903,6 +952,9 @@
             if ((other.mChangeMask & CHANGE_IGNORE_ORIENTATION_REQUEST) != 0) {
                 mIgnoreOrientationRequest = other.mIgnoreOrientationRequest;
             }
+            if ((other.mChangeMask & CHANGE_FORCE_TRANSLUCENT) != 0) {
+                mForceTranslucent = other.mForceTranslucent;
+            }
             mChangeMask |= other.mChangeMask;
             if (other.mActivityWindowingMode >= 0) {
                 mActivityWindowingMode = other.mActivityWindowingMode;
@@ -953,6 +1005,15 @@
             return mIgnoreOrientationRequest;
         }
 
+        /** Gets the requested force translucent state. */
+        public boolean getForceTranslucent() {
+            if ((mChangeMask & CHANGE_FORCE_TRANSLUCENT) == 0) {
+                throw new RuntimeException("Force translucent not set. "
+                        + "Check CHANGE_FORCE_TRANSLUCENT first");
+            }
+            return mForceTranslucent;
+        }
+
         public int getChangeMask() {
             return mChangeMask;
         }
@@ -1030,6 +1091,7 @@
             dest.writeBoolean(mFocusable);
             dest.writeBoolean(mHidden);
             dest.writeBoolean(mIgnoreOrientationRequest);
+            dest.writeBoolean(mForceTranslucent);
             dest.writeInt(mChangeMask);
             dest.writeInt(mConfigSetMask);
             dest.writeInt(mWindowSetMask);
@@ -1091,6 +1153,7 @@
         public static final int HIERARCHY_OP_TYPE_ADD_RECT_INSETS_PROVIDER = 16;
         public static final int HIERARCHY_OP_TYPE_REMOVE_INSETS_PROVIDER = 17;
         public static final int HIERARCHY_OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT = 18;
+        public static final int HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP = 19;
 
         // The following key(s) are for use with mLaunchOptions:
         // When launching a task (eg. from recents), this is the taskId to be launched.
@@ -1141,6 +1204,8 @@
         @Nullable
         private ShortcutInfo mShortcutInfo;
 
+        private boolean mAlwaysOnTop;
+
         public static HierarchyOp createForReparent(
                 @NonNull IBinder container, @Nullable IBinder reparent, boolean toTop) {
             return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_REPARENT)
@@ -1238,6 +1303,7 @@
             mTaskFragmentCreationOptions = copy.mTaskFragmentCreationOptions;
             mPendingIntent = copy.mPendingIntent;
             mShortcutInfo = copy.mShortcutInfo;
+            mAlwaysOnTop = copy.mAlwaysOnTop;
         }
 
         protected HierarchyOp(Parcel in) {
@@ -1259,6 +1325,7 @@
             mTaskFragmentCreationOptions = in.readTypedObject(TaskFragmentCreationParams.CREATOR);
             mPendingIntent = in.readTypedObject(PendingIntent.CREATOR);
             mShortcutInfo = in.readTypedObject(ShortcutInfo.CREATOR);
+            mAlwaysOnTop = in.readBoolean();
         }
 
         public int getType() {
@@ -1324,6 +1391,10 @@
             return mActivityIntent;
         }
 
+        public boolean isAlwaysOnTop() {
+            return mAlwaysOnTop;
+        }
+
         @Nullable
         public TaskFragmentCreationParams getTaskFragmentCreationOptions() {
             return mTaskFragmentCreationOptions;
@@ -1392,6 +1463,9 @@
                             + " insetsType=" + Arrays.toString(mInsetsTypes) + "}";
                 case HIERARCHY_OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT:
                     return "{requestFocusOnTaskFragment: container=" + mContainer + "}";
+                case HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP:
+                    return "{setAlwaysOnTop: container=" + mContainer
+                            + " alwaysOnTop=" + mAlwaysOnTop + "}";
                 default:
                     return "{mType=" + mType + " container=" + mContainer + " reparent=" + mReparent
                             + " mToTop=" + mToTop
@@ -1421,6 +1495,7 @@
             dest.writeTypedObject(mTaskFragmentCreationOptions, flags);
             dest.writeTypedObject(mPendingIntent, flags);
             dest.writeTypedObject(mShortcutInfo, flags);
+            dest.writeBoolean(mAlwaysOnTop);
         }
 
         @Override
@@ -1479,6 +1554,8 @@
             @Nullable
             private ShortcutInfo mShortcutInfo;
 
+            private boolean mAlwaysOnTop;
+
             Builder(int type) {
                 mType = type;
             }
@@ -1538,6 +1615,11 @@
                 return this;
             }
 
+            Builder setAlwaysOnTop(boolean alwaysOnTop) {
+                mAlwaysOnTop = alwaysOnTop;
+                return this;
+            }
+
             Builder setTaskFragmentCreationOptions(
                     @Nullable TaskFragmentCreationParams taskFragmentCreationOptions) {
                 mTaskFragmentCreationOptions = taskFragmentCreationOptions;
@@ -1566,6 +1648,7 @@
                 hierarchyOp.mLaunchOptions = mLaunchOptions;
                 hierarchyOp.mActivityIntent = mActivityIntent;
                 hierarchyOp.mPendingIntent = mPendingIntent;
+                hierarchyOp.mAlwaysOnTop = mAlwaysOnTop;
                 hierarchyOp.mTaskFragmentCreationOptions = mTaskFragmentCreationOptions;
                 hierarchyOp.mShortcutInfo = mShortcutInfo;
 
diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java
index 1d396be..0730f3d 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -325,7 +325,8 @@
         public boolean checkApplicationCallbackRegistration(int priority,
                 OnBackInvokedCallback callback) {
             if (!mApplicationCallBackEnabled
-                    && !(callback instanceof CompatOnBackInvokedCallback)) {
+                    && !(callback instanceof CompatOnBackInvokedCallback)
+                    && !ALWAYS_ENFORCE_PREDICTIVE_BACK) {
                 Log.w("OnBackInvokedCallback",
                         "OnBackInvokedCallback is not enabled for the application."
                                 + "\nSet 'android:enableOnBackInvokedCallback=\"true\"' in the"
diff --git a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
index 2ee47b6..4babb70 100644
--- a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
+++ b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
@@ -34,7 +34,7 @@
     void setInputMethod(String id, in AndroidFuture future /* T=Void */);
     void setInputMethodAndSubtype(String id, in InputMethodSubtype subtype,
             in AndroidFuture future /* T=Void */);
-    void hideMySoftInput(int flags, in AndroidFuture future /* T=Void */);
+    void hideMySoftInput(int flags, int reason, in AndroidFuture future /* T=Void */);
     void showMySoftInput(int flags, in AndroidFuture future /* T=Void */);
     void updateStatusIconAsync(String packageName, int iconId);
     void switchToPreviousInputMethod(in AndroidFuture future /* T=Boolean */);
diff --git a/core/java/com/android/internal/inputmethod/InputMethodDebug.java b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
index d669768..97ad084 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodDebug.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
@@ -194,12 +194,12 @@
                 return "SHOW_SOFT_INPUT";
             case SoftInputShowHideReason.ATTACH_NEW_INPUT:
                 return "ATTACH_NEW_INPUT";
-            case SoftInputShowHideReason.SHOW_MY_SOFT_INPUT:
-                return "SHOW_MY_SOFT_INPUT";
+            case SoftInputShowHideReason.SHOW_SOFT_INPUT_FROM_IME:
+                return "SHOW_SOFT_INPUT_FROM_IME";
             case SoftInputShowHideReason.HIDE_SOFT_INPUT:
                 return "HIDE_SOFT_INPUT";
-            case SoftInputShowHideReason.HIDE_MY_SOFT_INPUT:
-                return "HIDE_MY_SOFT_INPUT";
+            case SoftInputShowHideReason.HIDE_SOFT_INPUT_FROM_IME:
+                return "HIDE_SOFT_INPUT_FROM_IME";
             case SoftInputShowHideReason.SHOW_AUTO_EDITOR_FORWARD_NAV:
                 return "SHOW_AUTO_EDITOR_FORWARD_NAV";
             case SoftInputShowHideReason.SHOW_STATE_VISIBLE_FORWARD_NAV:
@@ -242,6 +242,16 @@
                 return "SHOW_SOFT_INPUT_BY_INSETS_API";
             case SoftInputShowHideReason.HIDE_DISPLAY_IME_POLICY_HIDE:
                 return "HIDE_DISPLAY_IME_POLICY_HIDE";
+            case SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API:
+                return "HIDE_SOFT_INPUT_BY_INSETS_API";
+            case SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_BACK_KEY:
+                return "HIDE_SOFT_INPUT_BY_BACK_KEY";
+            case SoftInputShowHideReason.HIDE_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT:
+                return "HIDE_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT";
+            case SoftInputShowHideReason.HIDE_SOFT_INPUT_EXTRACT_INPUT_CHANGED:
+                return "HIDE_SOFT_INPUT_EXTRACT_INPUT_CHANGED";
+            case SoftInputShowHideReason.HIDE_SOFT_INPUT_IMM_DEPRECATION:
+                return "HIDE_SOFT_INPUT_IMM_DEPRECATION";
             default:
                 return "Unknown=" + reason;
         }
diff --git a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
index 15d7acf..67c2103 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
@@ -253,18 +253,19 @@
      * Calls {@link IInputMethodPrivilegedOperations#hideMySoftInput(int, IVoidResultCallback)}
      *
      * @param flags additional operating flags
+     * @param reason the reason to hide soft input
      * @see android.view.inputmethod.InputMethodManager#HIDE_IMPLICIT_ONLY
      * @see android.view.inputmethod.InputMethodManager#HIDE_NOT_ALWAYS
      */
     @AnyThread
-    public void hideMySoftInput(int flags) {
+    public void hideMySoftInput(int flags, @SoftInputShowHideReason int reason) {
         final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
         if (ops == null) {
             return;
         }
         try {
             final AndroidFuture<Void> future = new AndroidFuture<>();
-            ops.hideMySoftInput(flags, future);
+            ops.hideMySoftInput(flags, reason, future);
             CompletableFutureUtil.getResult(future);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
diff --git a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
index 9e57762..97ad5cb 100644
--- a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
+++ b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
@@ -19,8 +19,11 @@
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
 import android.annotation.IntDef;
+import android.os.IBinder;
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
 
 import java.lang.annotation.Retention;
 
@@ -31,9 +34,9 @@
 @IntDef(value = {
         SoftInputShowHideReason.SHOW_SOFT_INPUT,
         SoftInputShowHideReason.ATTACH_NEW_INPUT,
-        SoftInputShowHideReason.SHOW_MY_SOFT_INPUT,
+        SoftInputShowHideReason.SHOW_SOFT_INPUT_FROM_IME,
         SoftInputShowHideReason.HIDE_SOFT_INPUT,
-        SoftInputShowHideReason.HIDE_MY_SOFT_INPUT,
+        SoftInputShowHideReason.HIDE_SOFT_INPUT_FROM_IME,
         SoftInputShowHideReason.SHOW_AUTO_EDITOR_FORWARD_NAV,
         SoftInputShowHideReason.SHOW_STATE_VISIBLE_FORWARD_NAV,
         SoftInputShowHideReason.SHOW_STATE_ALWAYS_VISIBLE,
@@ -55,7 +58,12 @@
         SoftInputShowHideReason.SHOW_TOGGLE_SOFT_INPUT,
         SoftInputShowHideReason.HIDE_TOGGLE_SOFT_INPUT,
         SoftInputShowHideReason.SHOW_SOFT_INPUT_BY_INSETS_API,
-        SoftInputShowHideReason.HIDE_DISPLAY_IME_POLICY_HIDE})
+        SoftInputShowHideReason.HIDE_DISPLAY_IME_POLICY_HIDE,
+        SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API,
+        SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_BACK_KEY,
+        SoftInputShowHideReason.HIDE_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT,
+        SoftInputShowHideReason.HIDE_SOFT_INPUT_EXTRACT_INPUT_CHANGED,
+        SoftInputShowHideReason.HIDE_SOFT_INPUT_IMM_DEPRECATION})
 public @interface SoftInputShowHideReason {
     /** Show soft input by {@link android.view.inputmethod.InputMethodManager#showSoftInput}. */
     int SHOW_SOFT_INPUT = 0;
@@ -63,8 +71,12 @@
     /** Show soft input when {@code InputMethodManagerService#attachNewInputLocked} called. */
     int ATTACH_NEW_INPUT = 1;
 
-    /** Show soft input by {@code InputMethodManagerService#showMySoftInput}. */
-    int SHOW_MY_SOFT_INPUT = 2;
+    /** Show soft input by {@code InputMethodManagerService#showMySoftInput}. This is triggered when
+     *  the IME process try to show the keyboard.
+     *
+     * @see android.inputmethodservice.InputMethodService#requestShowSelf(int)
+     */
+    int SHOW_SOFT_INPUT_FROM_IME = 2;
 
     /**
      * Hide soft input by
@@ -72,8 +84,11 @@
      */
     int HIDE_SOFT_INPUT = 3;
 
-    /** Hide soft input by {@code InputMethodManagerService#hideMySoftInput}. */
-    int HIDE_MY_SOFT_INPUT = 4;
+    /**
+     * Hide soft input by
+     * {@link android.inputmethodservice.InputMethodService#requestHideSelf(int)}.
+     */
+    int HIDE_SOFT_INPUT_FROM_IME = 4;
 
     /**
      * Show soft input when navigated forward to the window (with
@@ -203,4 +218,32 @@
      * See also {@code InputMethodManagerService#mImeHiddenByDisplayPolicy}.
      */
     int HIDE_DISPLAY_IME_POLICY_HIDE = 26;
+
+    /**
+     * Hide soft input by {@link android.view.InsetsController#hide(int)}.
+     */
+    int HIDE_SOFT_INPUT_BY_INSETS_API = 27;
+
+    /**
+     * Hide soft input by {@link android.inputmethodservice.InputMethodService#handleBack(boolean)}.
+     */
+    int HIDE_SOFT_INPUT_BY_BACK_KEY = 28;
+
+    /**
+     * Hide soft input by
+     * {@link android.inputmethodservice.InputMethodService#onToggleSoftInput(int, int)}.
+     */
+    int HIDE_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT = 29;
+
+    /**
+     * Hide soft input by
+     * {@link android.inputmethodservice.InputMethodService#onExtractingInputChanged(EditorInfo)})}.
+     */
+    int HIDE_SOFT_INPUT_EXTRACT_INPUT_CHANGED = 30;
+
+    /**
+     * Hide soft input by the deprecated
+     * {@link InputMethodManager#hideSoftInputFromInputMethod(IBinder, int)}.
+     */
+    int HIDE_SOFT_INPUT_IMM_DEPRECATION = 31;
 }
diff --git a/core/java/com/android/internal/policy/DecorContext.java b/core/java/com/android/internal/policy/DecorContext.java
index 5e34c15..134a917 100644
--- a/core/java/com/android/internal/policy/DecorContext.java
+++ b/core/java/com/android/internal/policy/DecorContext.java
@@ -137,4 +137,13 @@
         }
         return false;
     }
+
+    @Override
+    public boolean isConfigurationContext() {
+        Context context = mContext.get();
+        if (context != null) {
+            return context.isConfigurationContext();
+        }
+        return false;
+    }
 }
diff --git a/core/java/com/android/internal/util/ScreenshotHelper.java b/core/java/com/android/internal/util/ScreenshotHelper.java
index 8af2450..9474f6f 100644
--- a/core/java/com/android/internal/util/ScreenshotHelper.java
+++ b/core/java/com/android/internal/util/ScreenshotHelper.java
@@ -1,6 +1,7 @@
 package com.android.internal.util;
 
 import static android.content.Intent.ACTION_USER_SWITCHED;
+import static android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -27,7 +28,6 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.Log;
-import android.view.WindowManager;
 import android.view.WindowManager.ScreenshotSource;
 import android.view.WindowManager.ScreenshotType;
 
@@ -42,10 +42,15 @@
     public static final int SCREENSHOT_MSG_PROCESS_COMPLETE = 2;
 
     /**
-     * Describes a screenshot request (to make it easier to pass data through to the handler).
+     * Describes a screenshot request.
      */
     public static class ScreenshotRequest implements Parcelable {
+        @ScreenshotType
+        private final int mType;
+
+        @ScreenshotSource
         private final int mSource;
+
         private final Bundle mBitmapBundle;
         private final Rect mBoundsInScreen;
         private final Insets mInsets;
@@ -53,20 +58,27 @@
         private final int mUserId;
         private final ComponentName mTopComponent;
 
-        @VisibleForTesting
-        public ScreenshotRequest(int source) {
-            mSource = source;
-            mBitmapBundle = null;
-            mBoundsInScreen = null;
-            mInsets = null;
-            mTaskId = -1;
-            mUserId = -1;
-            mTopComponent = null;
+
+        public ScreenshotRequest(@ScreenshotType int type, @ScreenshotSource int source) {
+            this(type, source, /* topComponent */ null);
         }
 
-        @VisibleForTesting
-        public ScreenshotRequest(int source, Bundle bitmapBundle, Rect boundsInScreen,
-                Insets insets, int taskId, int userId, ComponentName topComponent) {
+        public ScreenshotRequest(@ScreenshotType int type, @ScreenshotSource int source,
+                ComponentName topComponent) {
+            this(type,
+                source,
+                /* bitmapBundle*/ null,
+                /* boundsInScreen */ null,
+                /* insets */ null,
+                /* taskId */ -1,
+                /* userId */ -1,
+                topComponent);
+        }
+
+        public ScreenshotRequest(@ScreenshotType int type, @ScreenshotSource int source,
+                Bundle bitmapBundle, Rect boundsInScreen, Insets insets, int taskId, int userId,
+                ComponentName topComponent) {
+            mType = type;
             mSource = source;
             mBitmapBundle = bitmapBundle;
             mBoundsInScreen = boundsInScreen;
@@ -77,6 +89,7 @@
         }
 
         ScreenshotRequest(Parcel in) {
+            mType = in.readInt();
             mSource = in.readInt();
             if (in.readInt() == 1) {
                 mBitmapBundle = in.readBundle(getClass().getClassLoader());
@@ -96,6 +109,12 @@
             }
         }
 
+        @ScreenshotType
+        public int getType() {
+            return mType;
+        }
+
+        @ScreenshotSource
         public int getSource() {
             return mSource;
         }
@@ -131,6 +150,7 @@
 
         @Override
         public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(mType);
             dest.writeInt(mSource);
             if (mBitmapBundle == null) {
                 dest.writeInt(0);
@@ -208,8 +228,7 @@
          * Extracts the Bitmap added to a Bundle with {@link #hardwareBitmapToBundle(Bitmap)} .}
          *
          * <p>This Bitmap contains the HardwareBuffer from the original caller, be careful passing
-         * this
-         * Bitmap on to any other source.
+         * this Bitmap on to any other source.
          *
          * @param bundle containing the bitmap
          * @return a hardware Bitmap
@@ -219,8 +238,9 @@
                 throw new IllegalArgumentException("Bundle does not contain a hardware bitmap");
             }
 
-            HardwareBuffer buffer = bundle.getParcelable(KEY_BUFFER);
-            ParcelableColorSpace colorSpace = bundle.getParcelable(KEY_COLOR_SPACE);
+            HardwareBuffer buffer = bundle.getParcelable(KEY_BUFFER, HardwareBuffer.class);
+            ParcelableColorSpace colorSpace = bundle.getParcelable(KEY_COLOR_SPACE,
+                    ParcelableColorSpace.class);
 
             return Bitmap.wrapHardwareBuffer(Objects.requireNonNull(buffer),
                     colorSpace.getColorSpace());
@@ -260,16 +280,16 @@
      * Added to support reducing unit test duration; the method variant without a timeout argument
      * is recommended for general use.
      *
-     * @param screenshotType The type of screenshot, defined by {@link ScreenshotType}
+     * @param type The type of screenshot, defined by {@link ScreenshotType}
      * @param source The source of the screenshot request, defined by {@link ScreenshotSource}
      * @param handler used to process messages received from the screenshot service
      * @param completionConsumer receives the URI of the captured screenshot, once saved or
      *         null if no screenshot was saved
      */
-    public void takeScreenshot(@ScreenshotType int screenshotType, @ScreenshotSource int source,
+    public void takeScreenshot(@ScreenshotType int type, @ScreenshotSource int source,
             @NonNull Handler handler, @Nullable Consumer<Uri> completionConsumer) {
-        ScreenshotRequest screenshotRequest = new ScreenshotRequest(source);
-        takeScreenshot(screenshotType, handler, screenshotRequest, SCREENSHOT_TIMEOUT_MS,
+        ScreenshotRequest screenshotRequest = new ScreenshotRequest(type, source);
+        takeScreenshot(handler, screenshotRequest, SCREENSHOT_TIMEOUT_MS,
                 completionConsumer);
     }
 
@@ -279,7 +299,7 @@
      * Added to support reducing unit test duration; the method variant without a timeout argument
      * is recommended for general use.
      *
-     * @param screenshotType The type of screenshot, defined by {@link ScreenshotType}
+     * @param type The type of screenshot, defined by {@link ScreenshotType}
      * @param source The source of the screenshot request, defined by {@link ScreenshotSource}
      * @param handler used to process messages received from the screenshot service
      * @param timeoutMs time limit for processing, intended only for testing
@@ -287,10 +307,10 @@
      *         null if no screenshot was saved
      */
     @VisibleForTesting
-    public void takeScreenshot(@ScreenshotType int screenshotType, @ScreenshotSource int source,
+    public void takeScreenshot(@ScreenshotType int type, @ScreenshotSource int source,
             @NonNull Handler handler, long timeoutMs, @Nullable Consumer<Uri> completionConsumer) {
-        ScreenshotRequest screenshotRequest = new ScreenshotRequest(source);
-        takeScreenshot(screenshotType, handler, screenshotRequest, timeoutMs, completionConsumer);
+        ScreenshotRequest screenshotRequest = new ScreenshotRequest(type, source);
+        takeScreenshot(handler, screenshotRequest, timeoutMs, completionConsumer);
     }
 
     /**
@@ -311,14 +331,12 @@
             @NonNull Insets insets, int taskId, int userId, ComponentName topComponent,
             @ScreenshotSource int source, @NonNull Handler handler,
             @Nullable Consumer<Uri> completionConsumer) {
-        ScreenshotRequest screenshotRequest = new ScreenshotRequest(source, screenshotBundle,
-                boundsInScreen, insets, taskId, userId, topComponent);
-        takeScreenshot(WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE, handler, screenshotRequest,
-                SCREENSHOT_TIMEOUT_MS,
-                completionConsumer);
+        ScreenshotRequest screenshotRequest = new ScreenshotRequest(TAKE_SCREENSHOT_PROVIDED_IMAGE,
+                source, screenshotBundle, boundsInScreen, insets, taskId, userId, topComponent);
+        takeScreenshot(handler, screenshotRequest, SCREENSHOT_TIMEOUT_MS, completionConsumer);
     }
 
-    private void takeScreenshot(@ScreenshotType int screenshotType, @NonNull Handler handler,
+    private void takeScreenshot(@NonNull Handler handler,
             ScreenshotRequest screenshotRequest, long timeoutMs,
             @Nullable Consumer<Uri> completionConsumer) {
         synchronized (mScreenshotLock) {
@@ -336,7 +354,7 @@
                 }
             };
 
-            Message msg = Message.obtain(null, screenshotType, screenshotRequest);
+            Message msg = Message.obtain(null, 0, screenshotRequest);
 
             Handler h = new Handler(handler.getLooper()) {
                 @Override
diff --git a/core/java/com/android/internal/widget/LocalImageResolver.java b/core/java/com/android/internal/widget/LocalImageResolver.java
index b866723..b11ea29 100644
--- a/core/java/com/android/internal/widget/LocalImageResolver.java
+++ b/core/java/com/android/internal/widget/LocalImageResolver.java
@@ -25,6 +25,7 @@
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
 import android.net.Uri;
+import android.text.TextUtils;
 import android.util.Log;
 import android.util.Size;
 
@@ -108,6 +109,12 @@
                 }
                 break;
             case Icon.TYPE_RESOURCE:
+                if (!(TextUtils.isEmpty(icon.getResPackage())
+                        || context.getPackageName().equals(icon.getResPackage()))) {
+                    // We can't properly resolve icons from other packages here, so fall back.
+                    return icon.loadDrawable(context);
+                }
+
                 Drawable result = resolveImage(icon.getResId(), context, maxWidth, maxHeight);
                 if (result != null) {
                     return tintDrawable(icon, result);
diff --git a/core/java/com/android/internal/widget/floatingtoolbar/FloatingToolbarPopup.java b/core/java/com/android/internal/widget/floatingtoolbar/FloatingToolbarPopup.java
index c484525..f7af67b 100644
--- a/core/java/com/android/internal/widget/floatingtoolbar/FloatingToolbarPopup.java
+++ b/core/java/com/android/internal/widget/floatingtoolbar/FloatingToolbarPopup.java
@@ -21,6 +21,7 @@
 import android.graphics.Rect;
 import android.view.MenuItem;
 import android.view.View;
+import android.view.selectiontoolbar.SelectionToolbarManager;
 import android.widget.PopupWindow;
 
 import java.util.List;
@@ -92,7 +93,10 @@
      * enabled, otherwise returns {@link LocalFloatingToolbarPopup} implementation.
      */
     static FloatingToolbarPopup createInstance(Context context, View parent) {
-        return new LocalFloatingToolbarPopup(context, parent);
+        boolean enabled = SelectionToolbarManager.isRemoteSelectionToolbarEnabled(context);
+        return enabled
+                ? new RemoteFloatingToolbarPopup(context, parent)
+                : new LocalFloatingToolbarPopup(context, parent);
     }
 
 }
diff --git a/core/java/com/android/internal/widget/floatingtoolbar/RemoteFloatingToolbarPopup.java b/core/java/com/android/internal/widget/floatingtoolbar/RemoteFloatingToolbarPopup.java
index 8c2eb10..8787c39 100644
--- a/core/java/com/android/internal/widget/floatingtoolbar/RemoteFloatingToolbarPopup.java
+++ b/core/java/com/android/internal/widget/floatingtoolbar/RemoteFloatingToolbarPopup.java
@@ -23,6 +23,7 @@
 import android.annotation.Nullable;
 import android.annotation.UiThread;
 import android.content.Context;
+import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -107,6 +108,7 @@
     private int mSuggestedWidth;
     private final Rect mScreenViewPort = new Rect();
     private boolean mWidthChanged = true;
+    private final boolean mIsLightTheme;
 
     private final int[] mCoordsOnScreen = new int[2];
     private final int[] mCoordsOnWindow = new int[2];
@@ -116,9 +118,17 @@
         mPopupWindow = createPopupWindow(context);
         mSelectionToolbarManager = context.getSystemService(SelectionToolbarManager.class);
         mSelectionToolbarCallback = new SelectionToolbarCallbackImpl(this);
+        mIsLightTheme = isLightTheme(context);
         mFloatingToolbarToken = NO_TOOLBAR_ID;
     }
 
+    private boolean isLightTheme(Context context) {
+        TypedArray a = context.obtainStyledAttributes(new int[]{R.attr.isLightTheme});
+        boolean isLightTheme = a.getBoolean(0, true);
+        a.recycle();
+        return isLightTheme;
+    }
+
     @UiThread
     @Override
     public void show(List<MenuItem> menuItems,
@@ -155,7 +165,7 @@
                 contentRect,
                 suggestWidth,
                 mScreenViewPort,
-                mParent.getViewRootImpl().getInputToken());
+                mParent.getViewRootImpl().getInputToken(), mIsLightTheme);
         if (DEBUG) {
             Log.v(FloatingToolbar.FLOATING_TOOLBAR_TAG,
                     "RemoteFloatingToolbarPopup.show() for " + showInfo);
diff --git a/core/proto/android/server/vibrator/vibratormanagerservice.proto b/core/proto/android/server/vibrator/vibratormanagerservice.proto
index 2a625b027..25a1f68 100644
--- a/core/proto/android/server/vibrator/vibratormanagerservice.proto
+++ b/core/proto/android/server/vibrator/vibratormanagerservice.proto
@@ -86,7 +86,7 @@
     optional int32 flags = 3;
 }
 
-// Next id: 8
+// Next Tag: 9
 message VibrationProto {
     option (.android.msg_privacy).dest = DEST_AUTOMATIC;
     optional int64 start_time = 1;
@@ -94,11 +94,43 @@
     optional CombinedVibrationEffectProto effect = 3;
     optional CombinedVibrationEffectProto original_effect = 4;
     optional VibrationAttributesProto attributes = 5;
-    optional int32 status = 6;
     optional int64 duration_ms = 7;
+    optional Status status = 8;
+    reserved 6; // prev int32 status
+
+    // Also used by VibrationReported from frameworks/proto_logging/stats/atoms.proto.
+    // Next Tag: 26
+    enum Status {
+        UNKNOWN = 0;
+        RUNNING = 1;
+        FINISHED = 2;
+        FINISHED_UNEXPECTED = 3;  // Didn't terminate in the usual way.
+        FORWARDED_TO_INPUT_DEVICES = 4;
+        CANCELLED_BINDER_DIED = 5;
+        CANCELLED_BY_SCREEN_OFF = 6;
+        CANCELLED_BY_SETTINGS_UPDATE = 7;
+        CANCELLED_BY_USER = 8;
+        CANCELLED_BY_UNKNOWN_REASON = 9;
+        CANCELLED_SUPERSEDED = 10;
+        IGNORED_ERROR_APP_OPS = 11;
+        IGNORED_ERROR_CANCELLING = 12;
+        IGNORED_ERROR_SCHEDULING = 13;
+        IGNORED_ERROR_TOKEN= 14;
+        IGNORED_APP_OPS = 15;
+        IGNORED_BACKGROUND = 16;
+        IGNORED_UNKNOWN_VIBRATION = 17;
+        IGNORED_UNSUPPORTED = 18;
+        IGNORED_FOR_EXTERNAL = 19;
+        IGNORED_FOR_HIGHER_IMPORTANCE = 20;
+        IGNORED_FOR_ONGOING = 21;
+        IGNORED_FOR_POWER = 22;
+        IGNORED_FOR_RINGER_MODE = 23;
+        IGNORED_FOR_SETTINGS = 24;
+        IGNORED_SUPERSEDED = 25;
+    }
 }
 
-// Next id: 25
+// Next Tag: 25
 message VibratorManagerServiceDumpProto {
     option (.android.msg_privacy).dest = DEST_AUTOMATIC;
     repeated int32 vibrator_ids = 1;
diff --git a/core/res/res/color/system_bar_background_semi_transparent.xml b/core/res/res/color/system_bar_background_semi_transparent.xml
new file mode 100644
index 0000000..839d58a
--- /dev/null
+++ b/core/res/res/color/system_bar_background_semi_transparent.xml
@@ -0,0 +1,19 @@
+<?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.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@color/system_neutral2_900" android:alpha="0.5" />
+</selector>
diff --git a/core/res/res/layout/side_fps_toast.xml b/core/res/res/layout/side_fps_toast.xml
new file mode 100644
index 0000000..96860b0
--- /dev/null
+++ b/core/res/res/layout/side_fps_toast.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:minWidth="350dp"
+              android:layout_gravity="center"
+              android:background="@color/side_fps_toast_background">
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/fp_power_button_enrollment_title"
+        android:singleLine="true"
+        android:ellipsize="end"
+        android:textColor="@color/side_fps_text_color"
+        android:paddingLeft="20dp"/>
+    <Space
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_weight="1"/>
+    <Button
+        android:id="@+id/turn_off_screen"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/fp_power_button_enrollment_button_text"
+        android:paddingRight="20dp"
+        style="?android:attr/buttonBarNegativeButtonStyle"
+        android:textColor="@color/side_fps_button_color"
+        android:maxLines="1"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index cc1d9d1..d777334 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"ካሜራ አይገኝም"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"በስልክ ላይ ይቀጥሉ"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"ማይክሮፎን አይገኝም"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Play መደብር አይገኝም"</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>
@@ -1955,12 +1954,9 @@
     <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>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <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="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>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 77c447e..4b04132 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1948,8 +1948,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"الكاميرا غير متاحة"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"الاستمرار على الهاتف"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"الميكروفون غير متاح"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"‏متجر Play غير متوفّر"</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>
@@ -1959,12 +1958,9 @@
     <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>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <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="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>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 4fc1153..957dc54 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"কেমেৰা উপলব্ধ নহয়"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"ফ’নতে অব্যাহত ৰাখক"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"মাইক্ৰ’ফ’ন উপলব্ধ নহয়"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <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>
@@ -1955,12 +1954,9 @@
     <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>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <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="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>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 9cc5e5d..e139f4a9 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kamera əlçatan deyil"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Telefonda davam edin"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofon əlçatan deyil"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Play Market əlçatmazdır"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Android TV ayarları əlçatan deyil"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"Planşet ayarları əlçatan deyil"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Telefon ayarları əlçatan deyil"</string>
@@ -1955,12 +1954,9 @@
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Bu tətbiq əlavə təhlükəsizlik tələb edir. Android TV cihazınızda sınayın."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Bu tətbiq əlavə təhlükəsizlik tələb edir. Planşetinizdə sınayın."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Bu tətbiq əlavə təhlükəsizlik tələb edir. Telefonunuzda sınayın."</string>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"<xliff:g id="DEVICE">%1$s</xliff:g> cihazınızda buna giriş mümkün deyil. Android TV cihazınızda sınayın."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"<xliff:g id="DEVICE">%1$s</xliff:g> cihazınızda buna giriş mümkün deyil. Planşetinizdə sınayın."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"<xliff:g id="DEVICE">%1$s</xliff:g> cihazınızda buna giriş mümkün deyil. Telefonunuzda sınayın."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Bu tətbiq köhnə Android versiyası üçün hazırlanıb və düzgün işləməyə bilər. Güncəlləməni yoxlayın və ya developer ilə əlaqə saxlayın."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Güncəllənmə olmasını yoxlayın"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Yeni mesajlarınız var"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index c39495d..86e8735 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1945,8 +1945,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kamera nije dostupna"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Nastavite na telefonu"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofon je nedostupan"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Play prodavnica nije dostupna"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Podešavanja Android TV-a su nedostupna"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"Podešavanja tableta su nedostupna"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Podešavanja telefona su nedostupna"</string>
@@ -1956,12 +1955,9 @@
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Ova aplikacija zahteva dodatnu bezbednost. Probajte na Android TV uređaju."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Ova aplikacija zahteva dodatnu bezbednost. Probajte na tabletu."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Ova aplikacija zahteva dodatnu bezbednost. Probajte na telefonu."</string>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"Ovoj aplikaciji ne može da se pristupi sa uređaja <xliff:g id="DEVICE">%1$s</xliff:g>. Probajte na Android TV uređaju."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"Ovoj aplikaciji ne može da se pristupi sa uređaja <xliff:g id="DEVICE">%1$s</xliff:g>. Probajte na tabletu."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Ovoj aplikaciji ne može da se pristupi sa uređaja <xliff:g id="DEVICE">%1$s</xliff:g>. Probajte na telefonu."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ova aplikacija je napravljena za stariju verziju Android-a, pa možda neće raditi ispravno. Potražite ažuriranja ili kontaktirajte programera."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Potraži ažuriranje"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Imate nove poruke"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 0377c092..a24aee7 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1946,8 +1946,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Камера недаступная"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Працягніце на тэлефоне"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Мікрафон недаступны"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Крама Play недаступная"</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>
@@ -1957,12 +1956,9 @@
     <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>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <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="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>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index c6df6a4..86443d7 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Няма достъп до камерата"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Продължете на телефона"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Микрофонът не е достъпен"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Няма достъп до Google Play Магазин"</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>
@@ -1955,12 +1954,9 @@
     <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>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <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="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>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 51d8d25..085c706 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1945,8 +1945,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kamera nije dostupna"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Nastavite na telefonu"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofon nije dostupan"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Play trgovina nije dostupna"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Postavke Android TV-a nisu dostupne"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"Postavke tableta nisu dostupne"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Postavke telefona nisu dostupne"</string>
@@ -1956,12 +1955,9 @@
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Ova aplikacija zahtijeva dodatnu sigurnost. Umjesto toga pokušajte na uređaju Android TV."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Ova aplikacija zahtijeva dodatnu sigurnost. Umjesto toga pokušajte na tabletu."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Ova aplikacija zahtijeva dodatnu sigurnost. Umjesto toga pokušajte na telefonu."</string>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"Ne možete pristupiti ovoj aplikaciji na uređaju <xliff:g id="DEVICE">%1$s</xliff:g>. Umjesto toga pokušajte na uređaju Android TV."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"Ne možete pristupiti ovoj aplikaciji na uređaju <xliff:g id="DEVICE">%1$s</xliff:g>. Umjesto toga pokušajte na tabletu."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Ne možete pristupiti ovoj aplikaciji na uređaju <xliff:g id="DEVICE">%1$s</xliff:g>. Umjesto toga pokušajte na telefonu."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ova aplikacija je pravljena za stariju verziju Androida i možda neće ispravno raditi. Provjerite jesu li dostupna ažuriranja ili kontaktirajte programera."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Provjeri je li dostupno ažuriranje"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Imate nove poruke"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index f555a56..1ce2192 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"La càmera no està disponible"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Continua al telèfon"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"El micròfon no està disponible"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <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>
@@ -1955,12 +1954,9 @@
     <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>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"No s\'hi pot accedir des del dispositiu <xliff:g id="DEVICE">%1$s</xliff:g>. Prova-ho al dispositiu Android TV."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"No s\'hi pot accedir des del dispositiu <xliff:g id="DEVICE">%1$s</xliff:g>. Prova-ho a la tauleta."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"No s\'hi pot accedir des del dispositiu <xliff:g id="DEVICE">%1$s</xliff:g>. Prova-ho al telèfon."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Aquesta aplicació es va crear per a una versió antiga d\'Android i pot ser que no funcioni correctament. Prova de cercar actualitzacions o contacta amb el desenvolupador."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Cerca actualitzacions"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Tens missatges nous"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 01a448b..1a37357 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1946,8 +1946,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kamera není k dispozici"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Pokračujte na telefonu"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofon není k dispozici"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Obchod Play není dostupný"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Nastavení Android TV není k dispozici"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"Nastavení tabletu není k dispozici"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Nastavení telefonu není k dispozici"</string>
@@ -1957,12 +1956,9 @@
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Tato aplikace požaduje další zabezpečení. Zkuste to na zařízení Android TV."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Tato aplikace požaduje další zabezpečení. Zkuste to na tabletu."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Tato aplikace požaduje další zabezpečení. Zkuste to na telefonu."</string>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"Tato položka na vašem zařízení <xliff:g id="DEVICE">%1$s</xliff:g> není k dispozici. Zkuste to na zařízení Android TV."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"Tato položka na vašem zařízení <xliff:g id="DEVICE">%1$s</xliff:g> není k dispozici. Zkuste to na tabletu."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Tato položka na vašem zařízení <xliff:g id="DEVICE">%1$s</xliff:g> není k dispozici. Zkuste to na telefonu."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Tato aplikace byla vytvořena pro starší verzi systému Android a nemusí fungovat správně. Zkuste vyhledat aktualizace, případně kontaktujte vývojáře."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Zkontrolovat aktualizace"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Máte nové zprávy"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 3aff205..b6b33f6 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kameraet er ikke tilgængeligt"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Fortsæt på telefonen"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofonen er ikke tilgængelig"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Play Butik er ikke tilgængelig"</string>
     <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>
@@ -1955,12 +1954,9 @@
     <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>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"Du kan ikke gøre dette på din <xliff:g id="DEVICE">%1$s</xliff:g>. Prøv på din Android TV-enhed i stedet."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"Du kan ikke gøre dette på din <xliff:g id="DEVICE">%1$s</xliff:g>. Prøv på din tablet i stedet."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Du kan ikke gøre dette på din <xliff:g id="DEVICE">%1$s</xliff:g>. Prøv på din telefon i stedet."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Denne app er lavet til en ældre version af Android og fungerer muligvis ikke korrekt. Prøv at søge efter opdateringer, eller kontakt udvikleren."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Søg efter opdatering"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Du har nye beskeder"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 98413f7..1e4bbfc 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1022,9 +1022,9 @@
     <string name="js_dialog_before_unload" msgid="7213364985774778744">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nMöchtest du diese Seite wirklich verlassen?"</string>
     <string name="save_password_label" msgid="9161712335355510035">"Bestätigen"</string>
     <string name="double_tap_toast" msgid="7065519579174882778">"Tipp: Zum Vergrößern und Verkleinern doppeltippen"</string>
-    <string name="autofill_this_form" msgid="3187132440451621492">"Automatisches Ausfüllen"</string>
-    <string name="setup_autofill" msgid="5431369130866618567">"Autom.Ausfüll.konf."</string>
-    <string name="autofill_window_title" msgid="4379134104008111961">"Mit <xliff:g id="SERVICENAME">%1$s</xliff:g> automatisch ausfüllen"</string>
+    <string name="autofill_this_form" msgid="3187132440451621492">"Autofill"</string>
+    <string name="setup_autofill" msgid="5431369130866618567">"Autofill einrichten"</string>
+    <string name="autofill_window_title" msgid="4379134104008111961">"Autofill mit <xliff:g id="SERVICENAME">%1$s</xliff:g>"</string>
     <string name="autofill_address_name_separator" msgid="8190155636149596125">" "</string>
     <string name="autofill_address_summary_name_format" msgid="3402882515222673691">"$1$2$3"</string>
     <string name="autofill_address_summary_separator" msgid="760522655085707045">", "</string>
@@ -1145,7 +1145,7 @@
     <string name="selectTextMode" msgid="3225108910999318778">"Text auswählen"</string>
     <string name="undo" msgid="3175318090002654673">"Rückgängig machen"</string>
     <string name="redo" msgid="7231448494008532233">"Wiederholen"</string>
-    <string name="autofill" msgid="511224882647795296">"Automatisches Ausfüllen"</string>
+    <string name="autofill" msgid="511224882647795296">"Autofill"</string>
     <string name="textSelectionCABTitle" msgid="5151441579532476940">"Textauswahl"</string>
     <string name="addToDictionary" msgid="8041821113480950096">"Zum Wörterbuch hinzufügen"</string>
     <string name="deleteText" msgid="4200807474529938112">"Löschen"</string>
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kamera nicht verfügbar"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Weiter auf Smartphone"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofon nicht verfügbar"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Play Store nicht verfügbar"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Android TV-Einstellungen nicht verfügbar"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"Tablet-Einstellungen nicht verfügbar"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Smartphone-Einstellungen nicht verfügbar"</string>
@@ -1955,12 +1954,9 @@
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Diese App fordert zusätzliche Sicherheit an. Versuch es stattdessen auf deinem Android TV-Gerät."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Diese App fordert zusätzliche Sicherheit an. Versuch es stattdessen auf deinem Tablet."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Diese App fordert zusätzliche Sicherheit an. Versuch es stattdessen auf deinem Smartphone."</string>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"Auf deinem <xliff:g id="DEVICE">%1$s</xliff:g> ist kein Zugriff möglich. Versuch es stattdessen auf deinem Android TV-Gerät."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"Auf deinem <xliff:g id="DEVICE">%1$s</xliff:g> ist kein Zugriff möglich. Versuch es stattdessen auf deinem Tablet."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Auf deinem <xliff:g id="DEVICE">%1$s</xliff:g> ist kein Zugriff möglich. Versuch es stattdessen auf deinem Smartphone."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Diese App wurde für eine ältere Android-Version entwickelt und funktioniert möglicherweise nicht mehr richtig. Prüfe, ob Updates verfügbar sind oder kontaktiere den Entwickler."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Auf Updates prüfen"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Du hast neue Nachrichten"</string>
@@ -1999,11 +1995,11 @@
     <string name="time_picker_prompt_label" msgid="303588544656363889">"Uhrzeit eingeben"</string>
     <string name="time_picker_text_input_mode_description" msgid="4761160667516611576">"In den Texteingabemodus wechseln, um die Uhrzeit einzugeben."</string>
     <string name="time_picker_radial_mode_description" msgid="1222342577115016953">"In den Uhrzeitmodus wechseln, um die Uhrzeit einzugeben."</string>
-    <string name="autofill_picker_accessibility_title" msgid="4425806874792196599">"Optionen für automatisches Ausfüllen"</string>
-    <string name="autofill_save_accessibility_title" msgid="1523225776218450005">"Für „Automatisches Ausfüllen“ speichern"</string>
+    <string name="autofill_picker_accessibility_title" msgid="4425806874792196599">"Autofill-Optionen"</string>
+    <string name="autofill_save_accessibility_title" msgid="1523225776218450005">"Für Autofill speichern"</string>
     <string name="autofill_error_cannot_autofill" msgid="6528827648643138596">"Inhalte können nicht automatisch ausgefüllt werden"</string>
-    <string name="autofill_picker_no_suggestions" msgid="1076022650427481509">"Keine Vorschläge für automatisches Ausfüllen"</string>
-    <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{Ein Vorschlag für automatisches Ausfüllen}other{# Vorschläge für automatisches Ausfüllen}}"</string>
+    <string name="autofill_picker_no_suggestions" msgid="1076022650427481509">"Keine Autofill-Vorschläge"</string>
+    <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{1 Autofill-Vorschlag}other{# Autofill-Vorschläge}}"</string>
     <string name="autofill_save_title" msgid="7719802414283739775">"In "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>" speichern?"</string>
     <string name="autofill_save_title_with_type" msgid="3002460014579799605">"<xliff:g id="TYPE">%1$s</xliff:g> in "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" speichern?"</string>
     <string name="autofill_save_title_with_2types" msgid="3783270967447869241">"<xliff:g id="TYPE_0">%1$s</xliff:g> und <xliff:g id="TYPE_1">%2$s</xliff:g> in "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>" speichern?"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 7cc2bcb..fc5396b 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Η κάμερα δεν είναι διαθέσιμη"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Συνέχεια στο τηλέφωνο"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Το μικρόφωνο δεν είναι διαθέσιμο"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <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">"Οι ρυθμίσεις του tablet δεν είναι διαθέσιμες"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Οι ρυθμίσεις του τηλεφώνου δεν είναι διαθέσιμες"</string>
@@ -1955,12 +1954,9 @@
     <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">"Αυτή η εφαρμογή ζητά πρόσθετη ασφάλεια. Δοκιμάστε στο tablet σας."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Αυτή η εφαρμογή ζητά πρόσθετη ασφάλεια. Δοκιμάστε στο τηλέφωνό σας."</string>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <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>. Δοκιμάστε στο tablet σας."</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>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index e3fd3a0..2fdb821 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"La cámara no está disponible"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Continúa en el teléfono"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"El micrófono no está disponible"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <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ón de Android TV no está disponible"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"La configuración de la tablet no está disponible"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"La configuración del teléfono no está disponible"</string>
@@ -1955,12 +1954,9 @@
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Esta app solicita seguridad adicional. Inténtalo en tu dispositivo Android TV."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Esta app solicita seguridad adicional. Inténtalo en tu tablet."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Esta app solicita seguridad adicional. Inténtalo en tu teléfono."</string>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"No se puede acceder a esto en tu <xliff:g id="DEVICE">%1$s</xliff:g>. Inténtalo en tu dispositivo Android TV."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"No se puede acceder a esto en tu <xliff:g id="DEVICE">%1$s</xliff:g>. Inténtalo en tu tablet."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"No se puede acceder a esto en tu <xliff:g id="DEVICE">%1$s</xliff:g>. Inténtalo en tu teléfono."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Esta app se creó para una versión anterior de Android y es posible que no funcione correctamente. Busca actualizaciones o comunícate con el programador."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Buscar actualización"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Tienes mensajes nuevos"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 3a85197..0b24e30 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Cámara no disponible"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Continúa en el teléfono"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Micrófono no disponible"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Play Store no disponible"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Ajustes de Android TV no disponibles"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"Ajustes del tablet no disponibles"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Ajustes del teléfono no disponibles"</string>
@@ -1955,12 +1954,9 @@
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Esta aplicación solicita seguridad adicional. Prueba en tu dispositivo Android TV."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Esta aplicación solicita seguridad adicional. Prueba en tu tablet."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Esta aplicación solicita seguridad adicional. Prueba en tu teléfono."</string>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"No se puede acceder a este contenido en tu <xliff:g id="DEVICE">%1$s</xliff:g>. Prueba en tu dispositivo Android TV."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"No se puede acceder a este contenido en tu <xliff:g id="DEVICE">%1$s</xliff:g>. Prueba en tu tablet."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"No se puede acceder a este contenido en tu <xliff:g id="DEVICE">%1$s</xliff:g>. Prueba en tu teléfono."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Esta aplicación se ha diseñado para una versión anterior de Android y es posible que no funcione correctamente. Busca actualizaciones o ponte en contacto con el desarrollador."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Buscar actualizaciones"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Tienes mensajes nuevos"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 4c6a68d..7a706e5 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kaamera pole saadaval"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Jätkake telefonis"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofon pole saadaval"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Play pood ei ole saadaval"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Android TV seaded pole saadaval"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"Tahvelarvuti seaded pole saadaval"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Telefoni seaded pole saadaval"</string>
@@ -1955,12 +1954,9 @@
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"See rakendus nõuab lisaturvalisust. Proovige juurde pääseda oma Android TV seadmes."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"See rakendus nõuab lisaturvalisust. Proovige juurde pääseda oma tahvelarvutis."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"See rakendus nõuab lisaturvalisust. Proovige juurde pääseda oma telefonis."</string>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"Sellele ei pääse teie seadmes <xliff:g id="DEVICE">%1$s</xliff:g> juurde. Proovige juurde pääseda oma Android TV seadmes."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"Sellele ei pääse teie seadmes <xliff:g id="DEVICE">%1$s</xliff:g> juurde. Proovige juurde pääseda oma tahvelarvutis."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Sellele ei pääse teie seadmes <xliff:g id="DEVICE">%1$s</xliff:g> juurde. Proovige juurde pääseda oma telefonis."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"See rakendus on loodud Androidi vanema versiooni jaoks ega pruugi õigesti töötada. Otsige värskendusi või võtke ühendust arendajaga."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Otsi värskendust"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Teile on uusi sõnumeid"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 42161bf..c301611 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1857,10 +1857,10 @@
     <string name="package_updated_device_owner" msgid="7560272363805506941">"Administratzaileak eguneratu du"</string>
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Administratzaileak ezabatu du"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Ados"</string>
-    <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Bateria-aurrezleak gai iluna aktibatzen du, eta murriztu edo desaktibatu egiten ditu atzeko planoko jarduerak, zenbait efektu bisual, eta eginbide jakin eta sareko konexio batzuk."</string>
-    <string name="battery_saver_description" msgid="8518809702138617167">"Bateria-aurrezleak gai iluna aktibatzen du, eta atzeko planoko jarduerak, zenbait efektu bisual, eta eginbide jakin eta sareko konexio batzuk murrizten edo desaktibatzen ditu."</string>
-    <string name="data_saver_description" msgid="4995164271550590517">"Datu-erabilera murrizteko, atzeko planoan datuak bidaltzea eta jasotzea galarazten die datu-aurrezleak aplikazio batzuei. Erabiltzen ari zaren aplikazioek datuak atzitu ahalko dituzte, baina baliteke maiztasun txikiagoarekin atzitzea. Ondorioz, adibidez, baliteke irudiak ez erakustea haiek sakatu arte."</string>
-    <string name="data_saver_enable_title" msgid="7080620065745260137">"Datu-aurrezlea aktibatu nahi duzu?"</string>
+    <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Bateria-aurreztaileak gai iluna aktibatzen du, eta murriztu edo desaktibatu egiten ditu atzeko planoko jarduerak, zenbait efektu bisual, eta eginbide jakin eta sareko konexio batzuk."</string>
+    <string name="battery_saver_description" msgid="8518809702138617167">"Bateria-aurreztaileak gai iluna aktibatzen du, eta atzeko planoko jarduerak, zenbait efektu bisual, eta eginbide jakin eta sareko konexio batzuk murrizten edo desaktibatzen ditu."</string>
+    <string name="data_saver_description" msgid="4995164271550590517">"Datu-erabilera murrizteko, atzeko planoan datuak bidaltzea eta jasotzea galarazten die datu-aurreztaileak aplikazio batzuei. Erabiltzen ari zaren aplikazioek datuak atzitu ahalko dituzte, baina baliteke maiztasun txikiagoarekin atzitzea. Ondorioz, adibidez, baliteke irudiak ez erakustea haiek sakatu arte."</string>
+    <string name="data_saver_enable_title" msgid="7080620065745260137">"Datu-aurreztailea aktibatu nahi duzu?"</string>
     <string name="data_saver_enable_button" msgid="4399405762586419726">"Aktibatu"</string>
     <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Minutu batez ({formattedTime} arte)}other{# minutuz ({formattedTime} arte)}}"</string>
     <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Minutu batez ({formattedTime} arte)}other{# minutuz ({formattedTime} arte)}}"</string>
@@ -2087,9 +2087,9 @@
     <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Android 12-n, jakinarazpen hobetuek ordeztu dituzte Android-eko jakinarazpen egokituak. Eginbide horrek, iradokitako ekintzak eta erantzunak erakusten, eta zure jakinarazpenak antolatzen ditu.\n\nJakinarazpen hobetuek jakinarazpenen eduki osoa atzi dezakete, informazio pertsonala barne (esaterako, kontaktuen izenak eta mezuak). Halaber, eginbideak jakinarazpenak baztertu, edo haiei erantzun diezaieke; adibidez, telefono-deiei erantzun diezaieke, eta ez molestatzeko modua kontrolatu."</string>
     <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Ohitura moduaren informazio-jakinarazpena"</string>
     <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Baliteke bateria ohi baino lehenago agortzea"</string>
-    <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Bateria-aurrezlea aktibatuta dago bateriaren iraupena luzatzeko"</string>
-    <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Bateria-aurrezlea"</string>
-    <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Desaktibatu egin da bateria-aurrezlea"</string>
+    <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Bateria-aurreztailea aktibatuta dago bateriaren iraupena luzatzeko"</string>
+    <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Bateria-aurreztailea"</string>
+    <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Desaktibatu egin da bateria-aurreztailea"</string>
     <string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Behar adina bateria dauka telefonoak. Jada ez dago eginbiderik murriztuta."</string>
     <string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"Behar adina bateria dauka tabletak. Jada ez dago eginbiderik murriztuta."</string>
     <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"Behar adina bateria dauka gailuak. Jada ez dago eginbiderik murriztuta."</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 247bd29..fc284fe 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"دوربین دردسترس نیست"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"ادامه دادن در تلفن"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"میکروفون دردسترس نیست"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"‏«فروشگاه Play» دردسترس نیست"</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>
@@ -1955,12 +1954,9 @@
     <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>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <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="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>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index a93a185..ab4502f 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kamera ei käytettävissä"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Jatka puhelimella"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofoni ei ole käytettävissä"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Play Kauppa ei käytettävissä"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Android TV:n asetukset eivät ole käytettävissä"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"Tabletin asetukset eivät ole käytettävissä"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Puhelimen asetukset eivät ole käytettävissä"</string>
@@ -1955,12 +1954,9 @@
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Sovellus pyytää lisäsuojausta. Kokeile striimausta Android TV ‑laitteella."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Sovellus pyytää lisäsuojausta. Kokeile striimausta tabletilla."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Sovellus pyytää lisäsuojausta. Kokeile striimausta puhelimella."</string>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"<xliff:g id="DEVICE">%1$s</xliff:g> ei saa pääsyä sovellukseen. Kokeile striimausta Android TV ‑laitteella."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"<xliff:g id="DEVICE">%1$s</xliff:g> ei saa pääsyä sovellukseen. Kokeile striimausta tabletilla."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"<xliff:g id="DEVICE">%1$s</xliff:g> ei saa pääsyä sovellukseen. Kokeile striimausta puhelimella."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Tämä sovellus on suunniteltu vanhemmalle Android-versiolle eikä välttämättä toimi oikein. Kokeile tarkistaa päivitykset tai ottaa yhteyttä kehittäjään."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Tarkista päivitykset"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Sinulle on uusia viestejä"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index a930ecc..5fa8727 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Appareil photo non accessible"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Continuer sur le téléphone"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Microphone non accessible"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Boutique Play Store inaccessible"</string>
     <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>
@@ -1955,12 +1954,9 @@
     <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>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <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="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>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 26a04c7..4ad22af 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Caméra indisponible"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Continuez sur le téléphone"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Micro indisponible"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Play Store indisponible"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Paramètres Android TV indisponibles"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"Paramètres de la tablette indisponibles"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Paramètres du téléphone indisponibles"</string>
@@ -1955,12 +1954,9 @@
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Cette appli demande une sécurité supplémentaire. Essayez plutôt d\'y accéder sur votre appareil Android TV."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Cette appli demande une sécurité supplémentaire. Essayez plutôt d\'y accéder sur votre tablette."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Cette appli demande une sécurité supplémentaire. Essayez plutôt d\'y accéder sur votre téléphone."</string>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"Impossible d\'accéder à ces paramètres sur votre <xliff:g id="DEVICE">%1$s</xliff:g>. Essayez plutôt sur votre appareil Android TV."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"Impossible d\'accéder à ces paramètres sur votre <xliff:g id="DEVICE">%1$s</xliff:g>. Essayez plutôt sur votre tablette."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Impossible d\'accéder à ces paramètres sur votre <xliff:g id="DEVICE">%1$s</xliff:g>. Essayez plutôt sur votre téléphone."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Cette application a été conçue pour une ancienne version d\'Android et risque de ne pas fonctionner correctement. Recherchez des mises à jour ou contactez le développeur."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Rechercher une mise à jour"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Vous avez de nouveaux messages"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 5ac8039..14864ad 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"કૅમેરા ઉપલબ્ધ નથી"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"ફોન પર ચાલુ રાખો"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"માઇક્રોફોન ઉપલબ્ધ નથી"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <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>
@@ -1955,12 +1954,9 @@
     <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>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <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="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>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index f311494..b901c02 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"कैमरा उपलब्ध नहीं है"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"फ़ोन पर जारी रखें"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"माइक्रोफ़ोन उपलब्ध नहीं है"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <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>
@@ -1955,12 +1954,9 @@
     <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>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <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="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>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index cfdddd9..39db7b9 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1945,8 +1945,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kamera nije dostupna"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Nastavite na telefonu"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofon nije dostupan"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Trgovina Play nije dostupna"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Postavke Android TV-a nisu dostupne"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"Postavke tableta nisu dostupne"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Postavke telefona nisu dostupne"</string>
@@ -1956,12 +1955,9 @@
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Ta aplikacija zahtijeva dodatnu sigurnost. Pokušajte joj pristupiti na Android TV uređaju."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Ta aplikacija zahtijeva dodatnu sigurnost. Pokušajte joj pristupiti na tabletu."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Ta aplikacija zahtijeva dodatnu sigurnost. Pokušajte joj pristupiti na telefonu."</string>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"Toj aplikaciji nije moguće pristupiti na vašem uređaju <xliff:g id="DEVICE">%1$s</xliff:g>. Pokušajte joj pristupiti na Android TV uređaju."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"Toj aplikaciji nije moguće pristupiti na vašem uređaju <xliff:g id="DEVICE">%1$s</xliff:g>. Pokušajte joj pristupiti na svojem tabletu."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Toj aplikaciji nije moguće pristupiti na vašem uređaju <xliff:g id="DEVICE">%1$s</xliff:g>. Pokušajte joj pristupiti na svojem telefonu."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ova je aplikacija razvijena za stariju verziju Androida i možda neće funkcionirati pravilno. Potražite ažuriranja ili se obratite razvojnom programeru."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Provjeri ažuriranja"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Imate nove poruke"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 92fcde2..d0baae0 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"A kamera nem áll rendelkezésre"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Folytatás a telefonon"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"A mikrofon nem áll rendelkezésre"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"A Play Áruház nem áll rendelkezésre"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Az Android TV beállításai nem állnak rendelkezésre"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"A táblagép beállításai nem állnak rendelkezésre"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"A telefon beállításai nem állnak rendelkezésre"</string>
@@ -1955,12 +1954,9 @@
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Ez az alkalmazás nagyobb biztonságot igényel. Próbálja újra Android TV-eszközén."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Ez az alkalmazás nagyobb biztonságot igényel. Próbálja újra a táblagépén."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Ez az alkalmazás nagyobb biztonságot igényel. Próbálja újra a telefonján."</string>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"Ehhez nem lehet hozzáférni a következő eszközön: <xliff:g id="DEVICE">%1$s</xliff:g>. Próbálja újra az Android TV-eszközön."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"Ehhez nem lehet hozzáférni a következő eszközön: <xliff:g id="DEVICE">%1$s</xliff:g>. Próbálja újra a táblagépen."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Ehhez nem lehet hozzáférni a következő eszközön: <xliff:g id="DEVICE">%1$s</xliff:g>. Próbálja újra a telefonon."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ez az alkalmazás az Android egyik korábbi verziójához készült, így elképzelhető, hogy nem működik majd megfelelően ezen a rendszeren. Keressen frissítéseket, vagy vegye fel a kapcsolatot a fejlesztővel."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Frissítés keresése"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Új üzenetei érkeztek"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index a64cf9e..e262dbd 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Տեսախցիկն անհասանելի է"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Շարունակեք հեռախոսով"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Խոսափողն անհասանելի է"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Play Խանութը հասանելի չէ"</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>
@@ -1955,12 +1954,9 @@
     <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>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <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="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>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 5c3522b..11bb2b1 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -127,7 +127,7 @@
     <item msgid="468830943567116703">"Untuk menelepon dan mengirim pesan melalui Wi-Fi, tanyalah ke operator Anda terlebih dahulu untuk menyiapkan layanan ini. Kemudian, aktifkan kembali panggilan Wi-Fi dari Setelan. (Kode error: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
   </string-array>
   <string-array name="wfcOperatorErrorNotificationMessages">
-    <item msgid="4795145070505729156">"Terjadi masalah saat mendaftarkan panggilan Wi‑Fi dengan operator Anda: <xliff:g id="CODE">%1$s</xliff:g>"</item>
+    <item msgid="4795145070505729156">"Terjadi error saat mendaftarkan panggilan Wi‑Fi dengan operator Anda: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
     <!-- no translation found for wfcSpnFormat_spn (2982505428519096311) -->
     <skip />
@@ -157,7 +157,7 @@
     <string name="fcComplete" msgid="1080909484660507044">"Kode fitur selesai."</string>
     <string name="fcError" msgid="5325116502080221346">"Masalah sambungan atau kode fitur tidak valid."</string>
     <string name="httpErrorOk" msgid="6206751415788256357">"Oke"</string>
-    <string name="httpError" msgid="3406003584150566720">"Terjadi kesalahan jaringan."</string>
+    <string name="httpError" msgid="3406003584150566720">"Terjadi error jaringan."</string>
     <string name="httpErrorLookup" msgid="3099834738227549349">"Tidak dapat menemukan URL."</string>
     <string name="httpErrorUnsupportedAuthScheme" msgid="3976195595501606787">"Skema autentikasi situs tidak didukung."</string>
     <string name="httpErrorAuth" msgid="469553140922938968">"Tidak dapat mengautentikasi."</string>
@@ -1821,7 +1821,7 @@
     <string name="mediasize_unknown_portrait" msgid="3817016220446495613">"Potret tidak diketahui"</string>
     <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"Lanskap tidak diketahui"</string>
     <string name="write_fail_reason_cancelled" msgid="2344081488493969190">"Dibatalkan"</string>
-    <string name="write_fail_reason_cannot_write" msgid="432118118378451508">"Terjadi kesalahan saat menulis konten"</string>
+    <string name="write_fail_reason_cannot_write" msgid="432118118378451508">"Terjadi error saat menulis konten"</string>
     <string name="reason_unknown" msgid="5599739807581133337">"tak diketahui"</string>
     <string name="reason_service_unavailable" msgid="5288405248063804713">"Layanan cetak tidak diaktifkan"</string>
     <string name="print_service_installed_title" msgid="6134880817336942482">"Layanan <xliff:g id="NAME">%s</xliff:g> telah terpasang"</string>
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kamera tidak tersedia"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Lanjutkan di ponsel"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofon tidak tersedia"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Play Store tidak tersedia"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Setelan Android TV tidak tersedia"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"Setelan tablet tidak tersedia"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Setelan ponsel tidak tersedia"</string>
@@ -1955,12 +1954,9 @@
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Aplikasi ini meminta keamanan tambahan. Coba di perangkat Android TV."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Aplikasi ini meminta keamanan tambahan. Coba di tablet."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Aplikasi ini meminta keamanan tambahan. Coba di ponsel."</string>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"Setelan ini tidak dapat diakses di <xliff:g id="DEVICE">%1$s</xliff:g>. Coba di perangkat Android TV."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"Setelan ini tidak dapat diakses di <xliff:g id="DEVICE">%1$s</xliff:g>. Coba di tablet."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Setelan ini tidak dapat diakses di <xliff:g id="DEVICE">%1$s</xliff:g>. Coba di ponsel."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Aplikasi ini dibuat untuk Android versi lama dan mungkin tidak berfungsi sebagaimana mestinya. Coba periksa apakah ada update, atau hubungi developer."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Periksa apakah ada update"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Ada pesan baru"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 8b1793d..4e384c8 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Myndavél ekki tiltæk"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Halda áfram í símanum"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Hljóðnemi ekki tiltækur"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Play Store er ekki tiltæk"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Android TV stillingar ekki tiltækar"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"Spjaldtölvustillingar ekki tiltækar"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Símastillingar ekki tiltækar"</string>
@@ -1955,12 +1954,9 @@
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Þetta forrit biður um viðbótaröryggi. Prófaðu það í Android TV tækinu í staðinn."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Þetta forrit biður um viðbótaröryggi. Prófaðu það í spjaldtölvunni í staðinn."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Þetta forrit biður um viðbótaröryggi. Prófaðu það í símanum í staðinn."</string>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"Ekki er hægt að opna þetta í <xliff:g id="DEVICE">%1$s</xliff:g>. Prófaðu það í Android TV tækinu í staðinn."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"Ekki er hægt að opna þetta í <xliff:g id="DEVICE">%1$s</xliff:g>. Prófaðu það í spjaldtölvunni í staðinn."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Ekki er hægt að opna þetta í <xliff:g id="DEVICE">%1$s</xliff:g>. Prófaðu það í símanum í staðinn."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Þetta forrit var hannað fyrir eldri útgáfu af Android og ekki er víst að það virki eðlilega. Athugaðu hvort uppfærslur séu í boði eða hafðu samband við þróunaraðilann."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Leita að uppfærslu"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Þú ert með ný skilaboð"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 1e2c276..f313f86 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1944,8 +1944,7 @@
     <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>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Play Store non disponibile"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Impostazioni di Android TV non disponibili"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"Impostazioni del tablet non disponibili"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Impostazioni del telefono non disponibili"</string>
@@ -1955,12 +1954,9 @@
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Questa app richiede maggiore sicurezza. Prova a usare il dispositivo Android TV."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Questa app richiede maggiore sicurezza. Prova a usare il tablet."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Questa app richiede maggiore sicurezza. Prova a usare il telefono."</string>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"Non è possibile accedere a questa impostazione su <xliff:g id="DEVICE">%1$s</xliff:g>. Prova a usare il dispositivo Android TV."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"Non è possibile accedere a questa impostazione su <xliff:g id="DEVICE">%1$s</xliff:g>. Prova a usare il tablet."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Non è possibile accedere a questa impostazione su <xliff:g id="DEVICE">%1$s</xliff:g>. Prova a usare il telefono."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Questa app è stata realizzata per una versione precedente di Android e potrebbe non funzionare correttamente. Prova a verificare la disponibilità di aggiornamenti o contatta lo sviluppatore."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Cerca aggiornamenti"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Hai nuovi messaggi"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 7f62a24..13ae3b7 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"カメラ: 使用不可"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"スマートフォンで続行"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"マイク: 使用不可"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Play ストア利用不可"</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>
@@ -1955,12 +1954,9 @@
     <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>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <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="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>
@@ -2152,7 +2148,7 @@
     <string name="resolver_cant_share_with_personal_apps_explanation" msgid="6349766201904601544">"このコンテンツを個人用アプリと共有することはできません"</string>
     <string name="resolver_cant_access_personal_apps_explanation" msgid="1679399548862724359">"このコンテンツを個人用アプリで開くことはできません"</string>
     <string name="resolver_turn_on_work_apps" msgid="884910835250037247">"仕事用プロファイルが一時停止しています"</string>
-    <string name="resolver_switch_on_work" msgid="463709043650610420">"タップして有効化"</string>
+    <string name="resolver_switch_on_work" msgid="463709043650610420">"タップして ON にする"</string>
     <string name="resolver_no_work_apps_available" msgid="3298291360133337270">"仕事用アプリはありません"</string>
     <string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"個人用アプリはありません"</string>
     <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"個人用プロファイルで <xliff:g id="APP">%s</xliff:g> を開きますか?"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index b810de07..db7baa4 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Камера қолжетімді емес"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Телефоннан жалғастыру"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Микрофон қолжетімді емес"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <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>
@@ -1955,12 +1954,9 @@
     <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>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <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="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>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index cd0828d..458bceb 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"មិនអាចប្រើ​កាមេរ៉ា​បានទេ"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"បន្ត​នៅលើ​ទូរសព្ទ"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"មិនអាចប្រើ​មីក្រូហ្វូនបានទេ"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <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>
@@ -1955,12 +1954,9 @@
     <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>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <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="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>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index c9edf3f..af95039 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"ಕ್ಯಾಮರಾ ಲಭ್ಯವಿಲ್ಲ"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"ಫೋನ್‌ನಲ್ಲಿ ಮುಂದುವರಿಸಿ"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"ಮೈಕ್ರೊಫೋನ್ ಲಭ್ಯವಿಲ್ಲ"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <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>
@@ -1955,12 +1954,9 @@
     <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>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <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="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>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 1e6954d..29e9367 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"카메라를 사용할 수 없음"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"휴대전화에서 진행하기"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"마이크를 사용할 수 없음"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Play 스토어를 사용할 수 없음"</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>
@@ -1955,12 +1954,9 @@
     <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>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <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="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>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 96db982..557e635 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Камера жеткиликсиз"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Телефондон улантуу"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Микрофон жеткиликсиз"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <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>
@@ -1955,12 +1954,9 @@
     <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>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <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="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>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index f91b889..faa6b57 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"ກ້ອງຖ່າຍຮູບບໍ່ສາມາດໃຊ້ໄດ້"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"ສືບຕໍ່ຢູ່ໂທລະສັບ"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"ໄມໂຄຣໂຟນບໍ່ສາມາດໃຊ້ໄດ້"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <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>
@@ -1955,12 +1954,9 @@
     <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>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <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="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>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index e1ba13b..1a11949 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1946,8 +1946,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kamera nepasiekiama"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Tęsti telefone"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofonas nepasiekiamas"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"„Play“ parduotuvė nepasiekiama"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"„Android TV“ nustatymai nepasiekiami"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"Planšetinio kompiuterio nustatymai nepasiekiami"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Telefono nustatymai nepasiekiami"</string>
@@ -1957,12 +1956,9 @@
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Ši programa prašo papildomų saugos funkcijų. Pabandykite naudoti „Android TV“ įrenginį."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Ši programa prašo papildomų saugos funkcijų. Pabandykite naudoti planšetinį kompiuterį."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Ši programa prašo papildomų saugos funkcijų. Pabandykite naudoti telefoną."</string>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"Nepavyksta pasiekti nuotolinio įrenginio iš jūsų „<xliff:g id="DEVICE">%1$s</xliff:g>“. Pabandykite naudoti „Android TV“ įrenginį."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"Nepavyksta pasiekti nuotolinio įrenginio iš jūsų „<xliff:g id="DEVICE">%1$s</xliff:g>“. Pabandykite naudoti planšetinį kompiuterį."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Nepavyksta pasiekti nuotolinio įrenginio iš jūsų „<xliff:g id="DEVICE">%1$s</xliff:g>“. Pabandykite naudoti telefoną."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ši programa sukurta naudoti senesnės versijos sistemoje „Android“ ir gali tinkamai neveikti. Pabandykite patikrinti, ar yra naujinių, arba susisiekite su kūrėju."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Tikrinti, ar yra naujinių"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Turite naujų pranešimų"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 16b0c5b..013e999 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1945,8 +1945,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kamera nav pieejama"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Turpiniet tālrunī"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofons nav pieejams"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Play veikals nav pieejams"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Android TV iestatījumi nav pieejami"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"Planšetdatora iestatījumi nav pieejami"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Tālruņa iestatījumi nav pieejami"</string>
@@ -1956,12 +1955,9 @@
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Šī lietotne pieprasa papildu drošību. Mēģiniet tai piekļūt savā Android TV ierīcē."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Šī lietotne pieprasa papildu drošību. Mēģiniet tai piekļūt savā planšetdatorā."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Šī lietotne pieprasa papildu drošību. Mēģiniet tai piekļūt savā tālrunī."</string>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"Šajā ierīcē (<xliff:g id="DEVICE">%1$s</xliff:g>) nevar piekļūt tālvadībai. Mēģiniet tai piekļūt savā Android TV ierīcē."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"Šajā ierīcē (<xliff:g id="DEVICE">%1$s</xliff:g>) nevar piekļūt tālvadībai. Mēģiniet tai piekļūt savā planšetdatorā."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Šajā ierīcē (<xliff:g id="DEVICE">%1$s</xliff:g>) nevar piekļūt tālvadībai. Mēģiniet tai piekļūt savā tālrunī."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Šī lietotne tika izstrādāta vecākai Android versijai un var nedarboties pareizi. Meklējiet atjauninājumus vai sazinieties ar izstrādātāju."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Meklēt atjauninājumu"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Jums ir jaunas īsziņas."</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 2d911a7..0aeec6d 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Камерата е недостапна"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Продолжете на телефонот"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Микрофонот не е достапен"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <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>
@@ -1955,12 +1954,9 @@
     <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>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <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="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>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index fd49247..1d823fd 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -166,7 +166,7 @@
     <string name="httpErrorIO" msgid="3860318696166314490">"या सर्व्हरशी संवाद प्रस्थापित करू शकलो नाही. नंतर पुन्हा प्रयत्न करा."</string>
     <string name="httpErrorTimeout" msgid="7446272815190334204">"सर्व्हरवरील कनेक्शन टाइमआउट झाले."</string>
     <string name="httpErrorRedirectLoop" msgid="8455757777509512098">"पृष्ठामध्ये बरीच सर्व्हर पुनर्निर्देशने आहेत."</string>
-    <string name="httpErrorUnsupportedScheme" msgid="2664108769858966374">"प्रोटोकॉल समर्थित नाही."</string>
+    <string name="httpErrorUnsupportedScheme" msgid="2664108769858966374">"प्रोटोकॉलला सपोर्ट नाही."</string>
     <string name="httpErrorFailedSslHandshake" msgid="546319061228876290">"सुरक्षित कनेक्शन इंस्टॉल करू शकलो नाही."</string>
     <string name="httpErrorBadUrl" msgid="754447723314832538">"URL अवैध असल्यामुळे पेज उघडू शकलो नाही."</string>
     <string name="httpErrorFile" msgid="3400658466057744084">"फायलीवर प्रवेश करू शकलो नाही."</string>
@@ -1442,7 +1442,7 @@
     <string name="ext_media_status_mounted_ro" msgid="1974809199760086956">"केवळ-वाचनीय"</string>
     <string name="ext_media_status_bad_removal" msgid="508448566481406245">"असुरक्षितपणे काढले"</string>
     <string name="ext_media_status_unmountable" msgid="7043574843541087748">"दूषित झाले"</string>
-    <string name="ext_media_status_unsupported" msgid="5460509911660539317">"समर्थित नसलेले"</string>
+    <string name="ext_media_status_unsupported" msgid="5460509911660539317">"सपोर्ट नसलेले"</string>
     <string name="ext_media_status_ejecting" msgid="7532403368044013797">"बाहेर काढत आहे…"</string>
     <string name="ext_media_status_formatting" msgid="774148701503179906">"फॉर्मेट करत आहे..."</string>
     <string name="ext_media_status_missing" msgid="6520746443048867314">"घातले नाही"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index baa17eb..69d2ddb 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kamera tidak tersedia"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Teruskan pada telefon"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofon tidak tersedia"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Play Store tidak tersedia"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Tetapan Android TV tidak tersedia"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"Tetapan tablet tidak tersedia"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Tetapan telefon tidak tersedia"</string>
@@ -1955,12 +1954,9 @@
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Apl ini meminta keselamatan tambahan. Cuba pada peranti Android TV anda."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Apl ini meminta keselamatan tambahan. Cuba pada tablet anda."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Apl ini meminta keselamatan tambahan. Cuba pada telefon anda."</string>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"Apl ini tidak boleh diakses pada <xliff:g id="DEVICE">%1$s</xliff:g> anda. Cuba pada peranti Android TV anda."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"Apl ini tidak boleh diakses pada <xliff:g id="DEVICE">%1$s</xliff:g> anda. Cuba pada tablet anda."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Apl ini tidak boleh diakses pada <xliff:g id="DEVICE">%1$s</xliff:g> anda. Cuba pada telefon anda."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Apl ini dibina untuk versi Android yang lebih lama dan mungkin tidak berfungsi dengan betul. Cuba semak kemas kini atau hubungi pembangun."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Semak kemaskinian"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Anda mempunyai mesej baharu"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 0696ddd..06688b8 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"ကင်မရာ မရနိုင်ပါ"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"ဖုန်းပေါ်တွင် ရှေ့ဆက်ပါ"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"မိုက်ခရိုဖုန်း မရနိုင်ပါ"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <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">"Tablet ဆက်တင်များ မရနိုင်ပါ"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Phone ဆက်တင်များ မရနိုင်ပါ"</string>
@@ -1955,12 +1954,9 @@
     <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>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <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="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>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index e9660a0..99b6d74 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kameraet er utilgjengelig"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Fortsett på telefonen"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofonen er utilgjengelig"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Play-butikken er utilgjengelig"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Android TV-innstillingene er utilgjengelige"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"Nettbrettinnstillingene er utilgjengelige"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Telefoninnstillingene er utilgjengelige"</string>
@@ -1955,12 +1954,9 @@
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Denne appen ber om ekstra sikkerhet. Prøv på Android TV-enheten din i stedet."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Denne appen ber om ekstra sikkerhet. Prøv på nettbrettet ditt i stedet."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Denne appen ber om ekstra sikkerhet. Prøv på telefonen din i stedet."</string>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"Dette er ikke tilgjengelig på <xliff:g id="DEVICE">%1$s</xliff:g>. Prøv på Android TV-enheten din i stedet."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"Dette er ikke tilgjengelig på <xliff:g id="DEVICE">%1$s</xliff:g>. Prøv på nettbrettet ditt i stedet."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Dette er ikke tilgjengelig på <xliff:g id="DEVICE">%1$s</xliff:g>. Prøv på telefonen din i stedet."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Denne appen er utviklet for en eldre versjon av Android og fungerer kanskje ikke som den skal. Prøv å se etter oppdateringer, eller kontakt utvikleren."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Se etter oppdateringer"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Du har nye meldinger"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 0fbaadb..594807d 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"क्यामेरा उपलब्ध छैन"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"फोनमा जारी राख्नुहोस्"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"माइक्रोफोन उपलब्ध छैन"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Play स्टोर उपलब्ध छैन"</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>
@@ -1955,12 +1954,9 @@
     <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>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <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="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>
diff --git a/core/res/res/values-night/colors.xml b/core/res/res/values-night/colors.xml
index 33c9b95..ffaccd3 100644
--- a/core/res/res/values-night/colors.xml
+++ b/core/res/res/values-night/colors.xml
@@ -37,4 +37,10 @@
     <color name="user_icon_6">#ff4ecde6</color><!-- cyan -->
     <color name="user_icon_7">#fffbbc04</color><!-- yellow -->
     <color name="user_icon_8">#fffa903e</color><!-- orange -->
+
+    <!-- Color for side fps toast dark theme-->
+    <color name="side_fps_toast_background">#2E3132</color>
+    <color name="side_fps_text_color">#EFF1F2</color>
+    <color name="side_fps_button_color">#33B9DB</color>
+
 </resources>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 3541a5d..07eee35 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"କ୍ୟାମେରା ଉପଲବ୍ଧ ନାହିଁ"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"ଫୋନରେ ଜାରି ରଖନ୍ତୁ"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"ମାଇକ୍ରୋଫୋନ ଉପଲବ୍ଧ ନାହିଁ"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <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>
@@ -1955,12 +1954,9 @@
     <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>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <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="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>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 13a5f97..593235e 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"ਕੈਮਰਾ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"ਫ਼ੋਨ \'ਤੇ ਜਾਰੀ ਰੱਖੋ"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਅਣਉਪਲਬਧ ਹੈ"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <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>
@@ -1955,12 +1954,9 @@
     <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>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <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="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>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index e9d6d63..025b0c2 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1946,8 +1946,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Aparat niedostępny"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Kontynuuj na telefonie"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofon niedostępny"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Sklep Play niedostępny"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Ustawienia Androida TV są niedostępne"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"Ustawienia tabletu są niedostępne"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Ustawienia telefonu są niedostępne"</string>
@@ -1957,12 +1956,9 @@
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Ta aplikacja wymaga dodatkowych zabezpieczeń. Użyj urządzenia z Androidem TV."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Ta aplikacja wymaga dodatkowych zabezpieczeń. Użyj tabletu."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Ta aplikacja wymaga dodatkowych zabezpieczeń. Użyj telefonu."</string>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"Nie można z tego skorzystać na urządzeniu <xliff:g id="DEVICE">%1$s</xliff:g>. Użyj urządzenia z Androidem TV."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"Nie można z tego skorzystać na urządzeniu <xliff:g id="DEVICE">%1$s</xliff:g>. Użyj tabletu."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Nie można z tego skorzystać na urządzeniu <xliff:g id="DEVICE">%1$s</xliff:g>. Użyj telefonu."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ta aplikacja jest na starszą wersję Androida i może nie działać prawidłowo. Sprawdź dostępność aktualizacji lub skontaktuj się z programistą."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Sprawdź dostępność aktualizacji"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Masz nowe wiadomości"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index e6c8c81..0dc380b7 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -743,8 +743,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="4068445390318355716">"Permite que um app remova certificados de DRM. Não deve ser necessário para apps comuns."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"vincular a um serviço de mensagens de operadora"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"Permite que o proprietário use a interface de nível superior de um serviço de mensagens de operadora. Não deve ser necessária para apps comuns."</string>
-    <string name="permlab_bindCarrierServices" msgid="2395596978626237474">"vincular a serviços de operadora"</string>
-    <string name="permdesc_bindCarrierServices" msgid="9185614481967262900">"Permite que o proprietário use serviços de operadora. Não deve ser necessário para apps comuns."</string>
+    <string name="permlab_bindCarrierServices" msgid="2395596978626237474">"vincular a serviços da operadora"</string>
+    <string name="permdesc_bindCarrierServices" msgid="9185614481967262900">"Permite que o proprietário use serviços da operadora. Não deve ser necessário para apps comuns."</string>
     <string name="permlab_access_notification_policy" msgid="5524112842876975537">"acessar \"Não perturbe\""</string>
     <string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Permitir que o app leia e grave a configuração \"Não perturbe\"."</string>
     <string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"iniciar uso da permissão para visualização"</string>
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Câmera indisponível"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Continuar no smartphone"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Microfone indisponível"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Play Store indisponível"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Configurações do Android TV indisponíveis"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"Configurações do tablet indisponíveis"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Configurações do smartphone indisponíveis"</string>
@@ -1955,12 +1954,9 @@
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Esse app está solicitando segurança extra. Tente pelo dispositivo Android TV."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Esse app está solicitando segurança extra. Tente pelo tablet."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Esse app está solicitando segurança extra. Tente pelo smartphone."</string>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"Não é possível acessar essa configuração pelo seu <xliff:g id="DEVICE">%1$s</xliff:g>. Tente pelo dispositivo Android TV."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"Não é possível acessar essa configuração pelo seu <xliff:g id="DEVICE">%1$s</xliff:g>. Tente pelo tablet."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Não é possível acessar essa configuração pelo seu <xliff:g id="DEVICE">%1$s</xliff:g>. Tente pelo smartphone."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Este app foi criado para uma versão mais antiga do Android e pode não funcionar corretamente. Tente verificar se há atualizações ou entre em contato com o desenvolvedor."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Procurar atualizações"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Você tem mensagens novas"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index e6c8c81..0dc380b7 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -743,8 +743,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="4068445390318355716">"Permite que um app remova certificados de DRM. Não deve ser necessário para apps comuns."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"vincular a um serviço de mensagens de operadora"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"Permite que o proprietário use a interface de nível superior de um serviço de mensagens de operadora. Não deve ser necessária para apps comuns."</string>
-    <string name="permlab_bindCarrierServices" msgid="2395596978626237474">"vincular a serviços de operadora"</string>
-    <string name="permdesc_bindCarrierServices" msgid="9185614481967262900">"Permite que o proprietário use serviços de operadora. Não deve ser necessário para apps comuns."</string>
+    <string name="permlab_bindCarrierServices" msgid="2395596978626237474">"vincular a serviços da operadora"</string>
+    <string name="permdesc_bindCarrierServices" msgid="9185614481967262900">"Permite que o proprietário use serviços da operadora. Não deve ser necessário para apps comuns."</string>
     <string name="permlab_access_notification_policy" msgid="5524112842876975537">"acessar \"Não perturbe\""</string>
     <string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Permitir que o app leia e grave a configuração \"Não perturbe\"."</string>
     <string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"iniciar uso da permissão para visualização"</string>
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Câmera indisponível"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Continuar no smartphone"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Microfone indisponível"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Play Store indisponível"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Configurações do Android TV indisponíveis"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"Configurações do tablet indisponíveis"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Configurações do smartphone indisponíveis"</string>
@@ -1955,12 +1954,9 @@
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Esse app está solicitando segurança extra. Tente pelo dispositivo Android TV."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Esse app está solicitando segurança extra. Tente pelo tablet."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Esse app está solicitando segurança extra. Tente pelo smartphone."</string>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"Não é possível acessar essa configuração pelo seu <xliff:g id="DEVICE">%1$s</xliff:g>. Tente pelo dispositivo Android TV."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"Não é possível acessar essa configuração pelo seu <xliff:g id="DEVICE">%1$s</xliff:g>. Tente pelo tablet."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Não é possível acessar essa configuração pelo seu <xliff:g id="DEVICE">%1$s</xliff:g>. Tente pelo smartphone."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Este app foi criado para uma versão mais antiga do Android e pode não funcionar corretamente. Tente verificar se há atualizações ou entre em contato com o desenvolvedor."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Procurar atualizações"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Você tem mensagens novas"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 5e69144..ae161b6a 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1945,8 +1945,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Camera video nu este disponibilă"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Continuați pe telefon"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Microfon indisponibil"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Aplicația Magazin Play nu este disponibilă"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Setările pentru Android TV sunt indisponibile"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"Setările pentru tabletă sunt indisponibile"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Setările pentru telefon sunt indisponibile"</string>
@@ -1956,12 +1955,9 @@
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Aplicația necesită securitate suplimentară. Încercați pe dispozitivul Android TV."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Aplicația necesită securitate suplimentară. Încercați pe tabletă."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Aplicația necesită securitate suplimentară. Încercați pe telefon."</string>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <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_app_store" msgid="8456784048558808909">"Căutați actualizări"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Aveți mesaje noi"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 8ce479a..195074c 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1946,8 +1946,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Камера недоступна"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Продолжите на телефоне"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Микрофон недоступен"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Google Play недоступен"</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>
@@ -1957,12 +1956,9 @@
     <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>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <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="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>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 7c8de57..a513aca 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"කැමරාව ලබා ගත නොහැකිය"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"දුරකථනයෙන් දිගටම කර ගෙන යන්න"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"මයික්‍රෆෝනය ලබා ගත නොහැකිය"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <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>
@@ -1955,12 +1954,9 @@
     <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>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <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="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>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index f3c28a8..665dd02 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1946,8 +1946,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kamera nie je k dispozícii"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Pokračujte v telefóne"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofón nie je k dispozícii"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Obchod Play nie je k dispozícii"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Nastavenia zariadenia Android TV nie sú k dispozícii"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"Nastavenia tabletu nie sú k dispozícii"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Nastavenia telefónu nie sú k dispozícii"</string>
@@ -1957,12 +1956,9 @@
     <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>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <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="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>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 759960f..fa4f2a3a1 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1946,8 +1946,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Fotoaparat ni na voljo"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Nadaljevanje v telefonu"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofon ni na voljo"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Trgovina Play ni na voljo"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Nastavitve naprave Android TV niso na voljo"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"Nastavitve tabličnega računalnika niso na voljo"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Nastavitve telefona niso na voljo"</string>
@@ -1957,12 +1956,9 @@
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Ta aplikacija zahteva dodatno varnost. Poskusite z napravo Android TV."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Ta aplikacija zahteva dodatno varnost. Poskusite s tabličnim računalnikom."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Ta aplikacija zahteva dodatno varnost. Poskusite s telefonom."</string>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"V napravi <xliff:g id="DEVICE">%1$s</xliff:g> ni mogoče dostopati do te vsebine. Poskusite z napravo Android TV."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"V napravi <xliff:g id="DEVICE">%1$s</xliff:g> ni mogoče dostopati do te vsebine. Poskusite s tabličnim računalnikom."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"V napravi <xliff:g id="DEVICE">%1$s</xliff:g> ni mogoče dostopati do te vsebine. Poskusite s telefonom."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ta aplikacija je bila zasnovana za starejšo različico Androida in morda ne bo delovala pravilno. Preverite, ali so na voljo posodobitve, ali pa se obrnite na razvijalca."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Preveri, ali je na voljo posodobitev"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Imate nova sporočila."</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index b8d6d6b..744d7be 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kamera nuk ofrohet"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Vazhdo në telefon"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofoni nuk ofrohet"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"\"Dyqani i Play\" nuk ofrohet"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Cilësimet e Android TV nuk ofrohen"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"Cilësimet e tabletit nuk ofrohen"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Cilësimet e telefonit nuk ofrohen"</string>
@@ -1955,12 +1954,9 @@
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Ky aplikacion po kërkon siguri shtesë. Provoje në pajisjen Android TV më mirë."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Ky aplikacion po kërkon siguri shtesë. Provoje në tablet më mirë."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Ky aplikacion po kërkon siguri shtesë. Provoje në telefon më mirë."</string>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"Qasja është e pamundur në <xliff:g id="DEVICE">%1$s</xliff:g>. Provoje në pajisjen Android TV më mirë."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"Qasja është e pamundur në <xliff:g id="DEVICE">%1$s</xliff:g>. Provoje në tablet më mirë."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Qasja është e pamundur në <xliff:g id="DEVICE">%1$s</xliff:g>. Provoje në telefon më mirë."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ky aplikacion është ndërtuar për një version më të vjetër të Android dhe mund të mos funksionojë mirë. Provo të kontrollosh për përditësime ose kontakto me zhvilluesin."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Kontrollo për përditësim"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Ke mesazhe të reja"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index fe27b01..faea736 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1945,8 +1945,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Камера није доступна"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Наставите на телефону"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Микрофон је недоступан"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Play продавница није доступна"</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>
@@ -1956,12 +1955,9 @@
     <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>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <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="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>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 49c9007..f899929 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kameran är inte tillgänglig"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Fortsätt på telefonen"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofonen är inte tillgänglig"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Play Butik är inte tillgängligt"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Inställningarna för Android TV är inte tillgängliga"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"Surfplattans inställningar är inte tillgängliga"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Telefonens inställningar är inte tillgängliga"</string>
@@ -1955,12 +1954,9 @@
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Appen begär ytterligare säkerhet. Testa med Android TV-enheten i stället."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Appen begär ytterligare säkerhet. Testa med surfplattan i stället."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Appen begär ytterligare säkerhet. Testa med telefonen i stället."</string>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"Det går inte att streama detta till <xliff:g id="DEVICE">%1$s</xliff:g>. Testa med Android TV-enheten i stället."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"Det går inte att streama detta till <xliff:g id="DEVICE">%1$s</xliff:g>. Testa med surfplattan i stället."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Det går inte att streama detta till <xliff:g id="DEVICE">%1$s</xliff:g>. Testa med telefonen i stället."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Appen har utvecklats för en äldre version av Android och kanske inte fungerar som den ska. Testa att söka efter uppdateringar eller kontakta utvecklaren."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Sök efter uppdateringar"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Du har nya meddelanden"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index f10ac5b..3f57bd1 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kamera haipatikani"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Endelea kwenye simu"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Maikrofoni haipatikani"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Huduma ya Duka la Google Play haipatikani"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Mipangilio ya Android TV haipatikani"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"Mipangilio ya kompyuta kibao haipatikani"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Mipangilio ya simu haipatikani"</string>
@@ -1955,12 +1954,9 @@
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Programu hii inaomba usalama wa ziada. Badala yake jaribu kwenye kifaa chako cha Android TV."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Programu hii inaomba usalama wa ziada. Badala yake jaribu kwenye kompyuta yako kibao."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Programu hii inaomba usalama wa ziada. Badala yake jaribu kwenye simu yako."</string>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"Huwezi kufikia mipangilio hii kwenye <xliff:g id="DEVICE">%1$s</xliff:g> yako. Badala yake jaribu kwenye kifaa chako cha Android TV."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"Huwezi kufikia mipangilio hii kwenye <xliff:g id="DEVICE">%1$s</xliff:g> yako. Badala yake jaribu kwenye kompyuta yako kibao."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Huwezi kufikia mipangilio hii kwenye <xliff:g id="DEVICE">%1$s</xliff:g> yako. Badala yake jaribu kwenye simu yako."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Programu hii iliundwa kwa ajili ya toleo la zamani la Android na huenda isifanye kazi vizuri. Jaribu kuangalia masasisho au uwasiliane na msanidi programu."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Angalia masasisho"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Una ujumbe mpya"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 70cb7ee..42d4bfa 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"கேமராவைப் பயன்படுத்த முடியாது"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"மொபைலில் தொடருங்கள்"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"மைக்ரோஃபோனைப் பயன்படுத்த முடியாது"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <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>
@@ -1955,12 +1954,9 @@
     <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>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <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="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>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index a9b0f44..8207c50 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1705,7 +1705,7 @@
     <string name="color_inversion_feature_name" msgid="326050048927789012">"కలర్ మార్పిడి"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"కలర్ కరెక్షన్"</string>
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"వన్-హ్యాండెడ్ మోడ్"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"కాంతిని మరింత డిమ్ చేయడం"</string>
+    <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ఎక్స్‌ట్రా డిమ్"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"వాల్యూమ్ కీలు నొక్కి ఉంచబడ్డాయి. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ఆన్ చేయబడింది"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"వాల్యూమ్ కీలు నొక్కి ఉంచబడ్డాయి. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ఆఫ్ చేయబడింది"</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>ని ఉపయోగించడానికి వాల్యూమ్ కీలు రెండింటినీ 3 సెకన్లు నొక్కి ఉంచండి"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 26b0b98..f54f4ec 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"กล้องไม่พร้อมใช้งาน"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"ดำเนินการต่อบนโทรศัพท์"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"ไมโครโฟนไม่พร้อมใช้งาน"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <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>
@@ -1955,12 +1954,9 @@
     <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>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <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="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>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 47f433c..9a77b4b 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Hindi available ang camera"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Magpatuloy sa telepono"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Hindi available ang mikropono"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Hindi available ang Play Store"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Hindi available ang mga setting ng Android TV"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"Hindi available ang mga setting ng tablet"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Hindi available ang mga setting ng telepono"</string>
@@ -1955,12 +1954,9 @@
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Humihiling ng karagdagang seguridad ang app na ito. Subukan na lang sa iyong Android TV device."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Humihiling ng karagdagang seguridad ang app na ito. Subukan na lang sa iyong tablet."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Humihiling ng karagdagang seguridad ang app na ito. Subukan na lang sa iyong telepono."</string>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"Hindi ito maa-access sa iyong <xliff:g id="DEVICE">%1$s</xliff:g>. Subukan na lang sa iyong Android TV device."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"Hindi ito maa-access sa iyong <xliff:g id="DEVICE">%1$s</xliff:g>. Subukan na lang sa iyong tablet."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Hindi ito maa-access sa iyong <xliff:g id="DEVICE">%1$s</xliff:g>. Subukan na lang sa iyong telepono."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ang app na ito ay ginawa para sa mas lumang bersyon ng Android at maaaring hindi gumana nang maayos. Subukang tingnan kung may mga update, o makipag-ugnayan sa developer."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Tingnan kung may update"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Mayroon kang mga bagong mensahe"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index de4499b..d27cb60 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kamera kullanılamıyor"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"İşleme telefonda devam edin"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofon kullanılamıyor"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Play Store kullanılamıyor"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Android TV ayarları kullanılamıyor"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"Tablet ayarları kullanılamıyor"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Telefon ayarları kullanılamıyor"</string>
@@ -1955,12 +1954,9 @@
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Bu uygulama daha fazla güvenlik istiyor. Bunun yerine Android TV cihazınızı kullanmayı deneyin."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Bu uygulama daha fazla güvenlik istiyor. Bunun yerine tabletinizi kullanmayı deneyin."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Bu uygulama daha fazla güvenlik istiyor. Bunun yerine telefonunuzu kullanmayı deneyin."</string>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"Bu uygulamaya <xliff:g id="DEVICE">%1$s</xliff:g> cihazınızdan erişilemiyor. Bunun yerine Android TV cihazınızı kullanmayı deneyin."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"Bu uygulamaya <xliff:g id="DEVICE">%1$s</xliff:g> cihazınızdan erişilemiyor. Bunun yerine tabletinizi kullanmayı deneyin."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Bu uygulamaya <xliff:g id="DEVICE">%1$s</xliff:g> cihazınızdan erişilemiyor. Bunun yerine telefonunuzu kullanmayı deneyin."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Bu uygulama Android\'in daha eski bir sürümü için oluşturuldu ve düzgün çalışmayabilir. Güncellemeleri kontrol etmeyi deneyin veya geliştiriciyle iletişime geçin."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Güncellemeleri denetle"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Yeni mesajlarınız var"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 9817167..9ea6633 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1946,8 +1946,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Камера недоступна"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Продовжте на телефоні"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Мікрофон недоступний"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Додаток Play Маркет недоступний"</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>
@@ -1957,12 +1956,9 @@
     <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>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <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="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>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index e3aaa68..e344ea5 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kamera ishlamayapti"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Telefonda davom ettirish"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofon ishlamayapti"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Play Market ishlamayapti"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Android TV sozlamalari ishlamayapti"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"Planshet sozlamalari ishlamayapti"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Telefon sozlamalari ishlamayapti"</string>
@@ -1955,12 +1954,9 @@
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Bu ilova qoʻshimcha himoyani talab qilmoqda. Android TV qurilmasi orqali urinib koʻring."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Bu ilova qoʻshimcha himoyani talab qilmoqda. Planshet orqali urinib koʻring."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Bu ilova qoʻshimcha himoyani talab qilmoqda. Telefon orqali urininb koʻring."</string>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"Bu <xliff:g id="DEVICE">%1$s</xliff:g> qurilmangizda ochilmaydi. Android TV qurilmasi orqali urinib koʻring."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"Bu <xliff:g id="DEVICE">%1$s</xliff:g> qurilmangizda ochilmaydi. Planshet orqali urinib koʻring."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Bu <xliff:g id="DEVICE">%1$s</xliff:g> qurilmangizda ochilmaydi. Telefon orqali urininb koʻring."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Bu ilova eskiroq Android versiyalariga chiqarilgan va xato ishlashi mumkin. Yangilanishlarini tekshiring yoki dasturchi bilan bog‘laning."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Yangilanish borligini tekshirish"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Sizga yangi SMS keldi"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 9db9285..86ca67b 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Không dùng được máy ảnh"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Tiếp tục trên điện thoại"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Không dùng được micrô"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Cửa hàng Play không có sẵn"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Không dùng được các chế độ cài đặt của Android TV"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"Không dùng được các chế độ cài đặt của máy tính bảng"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Không dùng được các chế độ cài đặt của điện thoại"</string>
@@ -1955,12 +1954,9 @@
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Ứng dụng này đang yêu cầu tính năng bảo mật bổ sung. Hãy thử trên thiết bị Android TV."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Ứng dụng này đang yêu cầu tính năng bảo mật bổ sung. Hãy thử trên máy tính bảng."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Ứng dụng này đang yêu cầu tính năng bảo mật bổ sung. Hãy thử trên điện thoại."</string>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"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 thiết bị Android TV."</string>
+    <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="new_sms_notification_title" msgid="6528758221319927107">"Bạn có tin nhắn mới"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index e715c73..b8c8198 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"无法使用摄像头"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"继续在手机上操作"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"无法使用麦克风"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"无法使用 Play 商店"</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>
@@ -1955,12 +1954,9 @@
     <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>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <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="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>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 50c06b7..1727a46 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -647,7 +647,7 @@
     <string name="face_acquired_poor_gaze" msgid="4427153558773628020">"請以更直視的角度看著裝置。"</string>
     <string name="face_acquired_not_detected" msgid="1057966913397548150">"看不到面孔,請將手機放在視線水平。"</string>
     <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"裝置不夠穩定。請拿穩手機。"</string>
-    <string name="face_acquired_recalibrate" msgid="8724013080976469746">"請重新註冊臉孔。"</string>
+    <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>
@@ -664,27 +664,27 @@
     <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"偵測到面部遮蓋物。您必須展示整個面孔。"</string>
   <string-array name="face_acquired_vendor">
   </string-array>
-    <string name="face_error_hw_not_available" msgid="5085202213036026288">"無法驗證臉孔,硬件無法使用。"</string>
+    <string name="face_error_hw_not_available" msgid="5085202213036026288">"無法驗證面孔,硬件無法使用。"</string>
     <string name="face_error_timeout" msgid="2598544068593889762">"請再次嘗試「面孔解鎖」"</string>
     <string name="face_error_no_space" msgid="5649264057026021723">"無法儲存新的臉容資料,請先刪除舊資料。"</string>
-    <string name="face_error_canceled" msgid="2164434737103802131">"臉孔操作已取消。"</string>
+    <string name="face_error_canceled" msgid="2164434737103802131">"面孔操作已取消。"</string>
     <string name="face_error_user_canceled" msgid="5766472033202928373">"使用者已取消「面孔解鎖」"</string>
     <string name="face_error_lockout" msgid="7864408714994529437">"嘗試次數過多,請稍後再試。"</string>
     <string name="face_error_lockout_permanent" msgid="3277134834042995260">"嘗試次數過多,因此系統已停用「面孔解鎖」。"</string>
     <string name="face_error_lockout_screen_lock" msgid="5062609811636860928">"嘗試次數過多,請改為解除螢幕鎖定來驗證身分。"</string>
-    <string name="face_error_unable_to_process" msgid="5723292697366130070">"無法驗證臉孔。請再試一次。"</string>
+    <string name="face_error_unable_to_process" msgid="5723292697366130070">"無法驗證面孔。請再試一次。"</string>
     <string name="face_error_not_enrolled" msgid="1134739108536328412">"您尚未設定「面孔解鎖」"</string>
     <string name="face_error_hw_not_present" msgid="7940978724978763011">"此裝置不支援「面孔解鎖」"</string>
     <string name="face_error_security_update_required" msgid="5076017208528750161">"感應器已暫時停用。"</string>
-    <string name="face_name_template" msgid="3877037340223318119">"臉孔 <xliff:g id="FACEID">%d</xliff:g>"</string>
+    <string name="face_name_template" msgid="3877037340223318119">"面孔 <xliff:g id="FACEID">%d</xliff:g>"</string>
     <string name="face_app_setting_name" msgid="5854024256907828015">"使用「面孔解鎖」"</string>
-    <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"使用臉孔或螢幕鎖定"</string>
+    <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"使用面孔或螢幕鎖定"</string>
     <string name="face_dialog_default_subtitle" msgid="6620492813371195429">"如要繼續操作,請使用您的面孔驗證身分"</string>
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"請使用面孔解鎖或螢幕鎖定功能驗證身分,才能繼續操作"</string>
   <string-array name="face_error_vendor">
   </string-array>
     <string name="face_error_vendor_unknown" msgid="7387005932083302070">"發生錯誤,請再試一次。"</string>
-    <string name="face_icon_content_description" msgid="465030547475916280">"臉孔圖示"</string>
+    <string name="face_icon_content_description" msgid="465030547475916280">"面孔圖示"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"讀取同步處理設定"</string>
     <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"允許應用程式讀取帳戶的同步設定,例如確定「通訊錄」應用程式是否和某個帳戶保持同步。"</string>
     <string name="permlab_writeSyncSettings" msgid="6583154300780427399">"開啟和關閉同步功能"</string>
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"無法使用相機"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"請繼續透過手機操作"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"無法使用麥克風"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"無法使用「Play 商店」"</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>
@@ -1955,12 +1954,9 @@
     <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>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <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="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>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 0c57cf3..424ef62 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"無法使用相機"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"請繼續在手機上操作"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"無法使用麥克風"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"無法存取 Play 商店"</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>
@@ -1955,12 +1954,9 @@
     <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>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <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="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>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 97a3fa0..6ce71c0 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1944,8 +1944,7 @@
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Ikhamera ayitholakali"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Qhubeka kufoni"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Imakrofoni ayitholakali"</string>
-    <!-- no translation found for app_streaming_blocked_title_for_playstore_dialog (8149823099822897538) -->
-    <skip />
+    <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"I-Google Play ayitholakali"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Amasethingi e-Android TV awatholakali"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"Amasethingi ethebulethi awatholakali"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Amasethingi efoni awatholakali"</string>
@@ -1955,12 +1954,9 @@
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Le app icela ukuvikeleka okwengeziwe. Zama kudivayisi yakho ye-Android TV kunalokho."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Le app icela ukuvikeleka okwengeziwe. Zama kuthebhulethi yakho kunalokho."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Le app icela ukuvikeleka okwengeziwe. Zama efonini yakho kunalokho."</string>
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (820334666354451145) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (3286849551133045896) -->
-    <skip />
-    <!-- no translation found for app_streaming_blocked_message_for_settings_dialog (6264287556598916295) -->
-    <skip />
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"Lokhu akukwazi ukufinyelelwa ku-<xliff:g id="DEVICE">%1$s</xliff:g> yakho. Zama kudivayisi yakho ye-Android TV kunalokho."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"Lokhu akukwazi ukufinyelelwa ku-<xliff:g id="DEVICE">%1$s</xliff:g> yakho. Zama kuthebulethi yakho kunalokho."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Lokhu akukwazi ukufinyelelwa ku-<xliff:g id="DEVICE">%1$s</xliff:g> yakho. Zama efonini yakho kunalokho."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Lolu hlelo lokusebenza belakhelwe inguqulo endala ye-Android futhi kungenzeka lungasebenzi kahle. Zama ukuhlolela izibuyekezo, noma uxhumane nonjiniyela."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Hlola izibuyekezo"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Unemilayezo emisha"</string>
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index b515abc..d5875f5 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -211,9 +211,6 @@
     <color name="Red_700">#ffc53929</color>
     <color name="Red_800">#ffb93221</color>
 
-    <!-- Status bar color for semi transparent mode. -->
-    <color name="system_bar_background_semi_transparent">#66000000</color> <!-- 40% black -->
-
     <color name="resize_shadow_start_color">#2a000000</color>
     <color name="resize_shadow_end_color">#00000000</color>
 
@@ -450,4 +447,10 @@
     <!-- Color of camera light when camera is in use -->
     <color name="camera_privacy_light_day">#FFFFFF</color>
     <color name="camera_privacy_light_night">#FFFFFF</color>
+
+    <!-- Color for side fps toast light theme -->
+    <color name="side_fps_toast_background">#F7F9FA</color>
+    <color name="side_fps_text_color">#191C1D</color>
+    <color name="side_fps_button_color">#00677E</color>
+
 </resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index d13bc87..31ea98cc 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2047,6 +2047,9 @@
          on grouped devices. -->
     <bool name="config_volumeAdjustmentForRemoteGroupSessions">true</bool>
 
+    <!-- Flag indicating current media Output Switcher version. -->
+    <integer name="config_mediaOutputSwitchDialogVersion">1</integer>
+
     <!-- Flag indicating that an outbound call must have a call capable phone account
          that has declared it can process the call's handle. -->
     <bool name="config_requireCallCapableAccountForHandle">false</bool>
@@ -3519,9 +3522,9 @@
          (for side fingerprint) -->
     <integer name="config_sidefpsPostAuthDowntime">400</integer>
 
-    <!-- The time (in millis) that a finger tap will wait for a power button
-         before dismissing the power dialog during enrollment(for side fingerprint) -->
-    <integer name="config_sidefpsEnrollPowerPressWindow">300</integer>
+    <!-- The time (in millis) the clickable toast dialog will last until
+         automatically dismissing. This is currently used in SideFpsEventHandler -->
+    <integer name="config_sideFpsToastTimeout">3000</integer>
 
     <!-- This config is used to force VoiceInteractionService to start on certain low ram devices.
          It declares the package name of VoiceInteractionService that should be started. -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a3b05b5..e3b7100 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3568,21 +3568,17 @@
     <!-- [CHAR LIMIT=NONE] Message to show in upgrading dialog when the bulk of the upgrade work is done. -->
     <string name="android_upgrading_complete">Finishing boot.</string>
 
-    <!-- [CHAR LIMIT=40] Title of dialog shown to confirm device going to sleep if the power button
-    is pressed during fingerprint enrollment. -->
-    <string name="fp_power_button_enrollment_title">Continue setup?</string>
-
     <!-- [CHAR LIMIT=NONE] Message of dialog shown to confirm device going to sleep if the power
     button is pressed during fingerprint enrollment. -->
     <string name="fp_power_button_enrollment_message">You pressed the power button — this usually turns off the screen.\n\nTry tapping lightly while setting up your fingerprint.</string>
 
+    <!-- [CHAR LIMIT=40] Title of dialog shown to confirm device going to sleep if the power button
+    is pressed during fingerprint enrollment. -->
+    <string name="fp_power_button_enrollment_title">Tap to turn off screen</string>
+
     <!-- [CHAR LIMIT=20] Positive button of dialog shown to confirm device going to sleep if the
     power button is pressed during fingerprint enrollment. -->
-    <string name="fp_power_button_enrollment_positive_button">Turn off screen</string>
-
-    <!-- [CHAR LIMIT=20] Negative button of dialog shown to confirm device going to sleep if the
-    power button is pressed during fingerprint enrollment. -->
-    <string name="fp_power_button_enrollment_negative_button">Continue setup</string>
+    <string name="fp_power_button_enrollment_button_text">Turn off screen</string>
 
     <!-- [CHAR LIMIT=40] Title of dialog shown to confirm device going to sleep if the power button
     is pressed during biometric prompt when a side fingerprint sensor is present. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index d7484c7..d03550c 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1853,8 +1853,7 @@
   <java-symbol type="string" name="fp_power_button_bp_negative_button" />
   <java-symbol type="string" name="fp_power_button_enrollment_title" />
   <java-symbol type="string" name="fp_power_button_enrollment_message" />
-  <java-symbol type="string" name="fp_power_button_enrollment_positive_button" />
-  <java-symbol type="string" name="fp_power_button_enrollment_negative_button" />
+  <java-symbol type="string" name="fp_power_button_enrollment_button_text" />
   <java-symbol type="string" name="global_actions" />
   <java-symbol type="string" name="global_action_power_off" />
   <java-symbol type="string" name="global_action_power_options" />
@@ -2631,7 +2630,11 @@
   <java-symbol type="integer" name="config_sidefpsBpPowerPressWindow"/>
   <java-symbol type="integer" name="config_sidefpsKeyguardPowerPressWindow"/>
   <java-symbol type="integer" name="config_sidefpsPostAuthDowntime"/>
-  <java-symbol type="integer" name="config_sidefpsEnrollPowerPressWindow"/>
+  <java-symbol type="integer" name="config_sideFpsToastTimeout"/>
+
+  <!-- Clickable toast used during sidefps enrollment -->
+  <java-symbol type="layout" name="side_fps_toast" />
+  <java-symbol type="id" name="turn_off_screen" />
 
   <!-- Face authentication messages -->
   <java-symbol type="string" name="face_recalibrate_notification_name" />
@@ -4706,6 +4709,8 @@
 
   <java-symbol type="bool" name="config_volumeAdjustmentForRemoteGroupSessions" />
 
+  <java-symbol type="integer" name="config_mediaOutputSwitchDialogVersion" />
+
   <!-- List of shared library packages that should be loaded by the classloader after the
        code and resources provided by applications. -->
   <java-symbol type="array" name="config_sharedLibrariesLoadedAfterApp" />
diff --git a/core/tests/coretests/src/android/view/WindowParamsTest.java b/core/tests/coretests/src/android/view/WindowParamsTest.java
new file mode 100644
index 0000000..49d4872
--- /dev/null
+++ b/core/tests/coretests/src/android/view/WindowParamsTest.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.Parcel;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+
+@Presubmit
+@SmallTest
+public class WindowParamsTest {
+
+    @Test
+    public void testParamsForRotation() {
+        final WindowManager.LayoutParams paramsA = new WindowManager.LayoutParams();
+        initParamsForRotation(paramsA);
+        final Parcel parcel = Parcel.obtain();
+        paramsA.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+
+        final WindowManager.LayoutParams paramsB = new WindowManager.LayoutParams(parcel);
+        assertEquals(0, paramsA.copyFrom(paramsB));
+
+        for (int i = 1; i <= 12; i++) {
+            initParamsForRotation(paramsA);
+            changeField(i, paramsA.paramsForRotation[0]);
+            assertEquals("Change not found for case " + i,
+                    WindowManager.LayoutParams.LAYOUT_CHANGED, paramsA.copyFrom(paramsB));
+        }
+
+        parcel.recycle();
+    }
+
+    private static void initParamsForRotation(WindowManager.LayoutParams params) {
+        params.paramsForRotation = new WindowManager.LayoutParams[4];
+        for (int i = 0; i < 4; i++) {
+            params.paramsForRotation[i] = new WindowManager.LayoutParams();
+        }
+    }
+
+    private static void changeField(int fieldCase, WindowManager.LayoutParams params) {
+        switch (fieldCase) {
+            case 1:
+                params.width++;
+                break;
+            case 2:
+                params.height++;
+                break;
+            case 3:
+                params.x++;
+                break;
+            case 4:
+                params.y++;
+                break;
+            case 5:
+                params.horizontalMargin++;
+                break;
+            case 6:
+                params.verticalMargin++;
+                break;
+            case 7:
+                params.layoutInDisplayCutoutMode++;
+                break;
+            case 8:
+                params.gravity++;
+                break;
+            case 9:
+                params.providedInsets = new InsetsFrameProvider[0];
+                break;
+            case 10:
+                params.setFitInsetsTypes(0);
+                break;
+            case 11:
+                params.setFitInsetsSides(0);
+                break;
+            case 12:
+                params.setFitInsetsIgnoringVisibility(!params.isFitInsetsIgnoringVisibility());
+                break;
+        }
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/widget/LocalImageResolverTest.java b/core/tests/coretests/src/com/android/internal/widget/LocalImageResolverTest.java
index c63d18b..0cee526 100644
--- a/core/tests/coretests/src/com/android/internal/widget/LocalImageResolverTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/LocalImageResolverTest.java
@@ -270,4 +270,13 @@
         assertThat(bd.getBitmap().getHeight()).isEqualTo(originalHeight);
 
     }
+
+    @Test
+    public void resolveImage_iconWithOtherPackageResource_usesPackageContextDefinition()
+            throws IOException {
+        Icon icon = Icon.createWithResource("this_is_invalid", R.drawable.test32x24);
+        Drawable d = LocalImageResolver.resolveImage(icon, mContext);
+        // This drawable must not be loaded - if it was, the code ignored the package specification.
+        assertThat(d).isNull();
+    }
 }
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index f9bfd58..e8873cd 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -1105,6 +1105,12 @@
       "group": "WM_DEBUG_TASKS",
       "at": "com\/android\/server\/wm\/RootWindowContainer.java"
     },
+    "-1018968224": {
+      "message": "Recorded task is removed, so stop recording on display %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
     "-1016578046": {
       "message": "Moving to %s Relaunching %s callers=%s",
       "level": "INFO",
@@ -2251,6 +2257,12 @@
       "group": "WM_DEBUG_FOCUS",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "96494268": {
+      "message": "Stop MediaProjection on virtual display %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
     "100936473": {
       "message": "Wallpaper animation!",
       "level": "VERBOSE",
diff --git a/ktfmt_includes.txt b/ktfmt_includes.txt
new file mode 100644
index 0000000..96da8c9
--- /dev/null
+++ b/ktfmt_includes.txt
@@ -0,0 +1,9 @@
+packages/SystemUI/compose/
+packages/SystemUI/screenshot/
+packages/SystemUI/src/com/android/systemui/people/data
+packages/SystemUI/src/com/android/systemui/people/ui
+packages/SystemUI/src/com/android/systemui/keyguard/data
+packages/SystemUI/src/com/android/systemui/keyguard/dagger
+packages/SystemUI/src/com/android/systemui/keyguard/domain
+packages/SystemUI/src/com/android/systemui/keyguard/shared
+packages/SystemUI/src/com/android/systemui/keyguard/ui
\ No newline at end of file
diff --git a/libs/WindowManager/Jetpack/window-extensions-release.aar b/libs/WindowManager/Jetpack/window-extensions-release.aar
index f54ab08..918e514 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/res/drawable/decor_minimize_button_dark.xml b/libs/WindowManager/Shell/res/drawable/decor_minimize_button_dark.xml
new file mode 100644
index 0000000..0bcaa53
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/decor_minimize_button_dark.xml
@@ -0,0 +1,24 @@
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24"
+        android:tint="?attr/colorControlNormal">
+    <path
+        android:fillColor="@android:color/white" android:pathData="M6,21V19H18V21Z"/>
+</vector>
diff --git a/libs/WindowManager/Shell/res/layout/caption_window_decoration.xml b/libs/WindowManager/Shell/res/layout/caption_window_decoration.xml
index a112f19..d183e42 100644
--- a/libs/WindowManager/Shell/res/layout/caption_window_decoration.xml
+++ b/libs/WindowManager/Shell/res/layout/caption_window_decoration.xml
@@ -22,6 +22,17 @@
     android:gravity="end"
     android:background="@drawable/decor_caption_title">
     <Button
+        android:id="@+id/minimize_window"
+        android:visibility="gone"
+        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"/>
+    <Button
         android:id="@+id/maximize_window"
         android:layout_width="32dp"
         android:layout_height="32dp"
@@ -42,4 +53,3 @@
         android:background="@drawable/decor_close_button_dark"
         android:duplicateParentState="true"/>
 </com.android.wm.shell.windowdecor.WindowDecorLinearLayout>
-
diff --git a/libs/WindowManager/Shell/res/values-es/strings_tv.xml b/libs/WindowManager/Shell/res/values-es/strings_tv.xml
index 7993e03..75db421 100644
--- a/libs/WindowManager/Shell/res/values-es/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-es/strings_tv.xml
@@ -23,7 +23,7 @@
     <string name="pip_fullscreen" msgid="7278047353591302554">"Pantalla completa"</string>
     <string name="pip_move" msgid="158770205886688553">"Mover"</string>
     <string name="pip_expand" msgid="1051966011679297308">"Mostrar"</string>
-    <string name="pip_collapse" msgid="3903295106641385962">"Ocultar"</string>
+    <string name="pip_collapse" msgid="3903295106641385962">"Contraer"</string>
     <string name="pip_edu_text" msgid="3672999496647508701">" Pulsa dos veces "<annotation icon="home_icon">"INICIO"</annotation>" para ver los controles"</string>
     <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menú de imagen en imagen."</string>
     <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Mover hacia la izquierda"</string>
diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml
index 68a08513..96778a9 100644
--- a/libs/WindowManager/Shell/res/values/strings.xml
+++ b/libs/WindowManager/Shell/res/values/strings.xml
@@ -192,6 +192,8 @@
     <!-- Freeform window caption strings -->
     <!-- Accessibility text for the maximize window button [CHAR LIMIT=NONE] -->
     <string name="maximize_button_text">Maximize</string>
+     <!-- Accessibility text for the minimize window button [CHAR LIMIT=NONE] -->
+     <string name="minimize_button_text">Minimize</string>
     <!-- Accessibility text for the close window button [CHAR LIMIT=NONE] -->
     <string name="close_button_text">Close</string>
 </resources>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index 5cba3b4..6ae0f9b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -55,6 +55,7 @@
 import com.android.wm.shell.compatui.CompatUIController;
 import com.android.wm.shell.recents.RecentTasksController;
 import com.android.wm.shell.startingsurface.StartingWindowController;
+import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.unfold.UnfoldAnimationController;
 
@@ -72,6 +73,7 @@
  */
 public class ShellTaskOrganizer extends TaskOrganizer implements
         CompatUIController.CompatUICallback {
+    private static final String TAG = "ShellTaskOrganizer";
 
     // Intentionally using negative numbers here so the positive numbers can be used
     // for task id specific listeners that will be added later.
@@ -90,8 +92,6 @@
     })
     public @interface TaskListenerType {}
 
-    private static final String TAG = "ShellTaskOrganizer";
-
     /**
      * Callbacks for when the tasks change in the system.
      */
@@ -177,6 +177,9 @@
     @Nullable
     private final CompatUIController mCompatUI;
 
+    @NonNull
+    private final ShellCommandHandler mShellCommandHandler;
+
     @Nullable
     private final Optional<RecentTasksController> mRecentTasks;
 
@@ -187,29 +190,33 @@
     private RunningTaskInfo mLastFocusedTaskInfo;
 
     public ShellTaskOrganizer(ShellExecutor mainExecutor) {
-        this(null /* shellInit */, null /* taskOrganizerController */, null /* compatUI */,
+        this(null /* shellInit */, null /* shellCommandHandler */,
+                null /* taskOrganizerController */, null /* compatUI */,
                 Optional.empty() /* unfoldAnimationController */,
                 Optional.empty() /* recentTasksController */,
                 mainExecutor);
     }
 
     public ShellTaskOrganizer(ShellInit shellInit,
+            ShellCommandHandler shellCommandHandler,
             @Nullable CompatUIController compatUI,
             Optional<UnfoldAnimationController> unfoldAnimationController,
             Optional<RecentTasksController> recentTasks,
             ShellExecutor mainExecutor) {
-        this(shellInit, null /* taskOrganizerController */, compatUI,
+        this(shellInit, shellCommandHandler, null /* taskOrganizerController */, compatUI,
                 unfoldAnimationController, recentTasks, mainExecutor);
     }
 
     @VisibleForTesting
     protected ShellTaskOrganizer(ShellInit shellInit,
+            ShellCommandHandler shellCommandHandler,
             ITaskOrganizerController taskOrganizerController,
             @Nullable CompatUIController compatUI,
             Optional<UnfoldAnimationController> unfoldAnimationController,
             Optional<RecentTasksController> recentTasks,
             ShellExecutor mainExecutor) {
         super(taskOrganizerController, mainExecutor);
+        mShellCommandHandler = shellCommandHandler;
         mCompatUI = compatUI;
         mRecentTasks = recentTasks;
         mUnfoldAnimationController = unfoldAnimationController.orElse(null);
@@ -219,6 +226,7 @@
     }
 
     private void onInit() {
+        mShellCommandHandler.addDumpCallback(this::dump, this);
         if (mCompatUI != null) {
             mCompatUI.setCompatUICallback(this);
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/PhysicsAnimator.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/PhysicsAnimator.kt
index 312af4f..ee8c414 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/PhysicsAnimator.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/PhysicsAnimator.kt
@@ -22,7 +22,6 @@
 import androidx.dynamicanimation.animation.DynamicAnimation
 import androidx.dynamicanimation.animation.FlingAnimation
 import androidx.dynamicanimation.animation.FloatPropertyCompat
-import androidx.dynamicanimation.animation.FrameCallbackScheduler
 import androidx.dynamicanimation.animation.SpringAnimation
 import androidx.dynamicanimation.animation.SpringForce
 
@@ -125,12 +124,6 @@
     private var defaultFling: FlingConfig = globalDefaultFling
 
     /**
-     * FrameCallbackScheduler to use if it need custom FrameCallbackScheduler, if this is null,
-     * it will use the default FrameCallbackScheduler in the DynamicAnimation.
-     */
-    private var customScheduler: FrameCallbackScheduler? = null
-
-    /**
      * Internal listeners that respond to DynamicAnimations updating and ending, and dispatch to
      * the listeners provided via [addUpdateListener] and [addEndListener]. This allows us to add
      * just one permanent update and end listener to the DynamicAnimations.
@@ -454,14 +447,6 @@
         this.defaultFling = defaultFling
     }
 
-    /**
-     * Set the custom FrameCallbackScheduler for all aniatmion in this animator. Set this with null for
-     * restoring to default FrameCallbackScheduler.
-     */
-    fun setCustomScheduler(scheduler: FrameCallbackScheduler) {
-        this.customScheduler = scheduler
-    }
-
     /** Starts the animations! */
     fun start() {
         startAction()
@@ -511,12 +496,9 @@
                     // springs) on this property before flinging.
                     cancel(animatedProperty)
 
-                    // Apply the custom animation scheduler if it not null
-                    val flingAnim = getFlingAnimation(animatedProperty, target)
-                    flingAnim.scheduler = customScheduler ?: flingAnim.scheduler
-
                     // Apply the configuration and start the animation.
-                    flingAnim.also { flingConfig.applyToAnimation(it) }.start()
+                    getFlingAnimation(animatedProperty, target)
+                        .also { flingConfig.applyToAnimation(it) }.start()
                 }
             }
 
@@ -529,18 +511,6 @@
                     // Apply the configuration and start the animation.
                     val springAnim = getSpringAnimation(animatedProperty, target)
 
-                    // If customScheduler is exist and has not been set to the animation,
-                    // it should set here.
-                    if (customScheduler != null &&
-                            springAnim.scheduler != customScheduler) {
-                        // Cancel the animation before set animation handler
-                        if (springAnim.isRunning) {
-                            cancel(animatedProperty)
-                        }
-                        // Apply the custom scheduler handler if it not null
-                        springAnim.scheduler = customScheduler ?: springAnim.scheduler
-                    }
-
                     // Apply the configuration and start the animation.
                     springConfig.applyToAnimation(springAnim)
                     animationStartActions.add(springAnim::start)
@@ -596,12 +566,9 @@
                                     }
                                 }
 
-                                // Apply the custom animation scheduler if it not null
-                                val springAnim = getSpringAnimation(animatedProperty, target)
-                                springAnim.scheduler = customScheduler ?: springAnim.scheduler
-
                                 // Apply the configuration and start the spring animation.
-                                springAnim.also { springConfig.applyToAnimation(it) }.start()
+                                getSpringAnimation(animatedProperty, target)
+                                    .also { springConfig.applyToAnimation(it) }.start()
                             }
                         }
                     })
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 05fafc5..d3e46f8 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
@@ -57,6 +57,7 @@
 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.ShellInit;
 
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -90,13 +91,14 @@
      * Raw delta between {@link #mInitTouchLocation} and the last touch location.
      */
     private final Point mTouchEventDelta = new Point();
-    private final ShellExecutor mShellExecutor;
 
     /** True when a back gesture is ongoing */
     private boolean mBackGestureStarted = false;
 
     /** Tracks if an uninterruptible transition is in progress */
     private boolean mTransitionInProgress = false;
+    /** Tracks if we should start the back gesture on the next motion move event */
+    private boolean mShouldStartOnNextMoveEvent = false;
     /** @see #setTriggerBack(boolean) */
     private boolean mTriggerBack;
 
@@ -105,6 +107,9 @@
     private final SurfaceControl.Transaction mTransaction;
     private final IActivityTaskManager mActivityTaskManager;
     private final Context mContext;
+    private final ContentResolver mContentResolver;
+    private final ShellExecutor mShellExecutor;
+    private final Handler mBgHandler;
     @Nullable
     private IOnBackInvokedCallback mBackToLauncherCallback;
     private float mTriggerThreshold;
@@ -133,16 +138,19 @@
     };
 
     public BackAnimationController(
+            @NonNull ShellInit shellInit,
             @NonNull @ShellMainThread ShellExecutor shellExecutor,
             @NonNull @ShellBackgroundThread Handler backgroundHandler,
             Context context) {
-        this(shellExecutor, backgroundHandler, new SurfaceControl.Transaction(),
+        this(shellInit, shellExecutor, backgroundHandler, new SurfaceControl.Transaction(),
                 ActivityTaskManager.getService(), context, context.getContentResolver());
     }
 
     @VisibleForTesting
-    BackAnimationController(@NonNull @ShellMainThread ShellExecutor shellExecutor,
-            @NonNull @ShellBackgroundThread Handler handler,
+    BackAnimationController(
+            @NonNull ShellInit shellInit,
+            @NonNull @ShellMainThread ShellExecutor shellExecutor,
+            @NonNull @ShellBackgroundThread Handler bgHandler,
             @NonNull SurfaceControl.Transaction transaction,
             @NonNull IActivityTaskManager activityTaskManager,
             Context context, ContentResolver contentResolver) {
@@ -150,7 +158,13 @@
         mTransaction = transaction;
         mActivityTaskManager = activityTaskManager;
         mContext = context;
-        setupAnimationDeveloperSettingsObserver(contentResolver, handler);
+        mContentResolver = contentResolver;
+        mBgHandler = bgHandler;
+        shellInit.addInitCallback(this::onInit, this);
+    }
+
+    private void onInit() {
+        setupAnimationDeveloperSettingsObserver(mContentResolver, mBgHandler);
     }
 
     private void setupAnimationDeveloperSettingsObserver(
@@ -286,12 +300,17 @@
         if (mTransitionInProgress) {
             return;
         }
-        if (keyAction == MotionEvent.ACTION_MOVE) {
+        if (keyAction == MotionEvent.ACTION_DOWN) {
             if (!mBackGestureStarted) {
+                mShouldStartOnNextMoveEvent = true;
+            }
+        } else if (keyAction == MotionEvent.ACTION_MOVE) {
+            if (!mBackGestureStarted && mShouldStartOnNextMoveEvent) {
                 // Let the animation initialized here to make sure the onPointerDownOutsideFocus
                 // could be happened when ACTION_DOWN, it may change the current focus that we
                 // would access it when startBackNavigation.
                 onGestureStarted(touchX, touchY);
+                mShouldStartOnNextMoveEvent = false;
             }
             onMove(touchX, touchY, swipeEdge);
         } else if (keyAction == MotionEvent.ACTION_UP || keyAction == MotionEvent.ACTION_CANCEL) {
@@ -425,6 +444,11 @@
 
     private void onGestureFinished(boolean fromTouch) {
         ProtoLog.d(WM_SHELL_BACK_PREVIEW, "onGestureFinished() mTriggerBack == %s", mTriggerBack);
+        if (!mBackGestureStarted) {
+            finishAnimation();
+            return;
+        }
+
         if (fromTouch) {
             // Let touch reset the flag otherwise it will start a new back navigation and refresh
             // the info when received a new move event.
@@ -540,6 +564,7 @@
         boolean triggerBack = mTriggerBack;
         mBackNavigationInfo = null;
         mTriggerBack = false;
+        mShouldStartOnNextMoveEvent = false;
         if (backNavigationInfo == null) {
             return;
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 8771ceb..de26b549 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -1094,13 +1094,16 @@
     }
 
     void updateNotNotifyingEntry(Bubble b, BubbleEntry entry, boolean showInShade) {
+        boolean showInShadeBefore = b.showInShade();
         boolean isBubbleSelected = Objects.equals(b, mBubbleData.getSelectedBubble());
         boolean isBubbleExpandedAndSelected = isStackExpanded() && isBubbleSelected;
         b.setEntry(entry);
         boolean suppress = isBubbleExpandedAndSelected || !showInShade || !b.showInShade();
         b.setSuppressNotification(suppress);
         b.setShowDot(!isBubbleExpandedAndSelected);
-        mImpl.mCachedState.updateBubbleSuppressedState(b);
+        if (showInShadeBefore != b.showInShade()) {
+            mImpl.mCachedState.updateBubbleSuppressedState(b);
+        }
     }
 
     @VisibleForTesting
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java
index afc706e..b8204d0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java
@@ -19,6 +19,7 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.window.TransitionInfo.FLAG_FIRST_CUSTOM;
 
 import android.annotation.IntDef;
 
@@ -55,4 +56,7 @@
             {WINDOWING_MODE_FULLSCREEN, WINDOWING_MODE_UNDEFINED};
     public static final int[] CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE =
             {WINDOWING_MODE_FULLSCREEN, WINDOWING_MODE_UNDEFINED, WINDOWING_MODE_MULTI_WINDOW};
+
+    /** Flag applied to a transition change to identify it as a divider bar for animation. */
+    public static final int FLAG_IS_DIVIDER_BAR = FLAG_FIRST_CUSTOM;
 }
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 db8d9d4..235fd9c 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
@@ -43,6 +43,7 @@
 import com.android.wm.shell.compatui.letterboxedu.LetterboxEduWindowManager;
 import com.android.wm.shell.sysui.KeyguardChangeListener;
 import com.android.wm.shell.sysui.ShellController;
+import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.transition.Transitions;
 
 import java.lang.ref.WeakReference;
@@ -119,6 +120,7 @@
     private boolean mKeyguardShowing;
 
     public CompatUIController(Context context,
+            ShellInit shellInit,
             ShellController shellController,
             DisplayController displayController,
             DisplayInsetsController displayInsetsController,
@@ -134,10 +136,14 @@
         mSyncQueue = syncQueue;
         mMainExecutor = mainExecutor;
         mTransitionsLazy = transitionsLazy;
+        mCompatUIHintsState = new CompatUIHintsState();
+        shellInit.addInitCallback(this::onInit, this);
+    }
+
+    private void onInit() {
+        mShellController.addKeyguardChangeListener(this);
         mDisplayController.addDisplayWindowListener(this);
         mImeController.addPositionProcessor(this);
-        mCompatUIHintsState = new CompatUIHintsState();
-        shellController.addKeyguardChangeListener(this);
     }
 
     /** Sets the callback for UI interactions. */
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 3add417..a6a04cf 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
@@ -128,15 +128,9 @@
                 mainExecutor);
     }
 
-    // Workaround for dynamic overriding with a default implementation, see {@link DynamicOverride}
-    @BindsOptionalOf
-    @DynamicOverride
-    abstract DisplayImeController optionalDisplayImeController();
-
     @WMSingleton
     @Provides
     static DisplayImeController provideDisplayImeController(
-            @DynamicOverride Optional<DisplayImeController> overrideDisplayImeController,
             IWindowManager wmService,
             ShellInit shellInit,
             DisplayController displayController,
@@ -144,9 +138,6 @@
             TransactionPool transactionPool,
             @ShellMainThread ShellExecutor mainExecutor
     ) {
-        if (overrideDisplayImeController.isPresent()) {
-            return overrideDisplayImeController.get();
-        }
         return new DisplayImeController(wmService, shellInit, displayController,
                 displayInsetsController, transactionPool, mainExecutor);
     }
@@ -174,13 +165,14 @@
     @Provides
     static ShellTaskOrganizer provideShellTaskOrganizer(
             ShellInit shellInit,
+            ShellCommandHandler shellCommandHandler,
             CompatUIController compatUI,
             Optional<UnfoldAnimationController> unfoldAnimationController,
             Optional<RecentTasksController> recentTasksOptional,
             @ShellMainThread ShellExecutor mainExecutor
     ) {
-        return new ShellTaskOrganizer(shellInit, compatUI, unfoldAnimationController,
-                recentTasksOptional, mainExecutor);
+        return new ShellTaskOrganizer(shellInit, shellCommandHandler, compatUI,
+                unfoldAnimationController, recentTasksOptional, mainExecutor);
     }
 
     @WMSingleton
@@ -188,6 +180,7 @@
     static KidsModeTaskOrganizer provideKidsModeTaskOrganizer(
             Context context,
             ShellInit shellInit,
+            ShellCommandHandler shellCommandHandler,
             SyncTransactionQueue syncTransactionQueue,
             DisplayController displayController,
             DisplayInsetsController displayInsetsController,
@@ -196,19 +189,20 @@
             @ShellMainThread ShellExecutor mainExecutor,
             @ShellMainThread Handler mainHandler
     ) {
-        return new KidsModeTaskOrganizer(context, shellInit, syncTransactionQueue,
-                displayController, displayInsetsController, unfoldAnimationController,
-                recentTasksOptional, mainExecutor, 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) {
-        return new CompatUIController(context, shellController, displayController,
+        return new CompatUIController(context, shellInit, shellController, displayController,
                 displayInsetsController, imeController, syncQueue, mainExecutor, transitionsLazy);
     }
 
@@ -268,12 +262,14 @@
     @Provides
     static Optional<BackAnimationController> provideBackAnimationController(
             Context context,
+            ShellInit shellInit,
             @ShellMainThread ShellExecutor shellExecutor,
             @ShellBackgroundThread Handler backgroundHandler
     ) {
         if (BackAnimationController.IS_ENABLED) {
             return Optional.of(
-                    new BackAnimationController(shellExecutor, backgroundHandler, context));
+                    new BackAnimationController(shellInit, shellExecutor, backgroundHandler,
+                            context));
         }
         return Optional.empty();
     }
@@ -384,11 +380,14 @@
     @WMSingleton
     @Provides
     static Optional<HideDisplayCutoutController> provideHideDisplayCutoutController(Context context,
-            ShellController shellController, DisplayController displayController,
+            ShellInit shellInit,
+            ShellCommandHandler shellCommandHandler,
+            ShellController shellController,
+            DisplayController displayController,
             @ShellMainThread ShellExecutor mainExecutor) {
         return Optional.ofNullable(
-                HideDisplayCutoutController.create(context, shellController, displayController,
-                        mainExecutor));
+                HideDisplayCutoutController.create(context, shellInit, shellCommandHandler,
+                        shellController, displayController, mainExecutor));
     }
 
     //
@@ -466,12 +465,13 @@
     static Optional<RecentTasksController> provideRecentTasksController(
             Context context,
             ShellInit shellInit,
+            ShellCommandHandler shellCommandHandler,
             TaskStackListenerImpl taskStackListener,
             @ShellMainThread ShellExecutor mainExecutor
     ) {
         return Optional.ofNullable(
-                RecentTasksController.create(context, shellInit, taskStackListener,
-                        mainExecutor));
+                RecentTasksController.create(context, shellInit, shellCommandHandler,
+                        taskStackListener, mainExecutor));
     }
 
     //
@@ -649,8 +649,9 @@
     @WMSingleton
     @Provides
     static ShellController provideShellController(ShellInit shellInit,
+            ShellCommandHandler shellCommandHandler,
             @ShellMainThread ShellExecutor mainExecutor) {
-        return new ShellController(shellInit, mainExecutor);
+        return new ShellController(shellInit, shellCommandHandler, mainExecutor);
     }
 
     //
@@ -676,12 +677,15 @@
             KidsModeTaskOrganizer kidsModeTaskOrganizer,
             Optional<BubbleController> bubblesOptional,
             Optional<SplitScreenController> splitScreenOptional,
+            Optional<Pip> pipOptional,
             Optional<PipTouchHandler> pipTouchHandlerOptional,
             FullscreenTaskListener fullscreenTaskListener,
             Optional<UnfoldAnimationController> unfoldAnimationController,
             Optional<UnfoldTransitionHandler> unfoldTransitionHandler,
             Optional<FreeformComponents> freeformComponents,
             Optional<RecentTasksController> recentTasksOptional,
+            Optional<OneHandedController> oneHandedControllerOptional,
+            Optional<HideDisplayCutoutController> hideDisplayCutoutControllerOptional,
             ActivityEmbeddingController activityEmbeddingOptional,
             Transitions transitions,
             StartingWindowController startingWindow,
@@ -697,18 +701,7 @@
 
     @WMSingleton
     @Provides
-    static ShellCommandHandler provideShellCommandHandlerImpl(
-            ShellController shellController,
-            ShellTaskOrganizer shellTaskOrganizer,
-            KidsModeTaskOrganizer kidsModeTaskOrganizer,
-            Optional<SplitScreenController> splitScreenOptional,
-            Optional<Pip> pipOptional,
-            Optional<OneHandedController> oneHandedOptional,
-            Optional<HideDisplayCutoutController> hideDisplayCutout,
-            Optional<RecentTasksController> recentTasksOptional,
-            @ShellMainThread ShellExecutor mainExecutor) {
-        return new ShellCommandHandler(shellController, shellTaskOrganizer,
-                kidsModeTaskOrganizer, splitScreenOptional, pipOptional, oneHandedOptional,
-                hideDisplayCutout, recentTasksOptional, mainExecutor);
+    static ShellCommandHandler provideShellCommandHandler() {
+        return new ShellCommandHandler();
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index d53451a..2ca9c3b 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
@@ -74,6 +74,7 @@
 import com.android.wm.shell.pip.phone.PipTouchHandler;
 import com.android.wm.shell.recents.RecentTasksController;
 import com.android.wm.shell.splitscreen.SplitScreenController;
+import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellController;
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.transition.SplitscreenPipMixedHandler;
@@ -248,14 +249,20 @@
     @Provides
     @DynamicOverride
     static OneHandedController provideOneHandedController(Context context,
+            ShellInit shellInit,
+            ShellCommandHandler shellCommandHandler,
             ShellController shellController,
-            WindowManager windowManager, DisplayController displayController,
-            DisplayLayout displayLayout, TaskStackListenerImpl taskStackListener,
-            UiEventLogger uiEventLogger, InteractionJankMonitor jankMonitor,
-            @ShellMainThread ShellExecutor mainExecutor, @ShellMainThread Handler mainHandler) {
-        return OneHandedController.create(context, shellController, windowManager,
-                displayController, displayLayout, taskStackListener, jankMonitor, uiEventLogger,
-                mainExecutor, mainHandler);
+            WindowManager windowManager,
+            DisplayController displayController,
+            DisplayLayout displayLayout,
+            TaskStackListenerImpl taskStackListener,
+            UiEventLogger uiEventLogger,
+            InteractionJankMonitor jankMonitor,
+            @ShellMainThread ShellExecutor mainExecutor,
+            @ShellMainThread Handler mainHandler) {
+        return OneHandedController.create(context, shellInit, shellCommandHandler, shellController,
+                windowManager, displayController, displayLayout, taskStackListener, jankMonitor,
+                uiEventLogger, mainExecutor, mainHandler);
     }
 
     //
@@ -268,6 +275,7 @@
     static SplitScreenController provideSplitScreenController(
             Context context,
             ShellInit shellInit,
+            ShellCommandHandler shellCommandHandler,
             ShellController shellController,
             ShellTaskOrganizer shellTaskOrganizer,
             SyncTransactionQueue syncQueue,
@@ -281,10 +289,10 @@
             IconProvider iconProvider,
             Optional<RecentTasksController> recentTasks,
             @ShellMainThread ShellExecutor mainExecutor) {
-        return new SplitScreenController(context, shellInit, shellController, shellTaskOrganizer,
-                syncQueue, rootTaskDisplayAreaOrganizer, displayController, displayImeController,
-                displayInsetsController, dragAndDropController, transitions, transactionPool,
-                iconProvider, recentTasks, mainExecutor);
+        return new SplitScreenController(context, shellInit, shellCommandHandler, shellController,
+                shellTaskOrganizer, syncQueue, rootTaskDisplayAreaOrganizer, displayController,
+                displayImeController, displayInsetsController, dragAndDropController, transitions,
+                transactionPool, iconProvider, recentTasks, mainExecutor);
     }
 
     //
@@ -294,24 +302,33 @@
     @WMSingleton
     @Provides
     static Optional<Pip> providePip(Context context,
-            ShellController shellController, DisplayController displayController,
-            PipAppOpsListener pipAppOpsListener, PipBoundsAlgorithm pipBoundsAlgorithm,
-            PipKeepClearAlgorithm pipKeepClearAlgorithm, PipBoundsState pipBoundsState,
-            PipMotionHelper pipMotionHelper, PipMediaController pipMediaController,
-            PhonePipMenuController phonePipMenuController, PipTaskOrganizer pipTaskOrganizer,
+            ShellInit shellInit,
+            ShellCommandHandler shellCommandHandler,
+            ShellController shellController,
+            DisplayController displayController,
+            PipAppOpsListener pipAppOpsListener,
+            PipBoundsAlgorithm pipBoundsAlgorithm,
+            PipKeepClearAlgorithm pipKeepClearAlgorithm,
+            PipBoundsState pipBoundsState,
+            PipMotionHelper pipMotionHelper,
+            PipMediaController pipMediaController,
+            PhonePipMenuController phonePipMenuController,
+            PipTaskOrganizer pipTaskOrganizer,
             PipTransitionState pipTransitionState,
-            PipTouchHandler pipTouchHandler, PipTransitionController pipTransitionController,
+            PipTouchHandler pipTouchHandler,
+            PipTransitionController pipTransitionController,
             WindowManagerShellWrapper windowManagerShellWrapper,
             TaskStackListenerImpl taskStackListener,
             PipParamsChangedForwarder pipParamsChangedForwarder,
             Optional<OneHandedController> oneHandedController,
             @ShellMainThread ShellExecutor mainExecutor) {
-        return Optional.ofNullable(PipController.create(context, shellController, displayController,
-                pipAppOpsListener, pipBoundsAlgorithm, pipKeepClearAlgorithm, pipBoundsState,
-                pipMotionHelper,
-                pipMediaController, phonePipMenuController, pipTaskOrganizer, pipTransitionState,
-                pipTouchHandler, pipTransitionController, windowManagerShellWrapper,
-                taskStackListener, pipParamsChangedForwarder, oneHandedController, 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,
+                oneHandedController, mainExecutor));
     }
 
     @WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/debugging.md b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/debugging.md
index 52f0c42..99922fb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/debugging.md
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/debugging.md
@@ -59,9 +59,9 @@
 adb shell dumpsys activity service SystemUIService WMShell
 ```
 
-If information should be added to the dump, make updates to:
-- `WMShell` if you are dumping SysUI state
-- `ShellCommandHandler` if you are dumping Shell state
+If information should be added to the dump, either:
+- Update `WMShell` if you are dumping SysUI state
+- Inject `ShellCommandHandler` into your Shell class, and add a dump callback
 
 ## Debugging in Android Studio
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/sysui.md b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/sysui.md
index 0dd50b1..d6302e6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/sysui.md
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/sysui.md
@@ -32,7 +32,7 @@
 
 More detail can be found in [go/wm-sysui-dagger](http://go/wm-sysui-dagger).
 
-## Interfaces to Shell components
+## Interfaces from SysUI to Shell components
 
 Within the same process, the WM Shell components can be running on a different thread than the main
 SysUI thread (disabled on certain products).  This introduces challenges where we have to be
@@ -54,12 +54,30 @@
 Adding an interface to a Shell component may seem like a lot of boiler plate, but is currently
 necessary to maintain proper threading and logic isolation.
 
-## Configuration changes & other SysUI events
+## Listening for Configuration changes & other SysUI events
 
-Aside from direct calls into Shell controllers for exposed features, the Shell also receives 
+Aside from direct calls into Shell controllers for exposed features, the Shell also receives
 common event callbacks from SysUI via the `ShellController`.  This includes things like:
 
 - Configuration changes
-- TODO: Shell init
-- TODO: Shell command
-- TODO: Keyguard events
\ No newline at end of file
+- Keyguard events
+- Shell init
+- Shell dumps & commands
+
+For other events which are specific to the Shell feature, then you can add callback methods on
+the Shell feature interface.  Any such calls should <u>**never**</u> be synchronous calls as
+they will need to post to the Shell main thread to run.
+
+## Shell commands & Dumps
+
+Since the Shell library is a part of the SysUI process, it relies on SysUI to trigger commands
+on individual Shell components, or to dump individual shell components.
+
+```shell
+# Dump everything
+adb shell dumpsys activity service SystemUIService WMShell
+
+# Run a specific command
+adb shell dumpsys activity service SystemUIService WMShell help
+adb shell dumpsys activity service SystemUIService WMShell <cmd> <args> ...
+```
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
index ff3c083..497a6f6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
@@ -105,6 +105,10 @@
                 MATCH_PARENT));
         ((LayoutParams) mDropZoneView1.getLayoutParams()).weight = 1;
         ((LayoutParams) mDropZoneView2.getLayoutParams()).weight = 1;
+        int orientation = getResources().getConfiguration().orientation;
+        setOrientation(orientation == Configuration.ORIENTATION_LANDSCAPE
+                ? LinearLayout.HORIZONTAL
+                : LinearLayout.VERTICAL);
         updateContainerMargins(getResources().getConfiguration().orientation);
     }
 
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 af205ed..a1e9f93 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java
@@ -92,6 +92,12 @@
     }
 
     @Override
+    public void startMinimizedModeTransition(WindowContainerTransaction wct) {
+        final int type = WindowManager.TRANSIT_TO_BACK;
+        mPendingTransitionTokens.add(mTransitions.startTransition(type, wct, this));
+    }
+
+    @Override
     public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
             @NonNull SurfaceControl.Transaction startT,
             @NonNull SurfaceControl.Transaction finishT,
@@ -121,6 +127,8 @@
                             transition, info.getType(), change, startT, finishT);
                     break;
                 case WindowManager.TRANSIT_TO_BACK:
+                    transitionHandled |= startMinimizeTransition(transition);
+                    break;
                 case WindowManager.TRANSIT_TO_FRONT:
                     break;
             }
@@ -169,6 +177,13 @@
         return false;
     }
 
+    private boolean startMinimizeTransition(IBinder transition) {
+        if (!mPendingTransitionTokens.contains(transition)) {
+            return false;
+        }
+        return true;
+    }
+
     private boolean startChangeTransition(
             IBinder transition,
             int type,
@@ -243,4 +258,5 @@
                 return null;
         }
     }
+
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionStarter.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionStarter.java
index 25eaa0e..c947cf1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionStarter.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionStarter.java
@@ -29,6 +29,15 @@
      *
      * @param targetWindowingMode the target windowing mode
      * @param wct the {@link WindowContainerTransaction} that changes the windowing mode
+     *
      */
     void startWindowingModeTransition(int targetWindowingMode, WindowContainerTransaction wct);
-}
+
+    /**
+     * Starts window minimization transition
+     *
+     * @param wct the {@link WindowContainerTransaction} that changes the windowing mode
+     *
+     */
+    void startMinimizedModeTransition(WindowContainerTransaction wct);
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutController.java
index 665b035..32125fa 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutController.java
@@ -27,7 +27,9 @@
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.sysui.ConfigurationChangeListener;
+import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellController;
+import com.android.wm.shell.sysui.ShellInit;
 
 import java.io.PrintWriter;
 
@@ -38,6 +40,7 @@
     private static final String TAG = "HideDisplayCutoutController";
 
     private final Context mContext;
+    private final ShellCommandHandler mShellCommandHandler;
     private final ShellController mShellController;
     private final HideDisplayCutoutOrganizer mOrganizer;
     @VisibleForTesting
@@ -49,7 +52,10 @@
      */
     @Nullable
     public static HideDisplayCutoutController create(Context context,
-            ShellController shellController, DisplayController displayController,
+            ShellInit shellInit,
+            ShellCommandHandler shellCommandHandler,
+            ShellController shellController,
+            DisplayController displayController,
             ShellExecutor mainExecutor) {
         // The SystemProperty is set for devices that support this feature and is used to control
         // whether to create the HideDisplayCutout instance.
@@ -60,14 +66,24 @@
 
         HideDisplayCutoutOrganizer organizer =
                 new HideDisplayCutoutOrganizer(context, displayController, mainExecutor);
-        return new HideDisplayCutoutController(context, shellController, organizer);
+        return new HideDisplayCutoutController(context, shellInit, shellCommandHandler,
+                shellController, organizer);
     }
 
-    HideDisplayCutoutController(Context context, ShellController shellController,
+    HideDisplayCutoutController(Context context,
+            ShellInit shellInit,
+            ShellCommandHandler shellCommandHandler,
+            ShellController shellController,
             HideDisplayCutoutOrganizer organizer) {
         mContext = context;
+        mShellCommandHandler = shellCommandHandler;
         mShellController = shellController;
         mOrganizer = organizer;
+        shellInit.addInitCallback(this::onInit, this);
+    }
+
+    private void onInit() {
+        mShellCommandHandler.addDumpCallback(this::dump, this);
         updateStatus();
         mShellController.addConfigurationChangeListener(this);
     }
@@ -96,11 +112,11 @@
         updateStatus();
     }
 
-    public void dump(@NonNull PrintWriter pw) {
-        final String prefix = "  ";
+    public void dump(@NonNull PrintWriter pw, String prefix) {
+        final String innerPrefix = "  ";
         pw.print(TAG);
         pw.println(" states: ");
-        pw.print(prefix);
+        pw.print(innerPrefix);
         pw.print("mEnabled=");
         pw.println(mEnabled);
         mOrganizer.dump(pw);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java
index 73b9b89..2fdd121 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java
@@ -50,6 +50,7 @@
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.recents.RecentTasksController;
+import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.unfold.UnfoldAnimationController;
 
@@ -73,6 +74,7 @@
 
     private final Handler mMainHandler;
     private final Context mContext;
+    private final ShellCommandHandler mShellCommandHandler;
     private final SyncTransactionQueue mSyncQueue;
     private final DisplayController mDisplayController;
     private final DisplayInsetsController mDisplayInsetsController;
@@ -141,6 +143,8 @@
     @VisibleForTesting
     KidsModeTaskOrganizer(
             Context context,
+            ShellInit shellInit,
+            ShellCommandHandler shellCommandHandler,
             ITaskOrganizerController taskOrganizerController,
             SyncTransactionQueue syncTransactionQueue,
             DisplayController displayController,
@@ -150,19 +154,23 @@
             KidsModeSettingsObserver kidsModeSettingsObserver,
             ShellExecutor mainExecutor,
             Handler mainHandler) {
-        super(/* shellInit= */ null, taskOrganizerController, /* compatUI= */ null,
-                unfoldAnimationController, recentTasks, mainExecutor);
+        // Note: we don't call super with the shell init because we will be initializing manually
+        super(/* shellInit= */ null, /* shellCommandHandler= */ null, taskOrganizerController,
+                /* compatUI= */ null, unfoldAnimationController, recentTasks, mainExecutor);
         mContext = context;
+        mShellCommandHandler = shellCommandHandler;
         mMainHandler = mainHandler;
         mSyncQueue = syncTransactionQueue;
         mDisplayController = displayController;
         mDisplayInsetsController = displayInsetsController;
         mKidsModeSettingsObserver = kidsModeSettingsObserver;
+        shellInit.addInitCallback(this::onInit, this);
     }
 
     public KidsModeTaskOrganizer(
             Context context,
             ShellInit shellInit,
+            ShellCommandHandler shellCommandHandler,
             SyncTransactionQueue syncTransactionQueue,
             DisplayController displayController,
             DisplayInsetsController displayInsetsController,
@@ -171,9 +179,10 @@
             ShellExecutor mainExecutor,
             Handler mainHandler) {
         // Note: we don't call super with the shell init because we will be initializing manually
-        super(/* shellInit= */ null, /* compatUI= */ null, unfoldAnimationController, recentTasks,
-                mainExecutor);
+        super(/* shellInit= */ null, /* taskOrganizerController= */ null, /* compatUI= */ null,
+                unfoldAnimationController, recentTasks, mainExecutor);
         mContext = context;
+        mShellCommandHandler = shellCommandHandler;
         mMainHandler = mainHandler;
         mSyncQueue = syncTransactionQueue;
         mDisplayController = displayController;
@@ -185,6 +194,9 @@
      * Initializes kids mode status.
      */
     public void onInit() {
+        if (mShellCommandHandler != null) {
+            mShellCommandHandler.addDumpCallback(this::dump, this);
+        }
         if (mKidsModeSettingsObserver == null) {
             mKidsModeSettingsObserver = new KidsModeSettingsObserver(mMainHandler, mContext);
         }
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 24f02ac..9149204 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
@@ -56,7 +56,9 @@
 import com.android.wm.shell.common.annotations.ExternalThread;
 import com.android.wm.shell.sysui.ConfigurationChangeListener;
 import com.android.wm.shell.sysui.KeyguardChangeListener;
+import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellController;
+import com.android.wm.shell.sysui.ShellInit;
 
 import java.io.PrintWriter;
 
@@ -85,6 +87,7 @@
 
     private Context mContext;
 
+    private final ShellCommandHandler mShellCommandHandler;
     private final ShellController mShellController;
     private final AccessibilityManager mAccessibilityManager;
     private final DisplayController mDisplayController;
@@ -192,8 +195,9 @@
     /**
      * Creates {@link OneHandedController}, returns {@code null} if the feature is not supported.
      */
-    public static OneHandedController create(
-            Context context, ShellController shellController, WindowManager windowManager,
+    public static OneHandedController create(Context context,
+            ShellInit shellInit, ShellCommandHandler shellCommandHandler,
+            ShellController shellController, WindowManager windowManager,
             DisplayController displayController, DisplayLayout displayLayout,
             TaskStackListenerImpl taskStackListener,
             InteractionJankMonitor jankMonitor, UiEventLogger uiEventLogger,
@@ -213,14 +217,16 @@
                 context, displayLayout, settingsUtil, animationController, tutorialHandler,
                 jankMonitor, mainExecutor);
         OneHandedUiEventLogger oneHandedUiEventsLogger = new OneHandedUiEventLogger(uiEventLogger);
-        return new OneHandedController(context, shellController, displayController, organizer,
-                touchHandler, tutorialHandler, settingsUtil, accessibilityUtil, timeoutHandler,
-                oneHandedState, oneHandedUiEventsLogger, taskStackListener,
-                mainExecutor, mainHandler);
+        return new OneHandedController(context, shellInit, shellCommandHandler, shellController,
+                displayController, organizer, touchHandler, tutorialHandler, settingsUtil,
+                accessibilityUtil, timeoutHandler, oneHandedState, oneHandedUiEventsLogger,
+                taskStackListener, mainExecutor, mainHandler);
     }
 
     @VisibleForTesting
     OneHandedController(Context context,
+            ShellInit shellInit,
+            ShellCommandHandler shellCommandHandler,
             ShellController shellController,
             DisplayController displayController,
             OneHandedDisplayAreaOrganizer displayAreaOrganizer,
@@ -235,6 +241,7 @@
             ShellExecutor mainExecutor,
             Handler mainHandler) {
         mContext = context;
+        mShellCommandHandler = shellCommandHandler;
         mShellController = shellController;
         mOneHandedSettingsUtil = settingsUtil;
         mOneHandedAccessibilityUtil = oneHandedAccessibilityUtil;
@@ -247,8 +254,8 @@
         mMainHandler = mainHandler;
         mOneHandedUiEventLogger = uiEventsLogger;
         mTaskStackListener = taskStackListener;
+        mAccessibilityManager = AccessibilityManager.getInstance(mContext);
 
-        mDisplayController.addDisplayWindowListener(mDisplaysChangedListener);
         final float offsetPercentageConfig = context.getResources().getFraction(
                 R.fraction.config_one_handed_offset, 1, 1);
         final int sysPropPercentageConfig = SystemProperties.getInt(
@@ -268,6 +275,12 @@
                 getObserver(this::onSwipeToNotificationEnabledChanged);
         mShortcutEnabledObserver = getObserver(this::onShortcutEnabledChanged);
 
+        shellInit.addInitCallback(this::onInit, this);
+    }
+
+    private void onInit() {
+        mShellCommandHandler.addDumpCallback(this::dump, this);
+        mDisplayController.addDisplayWindowListener(mDisplaysChangedListener);
         mDisplayController.addDisplayChangingController(this);
         setupCallback();
         registerSettingObservers(mUserId);
@@ -275,7 +288,6 @@
         updateSettings();
         updateDisplayLayout(mContext.getDisplayId());
 
-        mAccessibilityManager = AccessibilityManager.getInstance(context);
         mAccessibilityManager.addAccessibilityStateChangeListener(
                 mAccessibilityStateChangeListener);
 
@@ -623,7 +635,7 @@
         updateOneHandedEnabled();
     }
 
-    public void dump(@NonNull PrintWriter pw) {
+    public void dump(@NonNull PrintWriter pw, String prefix) {
         final String innerPrefix = "  ";
         pw.println();
         pw.println(TAG);
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 38631ce..93172f8 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
@@ -20,7 +20,6 @@
 
 import com.android.wm.shell.common.annotations.ExternalThread;
 
-import java.io.PrintWriter;
 import java.util.function.Consumer;
 
 /**
@@ -99,12 +98,4 @@
      * view hierarchy or destroyed.
      */
     default void removePipExclusionBoundsChangeListener(Consumer<Rect> listener) { }
-
-    /**
-     * Dump the current state and information if need.
-     *
-     * @param pw The stream to dump information to.
-     */
-    default void dump(PrintWriter pw) {
-    }
 }
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 81e49f8..b32c3ee 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
@@ -29,7 +29,6 @@
 import android.app.TaskInfo;
 import android.content.Context;
 import android.graphics.Rect;
-import android.view.Choreographer;
 import android.view.Surface;
 import android.view.SurfaceControl;
 import android.window.TaskSnapshot;
@@ -279,14 +278,15 @@
             mEndValue = endValue;
             addListener(this);
             addUpdateListener(this);
-            mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
+            mSurfaceControlTransactionFactory =
+                    new PipSurfaceTransactionHelper.VsyncSurfaceControlTransactionFactory();
             mTransitionDirection = TRANSITION_DIRECTION_NONE;
         }
 
         @Override
         public void onAnimationStart(Animator animation) {
             mCurrentValue = mStartValue;
-            onStartTransaction(mLeash, newSurfaceControlTransaction());
+            onStartTransaction(mLeash, mSurfaceControlTransactionFactory.getTransaction());
             if (mPipAnimationCallback != null) {
                 mPipAnimationCallback.onPipAnimationStart(mTaskInfo, this);
             }
@@ -294,14 +294,16 @@
 
         @Override
         public void onAnimationUpdate(ValueAnimator animation) {
-            applySurfaceControlTransaction(mLeash, newSurfaceControlTransaction(),
+            applySurfaceControlTransaction(mLeash,
+                    mSurfaceControlTransactionFactory.getTransaction(),
                     animation.getAnimatedFraction());
         }
 
         @Override
         public void onAnimationEnd(Animator animation) {
             mCurrentValue = mEndValue;
-            final SurfaceControl.Transaction tx = newSurfaceControlTransaction();
+            final SurfaceControl.Transaction tx =
+                    mSurfaceControlTransactionFactory.getTransaction();
             onEndTransaction(mLeash, tx, mTransitionDirection);
             if (mPipAnimationCallback != null) {
                 mPipAnimationCallback.onPipAnimationEnd(mTaskInfo, tx, this);
@@ -348,7 +350,8 @@
         }
 
         void setColorContentOverlay(Context context) {
-            final SurfaceControl.Transaction tx = newSurfaceControlTransaction();
+            final SurfaceControl.Transaction tx =
+                    mSurfaceControlTransactionFactory.getTransaction();
             if (mContentOverlay != null) {
                 mContentOverlay.detach(tx);
             }
@@ -357,7 +360,8 @@
         }
 
         void setSnapshotContentOverlay(TaskSnapshot snapshot, Rect sourceRectHint) {
-            final SurfaceControl.Transaction tx = newSurfaceControlTransaction();
+            final SurfaceControl.Transaction tx =
+                    mSurfaceControlTransactionFactory.getTransaction();
             if (mContentOverlay != null) {
                 mContentOverlay.detach(tx);
             }
@@ -406,7 +410,7 @@
         void setDestinationBounds(Rect destinationBounds) {
             mDestinationBounds.set(destinationBounds);
             if (mAnimationType == ANIM_TYPE_ALPHA) {
-                onStartTransaction(mLeash, newSurfaceControlTransaction());
+                onStartTransaction(mLeash, mSurfaceControlTransactionFactory.getTransaction());
             }
         }
 
@@ -441,16 +445,6 @@
             mEndValue = endValue;
         }
 
-        /**
-         * @return {@link SurfaceControl.Transaction} instance with vsync-id.
-         */
-        protected SurfaceControl.Transaction newSurfaceControlTransaction() {
-            final SurfaceControl.Transaction tx =
-                    mSurfaceControlTransactionFactory.getTransaction();
-            tx.setFrameTimelineVsync(Choreographer.getSfInstance().getVsyncId());
-            return tx;
-        }
-
         @VisibleForTesting
         public void setSurfaceControlTransactionFactory(
                 PipSurfaceTransactionHelper.SurfaceControlTransactionFactory factory) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java
index 0e32663..7096a64 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java
@@ -111,9 +111,6 @@
         private final TaskSnapshot mSnapshot;
         private final Rect mSourceRectHint;
 
-        private float mTaskSnapshotScaleX;
-        private float mTaskSnapshotScaleY;
-
         public PipSnapshotOverlay(TaskSnapshot snapshot, Rect sourceRectHint) {
             mSnapshot = snapshot;
             mSourceRectHint = new Rect(sourceRectHint);
@@ -125,16 +122,16 @@
 
         @Override
         public void attach(SurfaceControl.Transaction tx, SurfaceControl parentLeash) {
-            mTaskSnapshotScaleX = (float) mSnapshot.getTaskSize().x
+            final float taskSnapshotScaleX = (float) mSnapshot.getTaskSize().x
                     / mSnapshot.getHardwareBuffer().getWidth();
-            mTaskSnapshotScaleY = (float) mSnapshot.getTaskSize().y
+            final float taskSnapshotScaleY = (float) mSnapshot.getTaskSize().y
                     / mSnapshot.getHardwareBuffer().getHeight();
             tx.show(mLeash);
             tx.setLayer(mLeash, Integer.MAX_VALUE);
             tx.setBuffer(mLeash, mSnapshot.getHardwareBuffer());
             // Relocate the content to parentLeash's coordinates.
             tx.setPosition(mLeash, -mSourceRectHint.left, -mSourceRectHint.top);
-            tx.setScale(mLeash, mTaskSnapshotScaleX, mTaskSnapshotScaleY);
+            tx.setScale(mLeash, taskSnapshotScaleX, taskSnapshotScaleY);
             tx.reparent(mLeash, parentLeash);
             tx.apply();
         }
@@ -146,20 +143,6 @@
 
         @Override
         public void onAnimationEnd(SurfaceControl.Transaction atomicTx, Rect destinationBounds) {
-            // Work around to make sure the snapshot overlay is aligned with PiP window before
-            // the atomicTx is committed along with the final WindowContainerTransaction.
-            final SurfaceControl.Transaction nonAtomicTx = new SurfaceControl.Transaction();
-            final float scaleX = (float) destinationBounds.width()
-                    / mSourceRectHint.width();
-            final float scaleY = (float) destinationBounds.height()
-                    / mSourceRectHint.height();
-            final float scale = Math.max(
-                    scaleX * mTaskSnapshotScaleX, scaleY * mTaskSnapshotScaleY);
-            nonAtomicTx.setScale(mLeash, scale, scale);
-            nonAtomicTx.setPosition(mLeash,
-                    -scale * mSourceRectHint.left / mTaskSnapshotScaleX,
-                    -scale * mSourceRectHint.top / mTaskSnapshotScaleY);
-            nonAtomicTx.apply();
             atomicTx.remove(mLeash);
         }
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
index 3ac08a6..b9746e3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
@@ -20,6 +20,7 @@
 import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.graphics.RectF;
+import android.view.Choreographer;
 import android.view.SurfaceControl;
 
 import com.android.wm.shell.R;
@@ -234,4 +235,18 @@
     public interface SurfaceControlTransactionFactory {
         SurfaceControl.Transaction getTransaction();
     }
+
+    /**
+     * Implementation of {@link SurfaceControlTransactionFactory} that returns
+     * {@link SurfaceControl.Transaction} with VsyncId being set.
+     */
+    public static class VsyncSurfaceControlTransactionFactory
+            implements SurfaceControlTransactionFactory {
+        @Override
+        public SurfaceControl.Transaction getTransaction() {
+            final SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
+            tx.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId());
+            return tx;
+        }
+    }
 }
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 f747b5e..b46eff6 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
@@ -304,7 +304,8 @@
         mSurfaceTransactionHelper = surfaceTransactionHelper;
         mPipAnimationController = pipAnimationController;
         mPipUiEventLoggerLogger = pipUiEventLogger;
-        mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
+        mSurfaceControlTransactionFactory =
+                new PipSurfaceTransactionHelper.VsyncSurfaceControlTransactionFactory();
         mSplitScreenOptional = splitScreenOptional;
         mTaskOrganizer = shellTaskOrganizer;
         mMainExecutor = mainExecutor;
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 586e3a0..fc97f31 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
@@ -89,7 +89,9 @@
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 import com.android.wm.shell.sysui.ConfigurationChangeListener;
 import com.android.wm.shell.sysui.KeyguardChangeListener;
+import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellController;
+import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.transition.Transitions;
 
 import java.io.PrintWriter;
@@ -122,6 +124,7 @@
     private TaskStackListenerImpl mTaskStackListener;
     private PipParamsChangedForwarder mPipParamsChangedForwarder;
     private Optional<OneHandedController> mOneHandedController;
+    private final ShellCommandHandler mShellCommandHandler;
     private final ShellController mShellController;
     protected final PipImpl mImpl;
 
@@ -295,6 +298,8 @@
      */
     @Nullable
     public static Pip create(Context context,
+            ShellInit shellInit,
+            ShellCommandHandler shellCommandHandler,
             ShellController shellController,
             DisplayController displayController,
             PipAppOpsListener pipAppOpsListener,
@@ -319,16 +324,18 @@
             return null;
         }
 
-        return new PipController(context, shellController, displayController, pipAppOpsListener,
-                pipBoundsAlgorithm, pipKeepClearAlgorithm, pipBoundsState, pipMotionHelper,
-                pipMediaController, phonePipMenuController, pipTaskOrganizer, pipTransitionState,
-                pipTouchHandler, pipTransitionController,
+        return new PipController(context, shellInit, shellCommandHandler, shellController,
+                displayController, pipAppOpsListener, pipBoundsAlgorithm, pipKeepClearAlgorithm,
+                pipBoundsState, pipMotionHelper, pipMediaController, phonePipMenuController,
+                pipTaskOrganizer, pipTransitionState, pipTouchHandler, pipTransitionController,
                 windowManagerShellWrapper, taskStackListener, pipParamsChangedForwarder,
                 oneHandedController, mainExecutor)
                 .mImpl;
     }
 
     protected PipController(Context context,
+            ShellInit shellInit,
+            ShellCommandHandler shellCommandHandler,
             ShellController shellController,
             DisplayController displayController,
             PipAppOpsListener pipAppOpsListener,
@@ -355,6 +362,7 @@
         }
 
         mContext = context;
+        mShellCommandHandler = shellCommandHandler;
         mShellController = shellController;
         mImpl = new PipImpl();
         mWindowManagerShellWrapper = windowManagerShellWrapper;
@@ -378,11 +386,11 @@
                 .getInteger(R.integer.config_pipEnterAnimationDuration);
         mPipParamsChangedForwarder = pipParamsChangedForwarder;
 
-        //TODO: move this to ShellInit when PipController can be injected
-        mMainExecutor.execute(this::init);
+        shellInit.addInitCallback(this::onInit, this);
     }
 
-    public void init() {
+    private void onInit() {
+        mShellCommandHandler.addDumpCallback(this::dump, this);
         mPipInputConsumer = new PipInputConsumer(WindowManagerGlobal.getWindowManagerService(),
                 INPUT_CONSUMER_PIP, mMainExecutor);
         mPipTransitionController.registerPipTransitionCallback(this);
@@ -503,6 +511,12 @@
                             updateMovementBounds(null /* toBounds */, false /* fromRotation */,
                                     false /* fromImeAdjustment */, false /* fromShelfAdjustment */,
                                     null /* windowContainerTransaction */);
+                        } else {
+                            // when we enter pip for the first time, the destination bounds and pip
+                            // bounds will already match, since they are calculated prior to
+                            // starting the animation, so we only need to update the min/max size
+                            // that is used for e.g. double tap to maximized state
+                            mTouchHandler.updateMinMaxSize(ratio);
                         }
                     }
 
@@ -622,7 +636,8 @@
                 mPipTaskOrganizer.scheduleAnimateResizePip(
                         postChangeBounds, duration, null /* updateBoundsCallback */);
             } else {
-                mTouchHandler.getMotionHelper().movePip(postChangeBounds);
+                // Directly move PiP to its final destination bounds without animation.
+                mPipTaskOrganizer.scheduleFinishResizePip(postChangeBounds);
             }
         } else {
             updateDisplayLayout.run();
@@ -912,7 +927,7 @@
         return true;
     }
 
-    private void dump(PrintWriter pw) {
+    private void dump(PrintWriter pw, String prefix) {
         final String innerPrefix = "  ";
         pw.println(TAG);
         mMenuController.dump(pw, innerPrefix);
@@ -1000,18 +1015,6 @@
                 PipController.this.showPictureInPictureMenu();
             });
         }
-
-        @Override
-        public void dump(PrintWriter pw) {
-            try {
-                mMainExecutor.executeBlocking(() -> {
-                    PipController.this.dump(pw);
-                });
-            } catch (InterruptedException e) {
-                ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                        "%s: Failed to dump PipController in 2s", TAG);
-            }
-        }
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
index a0e2201..7619646 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
@@ -288,8 +288,10 @@
 
         if (mTargetViewContainer.getVisibility() != View.VISIBLE) {
             mTargetViewContainer.getViewTreeObserver().addOnPreDrawListener(this);
-            mTargetViewContainer.show();
         }
+        // always invoke show, since the target might still be VISIBLE while playing hide animation,
+        // so we want to ensure it will show back again
+        mTargetViewContainer.show();
     }
 
     /** Animates the magnetic dismiss target out and then sets it to GONE. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
index 5a21e07..44d2202 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
@@ -33,10 +33,6 @@
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.os.Debug;
-import android.os.Looper;
-import android.view.Choreographer;
-
-import androidx.dynamicanimation.animation.FrameCallbackScheduler;
 
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.R;
@@ -89,25 +85,6 @@
     /** Coordinator instance for resolving conflicts with other floating content. */
     private FloatingContentCoordinator mFloatingContentCoordinator;
 
-    private ThreadLocal<FrameCallbackScheduler> mSfSchedulerThreadLocal =
-            ThreadLocal.withInitial(() -> {
-                final Looper initialLooper = Looper.myLooper();
-                final FrameCallbackScheduler scheduler = new FrameCallbackScheduler() {
-                    @Override
-                    public void postFrameCallback(@androidx.annotation.NonNull Runnable runnable) {
-                        // TODO(b/222697646): remove getSfInstance usage and use vsyncId for
-                        //  transactions
-                        Choreographer.getSfInstance().postFrameCallback(t -> runnable.run());
-                    }
-
-                    @Override
-                    public boolean isCurrentThread() {
-                        return Looper.myLooper() == initialLooper;
-                    }
-                };
-                return scheduler;
-            });
-
     /**
      * PhysicsAnimator instance for animating {@link PipBoundsState#getMotionBoundsState()}
      * using physics animations.
@@ -210,10 +187,8 @@
     }
 
     public void init() {
-        // Note: Needs to get the shell main thread sf vsync animation handler
         mTemporaryBoundsPhysicsAnimator = PhysicsAnimator.getInstance(
                 mPipBoundsState.getMotionBoundsState().getBoundsInMotion());
-        mTemporaryBoundsPhysicsAnimator.setCustomScheduler(mSfSchedulerThreadLocal.get());
     }
 
     @NonNull
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index c86c136..a2fa058 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -412,13 +412,7 @@
                 mPipBoundsState.getExpandedBounds(), insetBounds, expandedMovementBounds,
                 bottomOffset);
 
-        if (mPipResizeGestureHandler.isUsingPinchToZoom()) {
-            updatePinchResizeSizeConstraints(insetBounds, normalBounds, aspectRatio);
-        } else {
-            mPipResizeGestureHandler.updateMinSize(normalBounds.width(), normalBounds.height());
-            mPipResizeGestureHandler.updateMaxSize(mPipBoundsState.getExpandedBounds().width(),
-                    mPipBoundsState.getExpandedBounds().height());
-        }
+        updatePipSizeConstraints(insetBounds, normalBounds, aspectRatio);
 
         // The extra offset does not really affect the movement bounds, but are applied based on the
         // current state (ime showing, or shelf offset) when we need to actually shift
@@ -487,6 +481,27 @@
         }
     }
 
+    /**
+     * Update the values for min/max allowed size of picture in picture window based on the aspect
+     * ratio.
+     * @param aspectRatio aspect ratio to use for the calculation of min/max size
+     */
+    public void updateMinMaxSize(float aspectRatio) {
+        updatePipSizeConstraints(mInsetBounds, mPipBoundsState.getNormalBounds(),
+                aspectRatio);
+    }
+
+    private void updatePipSizeConstraints(Rect insetBounds, Rect normalBounds,
+            float aspectRatio) {
+        if (mPipResizeGestureHandler.isUsingPinchToZoom()) {
+            updatePinchResizeSizeConstraints(insetBounds, normalBounds, aspectRatio);
+        } else {
+            mPipResizeGestureHandler.updateMinSize(normalBounds.width(), normalBounds.height());
+            mPipResizeGestureHandler.updateMaxSize(mPipBoundsState.getExpandedBounds().width(),
+                    mPipBoundsState.getExpandedBounds().height());
+        }
+    }
+
     private void updatePinchResizeSizeConstraints(Rect insetBounds, Rect normalBounds,
             float aspectRatio) {
         final int shorterLength = Math.min(mPipBoundsState.getDisplayBounds().width(),
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 3d1a7e9..7b42350 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
@@ -44,6 +44,7 @@
 import com.android.wm.shell.common.annotations.ExternalThread;
 import com.android.wm.shell.common.annotations.ShellMainThread;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.util.GroupedRecentTaskInfo;
 import com.android.wm.shell.util.SplitBounds;
@@ -62,6 +63,7 @@
     private static final String TAG = RecentTasksController.class.getSimpleName();
 
     private final Context mContext;
+    private final ShellCommandHandler mShellCommandHandler;
     private final ShellExecutor mMainExecutor;
     private final TaskStackListenerImpl mTaskStackListener;
     private final RecentTasks mImpl = new RecentTasksImpl();
@@ -87,20 +89,24 @@
     public static RecentTasksController create(
             Context context,
             ShellInit shellInit,
+            ShellCommandHandler shellCommandHandler,
             TaskStackListenerImpl taskStackListener,
             @ShellMainThread ShellExecutor mainExecutor
     ) {
         if (!context.getResources().getBoolean(com.android.internal.R.bool.config_hasRecents)) {
             return null;
         }
-        return new RecentTasksController(context, shellInit, taskStackListener, mainExecutor);
+        return new RecentTasksController(context, shellInit, shellCommandHandler, taskStackListener,
+                mainExecutor);
     }
 
     RecentTasksController(Context context,
             ShellInit shellInit,
+            ShellCommandHandler shellCommandHandler,
             TaskStackListenerImpl taskStackListener,
             ShellExecutor mainExecutor) {
         mContext = context;
+        mShellCommandHandler = shellCommandHandler;
         mIsDesktopMode = mContext.getPackageManager().hasSystemFeature(FEATURE_PC);
         mTaskStackListener = taskStackListener;
         mMainExecutor = mainExecutor;
@@ -112,6 +118,7 @@
     }
 
     private void onInit() {
+        mShellCommandHandler.addDumpCallback(this::dump, this);
         mTaskStackListener.addListener(this);
     }
 
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 8de649e..2117b69 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
@@ -84,6 +84,7 @@
 import com.android.wm.shell.recents.RecentTasksController;
 import com.android.wm.shell.splitscreen.SplitScreen.StageType;
 import com.android.wm.shell.sysui.KeyguardChangeListener;
+import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellController;
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.transition.Transitions;
@@ -131,6 +132,7 @@
     @Retention(RetentionPolicy.SOURCE)
     @interface ExitReason{}
 
+    private final ShellCommandHandler mShellCommandHandler;
     private final ShellController mShellController;
     private final ShellTaskOrganizer mTaskOrganizer;
     private final SyncTransactionQueue mSyncQueue;
@@ -147,6 +149,7 @@
     private final SplitscreenEventLogger mLogger;
     private final IconProvider mIconProvider;
     private final Optional<RecentTasksController> mRecentTasksOptional;
+    private final SplitScreenShellCommandHandler mSplitScreenShellCommandHandler;
 
     private StageCoordinator mStageCoordinator;
     // Only used for the legacy recents animation from splitscreen to allow the tasks to be animated
@@ -155,6 +158,7 @@
 
     public SplitScreenController(Context context,
             ShellInit shellInit,
+            ShellCommandHandler shellCommandHandler,
             ShellController shellController,
             ShellTaskOrganizer shellTaskOrganizer,
             SyncTransactionQueue syncQueue,
@@ -168,6 +172,7 @@
             IconProvider iconProvider,
             Optional<RecentTasksController> recentTasks,
             ShellExecutor mainExecutor) {
+        mShellCommandHandler = shellCommandHandler;
         mShellController = shellController;
         mTaskOrganizer = shellTaskOrganizer;
         mSyncQueue = syncQueue;
@@ -183,6 +188,7 @@
         mLogger = new SplitscreenEventLogger();
         mIconProvider = iconProvider;
         mRecentTasksOptional = recentTasks;
+        mSplitScreenShellCommandHandler = new SplitScreenShellCommandHandler(this);
         // TODO(b/238217847): Temporarily add this check here until we can remove the dynamic
         //                    override for this controller from the base module
         if (ActivityTaskManager.supportsSplitScreenMultiWindow(context)) {
@@ -200,6 +206,9 @@
      */
     @VisibleForTesting
     void onInit() {
+        mShellCommandHandler.addDumpCallback(this::dump, this);
+        mShellCommandHandler.addCommandCallback("splitscreen", mSplitScreenShellCommandHandler,
+                this);
         mShellController.addKeyguardChangeListener(this);
         if (mStageCoordinator == null) {
             // TODO: Multi-display
@@ -425,7 +434,7 @@
 
         // Flag with MULTIPLE_TASK if this is launching the same activity into both sides of the
         // split.
-        if (isLaunchingAdjacently(intent.getIntent(), position)) {
+        if (shouldAddMultipleTaskFlag(intent.getIntent(), position)) {
             fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
             ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Adding MULTIPLE_TASK");
         }
@@ -440,8 +449,7 @@
 
     /** Returns {@code true} if it's launching the same component on both sides of the split. */
     @VisibleForTesting
-    boolean isLaunchingAdjacently(@Nullable Intent startIntent,
-            @SplitPosition int position) {
+    boolean shouldAddMultipleTaskFlag(@Nullable Intent startIntent, @SplitPosition int position) {
         if (startIntent == null) {
             return false;
         }
@@ -452,6 +460,16 @@
         }
 
         if (isSplitScreenVisible()) {
+            // To prevent users from constantly dropping the same app to the same side resulting in
+            // a large number of instances in the background.
+            final ActivityManager.RunningTaskInfo targetTaskInfo = getTaskInfo(position);
+            final ComponentName targetActivity = targetTaskInfo != null
+                    ? targetTaskInfo.baseIntent.getComponent() : null;
+            if (Objects.equals(launchingActivity, targetActivity)) {
+                return false;
+            }
+
+            // Allow users to start a new instance the same to adjacent side.
             final ActivityManager.RunningTaskInfo pairedTaskInfo =
                     getTaskInfo(SplitLayout.reversePosition(position));
             final ComponentName pairedActivity = pairedTaskInfo != null
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenShellCommandHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenShellCommandHandler.java
new file mode 100644
index 0000000..7fd03a9
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenShellCommandHandler.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.splitscreen;
+
+import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
+
+import com.android.wm.shell.sysui.ShellCommandHandler;
+
+import java.io.PrintWriter;
+
+/**
+ * Handles the shell commands for the SplitscreenController.
+ */
+public class SplitScreenShellCommandHandler implements
+        ShellCommandHandler.ShellCommandActionHandler {
+
+    private final SplitScreenController mController;
+
+    public SplitScreenShellCommandHandler(SplitScreenController controller) {
+        mController = controller;
+    }
+
+    @Override
+    public boolean onShellCommand(String[] args, PrintWriter pw) {
+        switch (args[0]) {
+            case "moveToSideStage":
+                return runMoveToSideStage(args, pw);
+            case "removeFromSideStage":
+                return runRemoveFromSideStage(args, pw);
+            case "setSideStagePosition":
+                return runSetSideStagePosition(args, pw);
+            default:
+                pw.println("Invalid command: " + args[0]);
+                return false;
+        }
+    }
+
+    private boolean runMoveToSideStage(String[] args, PrintWriter pw) {
+        if (args.length < 3) {
+            // First argument is the action name.
+            pw.println("Error: task id should be provided as arguments");
+            return false;
+        }
+        final int taskId = new Integer(args[1]);
+        final int sideStagePosition = args.length > 2
+                ? new Integer(args[2]) : SPLIT_POSITION_BOTTOM_OR_RIGHT;
+        mController.moveToSideStage(taskId, sideStagePosition);
+        return true;
+    }
+
+    private boolean runRemoveFromSideStage(String[] args, PrintWriter pw) {
+        if (args.length < 2) {
+            // First argument is the action name.
+            pw.println("Error: task id should be provided as arguments");
+            return false;
+        }
+        final int taskId = new Integer(args[1]);
+        mController.removeFromSideStage(taskId);
+        return true;
+    }
+
+    private boolean runSetSideStagePosition(String[] args, PrintWriter pw) {
+        if (args.length < 2) {
+            // First argument is the action name.
+            pw.println("Error: side stage position should be provided as arguments");
+            return false;
+        }
+        final int position = new Integer(args[1]);
+        mController.setSideStagePosition(position);
+        return true;
+    }
+
+    @Override
+    public void printShellCommandHelp(PrintWriter pw, String prefix) {
+        pw.println(prefix + "moveToSideStage <taskId> <SideStagePosition>");
+        pw.println(prefix + "  Move a task with given id in split-screen mode.");
+        pw.println(prefix + "removeFromSideStage <taskId>");
+        pw.println(prefix + "  Remove a task with given id in split-screen mode.");
+        pw.println(prefix + "setSideStagePosition <SideStagePosition>");
+        pw.println(prefix + "  Sets the position of the side-stage.");
+    }
+}
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 8e1ae39..7e83d2f 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
@@ -32,13 +32,13 @@
 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_FIRST_CUSTOM;
 import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
 
 import static com.android.wm.shell.common.split.SplitLayout.PARALLAX_ALIGN_CENTER;
 import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES;
 import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES;
+import static com.android.wm.shell.common.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
@@ -147,9 +147,6 @@
 
     private static final String TAG = StageCoordinator.class.getSimpleName();
 
-    /** Flag applied to a transition change to identify it as a divider bar for animation. */
-    public static final int FLAG_IS_DIVIDER_BAR = FLAG_FIRST_CUSTOM;
-
     private final SurfaceSession mSurfaceSession = new SurfaceSession();
 
     private final MainStage mMainStage;
@@ -894,6 +891,7 @@
             }
         });
         mShouldUpdateRecents = false;
+        mIsDividerRemoteAnimating = false;
 
         if (childrenToTop == null) {
             mSideStage.removeAllTasks(wct, false /* toTop */);
@@ -1376,21 +1374,13 @@
                 }
             }
         } else if (isSideStage && hasChildren && !mMainStage.isActive()) {
-            if (mFocusingTaskInfo != null && !isValidToEnterSplitScreen(mFocusingTaskInfo)) {
-                final WindowContainerTransaction wct = new WindowContainerTransaction();
-                mSideStage.removeAllTasks(wct, true);
-                wct.reorder(mRootTaskInfo.token, false /* onTop */);
-                mTaskOrganizer.applyTransaction(wct);
-                Slog.i(TAG, "cancel entering split screen, reason = "
-                        + exitReasonToString(EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW));
-            } else {
-                final WindowContainerTransaction wct = new WindowContainerTransaction();
-                mSplitLayout.init();
-                prepareEnterSplitScreen(wct);
-                mSyncQueue.queue(wct);
-                mSyncQueue.runInSync(t ->
-                        updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */));
-            }
+            // TODO (b/238697912) : Add the validation to prevent entering non-recovered status
+            final WindowContainerTransaction wct = new WindowContainerTransaction();
+            mSplitLayout.init();
+            prepareEnterSplitScreen(wct);
+            mSyncQueue.queue(wct);
+            mSyncQueue.runInSync(t ->
+                    updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */));
         }
         if (mMainStageListener.mHasChildren && mSideStageListener.mHasChildren) {
             mShouldUpdateRecents = true;
@@ -1808,7 +1798,8 @@
 
         boolean shouldAnimate = true;
         if (mSplitTransitions.isPendingEnter(transition)) {
-            shouldAnimate = startPendingEnterAnimation(transition, info, startTransaction);
+            shouldAnimate = startPendingEnterAnimation(
+                    transition, info, startTransaction, finishTransaction);
         } else if (mSplitTransitions.isPendingRecent(transition)) {
             shouldAnimate = startPendingRecentAnimation(transition, info, startTransaction);
         } else if (mSplitTransitions.isPendingDismiss(transition)) {
@@ -1836,7 +1827,8 @@
     }
 
     private boolean startPendingEnterAnimation(@NonNull IBinder transition,
-            @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t) {
+            @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t,
+            @NonNull SurfaceControl.Transaction finishT) {
         // First, verify that we actually have opened apps in both splits.
         TransitionInfo.Change mainChild = null;
         TransitionInfo.Change sideChild = null;
@@ -1883,8 +1875,8 @@
                     + " before startAnimation().");
         }
 
-        finishEnterSplitScreen(t);
-        addDividerBarToTransition(info, t, true /* show */);
+        finishEnterSplitScreen(finishT);
+        addDividerBarToTransition(info, finishT, true /* show */);
         return true;
     }
 
@@ -1969,7 +1961,7 @@
             return false;
         }
 
-        addDividerBarToTransition(info, t, false /* show */);
+        addDividerBarToTransition(info, finishT, false /* show */);
         return true;
     }
 
@@ -1980,23 +1972,25 @@
     }
 
     private void addDividerBarToTransition(@NonNull TransitionInfo info,
-            @NonNull SurfaceControl.Transaction t, boolean show) {
+            @NonNull SurfaceControl.Transaction finishT, boolean show) {
         final SurfaceControl leash = mSplitLayout.getDividerLeash();
         final TransitionInfo.Change barChange = new TransitionInfo.Change(null /* token */, leash);
-        final Rect bounds = mSplitLayout.getDividerBounds();
-        barChange.setStartAbsBounds(bounds);
-        barChange.setEndAbsBounds(bounds);
+        mSplitLayout.getRefDividerBounds(mTempRect1);
+        barChange.setStartAbsBounds(mTempRect1);
+        barChange.setEndAbsBounds(mTempRect1);
         barChange.setMode(show ? TRANSIT_TO_FRONT : TRANSIT_TO_BACK);
         barChange.setFlags(FLAG_IS_DIVIDER_BAR);
         // Technically this should be order-0, but this is running after layer assignment
         // and it's a special case, so just add to end.
         info.addChange(barChange);
-        // Be default, make it visible. The remote animator can adjust alpha if it plans to animate.
+
         if (show) {
-            t.setAlpha(leash, 1.f);
-            t.setLayer(leash, Integer.MAX_VALUE);
-            t.setPosition(leash, bounds.left, bounds.top);
-            t.show(leash);
+            finishT.setLayer(leash, Integer.MAX_VALUE);
+            finishT.setPosition(leash, mTempRect1.left, mTempRect1.top);
+            finishT.show(leash);
+            // Ensure divider surface are re-parented back into the hierarchy at the end of the
+            // transition. See Transition#buildFinishTransaction for more detail.
+            finishT.reparent(leash, mRootTaskLeash);
         }
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
index b70bde3..7b498e4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
@@ -246,7 +246,7 @@
         window.setOuter(snapshotSurface);
         try {
             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "TaskSnapshot#relayout");
-            session.relayout(window, layoutParams, -1, -1, View.VISIBLE, 0,
+            session.relayout(window, layoutParams, -1, -1, View.VISIBLE, 0, 0, 0,
                     tmpFrames, tmpMergedConfiguration, surfaceControl, tmpInsetsState,
                     tmpControls, new Bundle());
             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellCommandHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellCommandHandler.java
index f4fc0c4..2e6ddc3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellCommandHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellCommandHandler.java
@@ -16,19 +16,14 @@
 
 package com.android.wm.shell.sysui;
 
-import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_INIT;
 
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.hidedisplaycutout.HideDisplayCutoutController;
-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.recents.RecentTasksController;
-import com.android.wm.shell.splitscreen.SplitScreenController;
+import com.android.internal.protolog.common.ProtoLog;
 
 import java.io.PrintWriter;
-import java.util.Optional;
+import java.util.Arrays;
+import java.util.TreeMap;
+import java.util.function.BiConsumer;
 
 /**
  * An entry point into the shell for dumping shell internal state and running adb commands.
@@ -38,52 +33,61 @@
 public final class ShellCommandHandler {
     private static final String TAG = ShellCommandHandler.class.getSimpleName();
 
-    private final Optional<SplitScreenController> mSplitScreenOptional;
-    private final Optional<Pip> mPipOptional;
-    private final Optional<OneHandedController> mOneHandedOptional;
-    private final Optional<HideDisplayCutoutController> mHideDisplayCutout;
-    private final Optional<RecentTasksController> mRecentTasks;
-    private final ShellTaskOrganizer mShellTaskOrganizer;
-    private final KidsModeTaskOrganizer mKidsModeTaskOrganizer;
+    // We're using a TreeMap to keep them sorted by command name
+    private final TreeMap<String, BiConsumer<PrintWriter, String>> mDumpables = new TreeMap<>();
+    private final TreeMap<String, ShellCommandActionHandler> mCommands = new TreeMap<>();
 
-    public ShellCommandHandler(
-            ShellController shellController,
-            ShellTaskOrganizer shellTaskOrganizer,
-            KidsModeTaskOrganizer kidsModeTaskOrganizer,
-            Optional<SplitScreenController> splitScreenOptional,
-            Optional<Pip> pipOptional,
-            Optional<OneHandedController> oneHandedOptional,
-            Optional<HideDisplayCutoutController> hideDisplayCutout,
-            Optional<RecentTasksController> recentTasks,
-            ShellExecutor mainExecutor) {
-        mShellTaskOrganizer = shellTaskOrganizer;
-        mKidsModeTaskOrganizer = kidsModeTaskOrganizer;
-        mRecentTasks = recentTasks;
-        mSplitScreenOptional = splitScreenOptional;
-        mPipOptional = pipOptional;
-        mOneHandedOptional = oneHandedOptional;
-        mHideDisplayCutout = hideDisplayCutout;
-        // TODO(238217847): To be removed once the command handler dependencies are inverted
-        shellController.setShellCommandHandler(this);
+    public interface ShellCommandActionHandler {
+        /**
+         * Handles the given command.
+         *
+         * @param args the arguments starting with the action name, then the action arguments
+         * @param pw the write to print output to
+         */
+        boolean onShellCommand(String[] args, PrintWriter pw);
+
+        /**
+         * Prints the help for this class of commands.  Implementations do not need to print the
+         * command class.
+         */
+        void printShellCommandHelp(PrintWriter pw, String prefix);
+    }
+
+
+    /**
+     * Adds a callback to run when the Shell is being dumped.
+     *
+     * @param callback the callback to be made when Shell is dumped, takes the print writer and
+     *                 a prefix
+     * @param instance used for debugging only
+     */
+    public <T> void addDumpCallback(BiConsumer<PrintWriter, String> callback, T instance) {
+        mDumpables.put(instance.getClass().getSimpleName(), callback);
+        ProtoLog.v(WM_SHELL_INIT, "Adding dump callback for %s",
+                instance.getClass().getSimpleName());
+    }
+
+    /**
+     * Adds an action callback to be invoked when the user runs that particular command from adb.
+     *
+     * @param commandClass the top level class of command to invoke
+     * @param actions the interface to callback when an action of this class is invoked
+     * @param instance used for debugging only
+     */
+    public <T> void addCommandCallback(String commandClass, ShellCommandActionHandler actions,
+            T instance) {
+        mCommands.put(commandClass, actions);
+        ProtoLog.v(WM_SHELL_INIT, "Adding command class %s for %s", commandClass,
+                instance.getClass().getSimpleName());
     }
 
     /** Dumps WM Shell internal state. */
     public void dump(PrintWriter pw) {
-        mShellTaskOrganizer.dump(pw, "");
-        pw.println();
-        pw.println();
-        mPipOptional.ifPresent(pip -> pip.dump(pw));
-        mOneHandedOptional.ifPresent(oneHanded -> oneHanded.dump(pw));
-        mHideDisplayCutout.ifPresent(hideDisplayCutout -> hideDisplayCutout.dump(pw));
-        pw.println();
-        pw.println();
-        mSplitScreenOptional.ifPresent(splitScreen -> splitScreen.dump(pw, ""));
-        pw.println();
-        pw.println();
-        mRecentTasks.ifPresent(recentTasks -> recentTasks.dump(pw, ""));
-        pw.println();
-        pw.println();
-        mKidsModeTaskOrganizer.dump(pw, "");
+        for (String key : mDumpables.keySet()) {
+            final BiConsumer<PrintWriter, String> r = mDumpables.get(key);
+            r.accept(pw, "");
+            pw.println();
+        }
     }
 
 
@@ -93,72 +97,32 @@
             // Argument at position 0 is "WMShell".
             return false;
         }
-        switch (args[1]) {
-            case "moveToSideStage":
-                return runMoveToSideStage(args, pw);
-            case "removeFromSideStage":
-                return runRemoveFromSideStage(args, pw);
-            case "setSideStagePosition":
-                return runSetSideStagePosition(args, pw);
-            case "help":
-                return runHelp(pw);
-            default:
-                return false;
-        }
-    }
 
-    private boolean runMoveToSideStage(String[] args, PrintWriter pw) {
-        if (args.length < 3) {
-            // First arguments are "WMShell" and command name.
-            pw.println("Error: task id should be provided as arguments");
+        final String cmdClass = args[1];
+        if (cmdClass.toLowerCase().equals("help")) {
+            return runHelp(pw);
+        }
+        if (!mCommands.containsKey(cmdClass)) {
             return false;
         }
-        final int taskId = new Integer(args[2]);
-        final int sideStagePosition = args.length > 3
-                ? new Integer(args[3]) : SPLIT_POSITION_BOTTOM_OR_RIGHT;
-        mSplitScreenOptional.ifPresent(split -> split.moveToSideStage(taskId, sideStagePosition));
-        return true;
-    }
 
-    private boolean runRemoveFromSideStage(String[] args, PrintWriter pw) {
-        if (args.length < 3) {
-            // First arguments are "WMShell" and command name.
-            pw.println("Error: task id should be provided as arguments");
-            return false;
-        }
-        final int taskId = new Integer(args[2]);
-        mSplitScreenOptional.ifPresent(split -> split.removeFromSideStage(taskId));
-        return true;
-    }
-
-    private boolean runSetSideStagePosition(String[] args, PrintWriter pw) {
-        if (args.length < 3) {
-            // First arguments are "WMShell" and command name.
-            pw.println("Error: side stage position should be provided as arguments");
-            return false;
-        }
-        final int position = new Integer(args[2]);
-        mSplitScreenOptional.ifPresent(split -> split.setSideStagePosition(position));
+        // Only pass the actions onwards as arguments to the callback
+        final ShellCommandActionHandler actions = mCommands.get(args[1]);
+        final String[] cmdClassArgs = Arrays.copyOfRange(args, 2, args.length);
+        actions.onShellCommand(cmdClassArgs, pw);
         return true;
     }
 
     private boolean runHelp(PrintWriter pw) {
         pw.println("Window Manager Shell commands:");
+        for (String commandClass : mCommands.keySet()) {
+            pw.println("  " + commandClass);
+            mCommands.get(commandClass).printShellCommandHelp(pw, "    ");
+        }
         pw.println("  help");
         pw.println("      Print this help text.");
         pw.println("  <no arguments provided>");
-        pw.println("    Dump Window Manager Shell internal state");
-        pw.println("  pair <taskId1> <taskId2>");
-        pw.println("  unpair <taskId>");
-        pw.println("    Pairs/unpairs tasks with given ids.");
-        pw.println("  moveToSideStage <taskId> <SideStagePosition>");
-        pw.println("    Move a task with given id in split-screen mode.");
-        pw.println("  removeFromSideStage <taskId>");
-        pw.println("    Remove a task with given id in split-screen mode.");
-        pw.println("  setSideStageOutline <true/false>");
-        pw.println("    Enable/Disable outline on the side-stage.");
-        pw.println("  setSideStagePosition <SideStagePosition>");
-        pw.println("    Sets the position of the side-stage.");
+        pw.println("    Dump all Window Manager Shell internal state");
         return true;
     }
 }
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 f1f317f..52ffb46 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
@@ -45,11 +45,10 @@
     private static final String TAG = ShellController.class.getSimpleName();
 
     private final ShellInit mShellInit;
+    private final ShellCommandHandler mShellCommandHandler;
     private final ShellExecutor mMainExecutor;
     private final ShellInterfaceImpl mImpl = new ShellInterfaceImpl();
 
-    private ShellCommandHandler mShellCommandHandler;
-
     private final CopyOnWriteArrayList<ConfigurationChangeListener> mConfigChangeListeners =
             new CopyOnWriteArrayList<>();
     private final CopyOnWriteArrayList<KeyguardChangeListener> mKeyguardChangeListeners =
@@ -57,8 +56,10 @@
     private Configuration mLastConfiguration;
 
 
-    public ShellController(ShellInit shellInit, ShellExecutor mainExecutor) {
+    public ShellController(ShellInit shellInit, ShellCommandHandler shellCommandHandler,
+            ShellExecutor mainExecutor) {
         mShellInit = shellInit;
+        mShellCommandHandler = shellCommandHandler;
         mMainExecutor = mainExecutor;
     }
 
@@ -70,15 +71,6 @@
     }
 
     /**
-     * Sets the command handler to call back to.
-     * TODO(238217847): This is only exposed this way until we can remove the dependencies from the
-     *                  command handler to other classes.
-     */
-    public void setShellCommandHandler(ShellCommandHandler shellCommandHandler) {
-        mShellCommandHandler = shellCommandHandler;
-    }
-
-    /**
      * Adds a new configuration listener. The configuration change callbacks are not made in any
      * particular order.
      */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInit.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInit.java
index c250e03..ac52235 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInit.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInit.java
@@ -52,6 +52,9 @@
      * Adds a callback to the ordered list of callbacks be made when Shell is first started.  This
      * can be used in class constructors when dagger is used to ensure that the initialization order
      * matches the dependency order.
+     *
+     * @param r the callback to be made when Shell is initialized
+     * @param instance used for debugging only
      */
     public <T extends Object> void addInitCallback(Runnable r, T instance) {
         if (mHasInitialized) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
index 5cce6b9..e26c259 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
@@ -20,9 +20,9 @@
 import static android.view.WindowManager.TRANSIT_TO_BACK;
 import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
 
+import static com.android.wm.shell.common.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR;
 import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
 import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_CHILD_TASK_ENTER_PIP;
-import static com.android.wm.shell.splitscreen.StageCoordinator.FLAG_IS_DIVIDER_BAR;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index 08eb2c9..6c65966 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
@@ -64,6 +64,7 @@
 import android.annotation.ColorInt;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.ActivityManager;
 import android.app.ActivityThread;
 import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
@@ -203,14 +204,24 @@
     }
 
     @VisibleForTesting
-    static boolean isRotationSeamless(@NonNull TransitionInfo info,
-            DisplayController displayController) {
+    static int getRotationAnimationHint(@NonNull TransitionInfo.Change displayChange,
+            @NonNull TransitionInfo info, @NonNull DisplayController displayController) {
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
-                "Display is changing, check if it should be seamless.");
-        boolean checkedDisplayLayout = false;
-        boolean hasTask = false;
-        boolean displayExplicitSeamless = false;
-        for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+                "Display is changing, resolve the animation hint.");
+        // The explicit request of display has the highest priority.
+        if (displayChange.getRotationAnimation() == ROTATION_ANIMATION_SEAMLESS) {
+            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
+                    "  display requests explicit seamless");
+            return ROTATION_ANIMATION_SEAMLESS;
+        }
+
+        boolean allTasksSeamless = false;
+        boolean rejectSeamless = false;
+        ActivityManager.RunningTaskInfo topTaskInfo = null;
+        int animationHint = ROTATION_ANIMATION_ROTATE;
+        // Traverse in top-to-bottom order so that the first task is top-most.
+        final int size = info.getChanges().size();
+        for (int i = 0; i < size; ++i) {
             final TransitionInfo.Change change = info.getChanges().get(i);
 
             // Only look at changing things. showing/hiding don't need to rotate.
@@ -223,95 +234,69 @@
                 if ((change.getFlags() & FLAG_DISPLAY_HAS_ALERT_WINDOWS) != 0) {
                     ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
                             "  display has system alert windows, so not seamless.");
-                    return false;
+                    rejectSeamless = true;
                 }
-                displayExplicitSeamless =
-                        change.getRotationAnimation() == ROTATION_ANIMATION_SEAMLESS;
             } else if ((change.getFlags() & FLAG_IS_WALLPAPER) != 0) {
                 if (change.getRotationAnimation() != ROTATION_ANIMATION_SEAMLESS) {
                     ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
                             "  wallpaper is participating but isn't seamless.");
-                    return false;
+                    rejectSeamless = true;
                 }
             } else if (change.getTaskInfo() != null) {
-                hasTask = true;
+                final int anim = change.getRotationAnimation();
+                final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
+                final boolean isTopTask = topTaskInfo == null;
+                if (isTopTask) {
+                    topTaskInfo = taskInfo;
+                    if (anim != ROTATION_ANIMATION_UNSPECIFIED
+                            && anim != ROTATION_ANIMATION_SEAMLESS) {
+                        animationHint = anim;
+                    }
+                }
                 // We only enable seamless rotation if all the visible task windows requested it.
-                if (change.getRotationAnimation() != ROTATION_ANIMATION_SEAMLESS) {
+                if (anim != ROTATION_ANIMATION_SEAMLESS) {
                     ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
                             "  task %s isn't requesting seamless, so not seamless.",
-                            change.getTaskInfo().taskId);
-                    return false;
-                }
-
-                // This is the only way to get display-id currently, so we will check display
-                // capabilities here
-                if (!checkedDisplayLayout) {
-                    // only need to check display once.
-                    checkedDisplayLayout = true;
-                    final DisplayLayout displayLayout = displayController.getDisplayLayout(
-                            change.getTaskInfo().displayId);
-                    // For the upside down rotation we don't rotate seamlessly as the navigation
-                    // bar moves position. Note most apps (using orientation:sensor or user as
-                    // opposed to fullSensor) will not enter the reverse portrait orientation, so
-                    // actually the orientation won't change at all.
-                    int upsideDownRotation = displayLayout.getUpsideDownRotation();
-                    if (change.getStartRotation() == upsideDownRotation
-                            || change.getEndRotation() == upsideDownRotation) {
-                        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
-                                "  rotation involves upside-down portrait, so not seamless.");
-                        return false;
-                    }
-
-                    // If the navigation bar can't change sides, then it will jump when we change
-                    // orientations and we don't rotate seamlessly - unless that is allowed, eg.
-                    // with gesture navigation where the navbar is low-profile enough that this
-                    // isn't very noticeable.
-                    if (!displayLayout.allowSeamlessRotationDespiteNavBarMoving()
-                            && (!(displayLayout.navigationBarCanMove()
-                                    && (change.getStartAbsBounds().width()
-                                            != change.getStartAbsBounds().height())))) {
-                        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
-                                "  nav bar changes sides, so not seamless.");
-                        return false;
-                    }
+                            taskInfo.taskId);
+                    allTasksSeamless = false;
+                } else if (isTopTask) {
+                    allTasksSeamless = true;
                 }
             }
         }
 
-        // ROTATION_ANIMATION_SEAMLESS can only be requested by task or display.
-        if (hasTask || displayExplicitSeamless) {
-            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "  Rotation IS seamless.");
-            return true;
+        if (!allTasksSeamless || rejectSeamless) {
+            return animationHint;
         }
-        return false;
-    }
 
-    /**
-     * Gets the rotation animation for the topmost task. Assumes that seamless is checked
-     * elsewhere, so it will default SEAMLESS to ROTATE.
-     */
-    private int getRotationAnimation(@NonNull TransitionInfo info) {
-        // Traverse in top-to-bottom order so that the first task is top-most
-        for (int i = 0; i < info.getChanges().size(); ++i) {
-            final TransitionInfo.Change change = info.getChanges().get(i);
-
-            // Only look at changing things. showing/hiding don't need to rotate.
-            if (change.getMode() != TRANSIT_CHANGE) continue;
-
-            // This container isn't rotating, so we can ignore it.
-            if (change.getEndRotation() == change.getStartRotation()) continue;
-
-            if (change.getTaskInfo() != null) {
-                final int anim = change.getRotationAnimation();
-                if (anim == ROTATION_ANIMATION_UNSPECIFIED
-                        // Fallback animation for seamless should also be default.
-                        || anim == ROTATION_ANIMATION_SEAMLESS) {
-                    return ROTATION_ANIMATION_ROTATE;
-                }
-                return anim;
-            }
+        // This is the only way to get display-id currently, so check display capabilities here.
+        final DisplayLayout displayLayout = displayController.getDisplayLayout(
+                topTaskInfo.displayId);
+        // For the upside down rotation we don't rotate seamlessly as the navigation bar moves
+        // position. Note most apps (using orientation:sensor or user as opposed to fullSensor)
+        // will not enter the reverse portrait orientation, so actually the orientation won't
+        // change at all.
+        final int upsideDownRotation = displayLayout.getUpsideDownRotation();
+        if (displayChange.getStartRotation() == upsideDownRotation
+                || displayChange.getEndRotation() == upsideDownRotation) {
+            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
+                    "  rotation involves upside-down portrait, so not seamless.");
+            return animationHint;
         }
-        return ROTATION_ANIMATION_ROTATE;
+
+        // If the navigation bar can't change sides, then it will jump when we change orientations
+        // and we don't rotate seamlessly - unless that is allowed, e.g. with gesture navigation
+        // where the navbar is low-profile enough that this isn't very noticeable.
+        if (!displayLayout.allowSeamlessRotationDespiteNavBarMoving()
+                && (!(displayLayout.navigationBarCanMove()
+                        && (displayChange.getStartAbsBounds().width()
+                                != displayChange.getStartAbsBounds().height())))) {
+            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
+                    "  nav bar changes sides, so not seamless.");
+            return animationHint;
+        }
+        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "  Rotation IS seamless.");
+        return ROTATION_ANIMATION_SEAMLESS;
     }
 
     @Override
@@ -354,8 +339,8 @@
 
             if (change.getMode() == TRANSIT_CHANGE && (change.getFlags() & FLAG_IS_DISPLAY) != 0) {
                 if (info.getType() == TRANSIT_CHANGE) {
-                    isSeamlessDisplayChange = isRotationSeamless(info, mDisplayController);
-                    final int anim = getRotationAnimation(info);
+                    final int anim = getRotationAnimationHint(change, info, mDisplayController);
+                    isSeamlessDisplayChange = anim == ROTATION_ANIMATION_SEAMLESS;
                     if (!(isSeamlessDisplayChange || anim == ROTATION_ANIMATION_JUMPCUT)) {
                         startRotationAnimation(startTransaction, change, info, anim, animations,
                                 onAnimFinish);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
index a843b2a..45b69f1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
@@ -162,13 +162,12 @@
                     .setParent(mAnimLeash)
                     .setBLASTLayer()
                     .setSecure(screenshotBuffer.containsSecureLayers())
+                    .setOpaque(true)
                     .setCallsite("ShellRotationAnimation")
                     .setName("RotationLayer")
                     .build();
 
             t.setLayer(mAnimLeash, SCREEN_FREEZE_LAYER_BASE);
-            t.setPosition(mAnimLeash, 0, 0);
-            t.setAlpha(mAnimLeash, 1);
             t.show(mAnimLeash);
 
             final ColorSpace colorSpace = screenshotBuffer.getColorSpace();
@@ -181,6 +180,7 @@
                 mBackColorSurface = new SurfaceControl.Builder(session)
                         .setParent(rootLeash)
                         .setColorLayer()
+                        .setOpaque(true)
                         .setCallsite("ShellRotationAnimation")
                         .setName("BackColorSurface")
                         .build();
@@ -189,7 +189,6 @@
 
                 t.setLayer(mBackColorSurface, -1);
                 t.setColor(mBackColorSurface, new float[]{mStartLuma, mStartLuma, mStartLuma});
-                t.setAlpha(mBackColorSurface, 1);
                 t.show(mBackColorSurface);
             }
 
@@ -242,7 +241,6 @@
         t.setMatrix(mScreenshotLayer,
                 mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
                 mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
-        t.setAlpha(mScreenshotLayer, (float) 1.0);
     }
 
     /**
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 279d57a..9335438 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
@@ -119,6 +119,8 @@
     /** List of possible handlers. Ordered by specificity (eg. tapped back to front). */
     private final ArrayList<TransitionHandler> mHandlers = new ArrayList<>();
 
+    private final ArrayList<TransitionObserver> mObservers = new ArrayList<>();
+
     /** List of {@link Runnable} instances to run when the last active transition has finished.  */
     private final ArrayList<Runnable> mRunWhenIdleQueue = new ArrayList<>();
 
@@ -242,6 +244,16 @@
         mRemoteTransitionHandler.removeFiltered(remoteTransition);
     }
 
+    /** Registers an observer on the lifecycle of transitions. */
+    public void registerObserver(@NonNull TransitionObserver observer) {
+        mObservers.add(observer);
+    }
+
+    /** Unregisters the observer. */
+    public void unregisterObserver(@NonNull TransitionObserver observer) {
+        mObservers.remove(observer);
+    }
+
     /** Boosts the process priority of remote animation player. */
     public static void setRunningRemoteTransitionDelegate(IApplicationThread appThread) {
         if (appThread == null) return;
@@ -407,6 +419,11 @@
                     + Arrays.toString(mActiveTransitions.stream().map(
                             activeTransition -> activeTransition.mToken).toArray()));
         }
+
+        for (int i = 0; i < mObservers.size(); ++i) {
+            mObservers.get(i).onTransitionReady(transitionToken, info, t, finishT);
+        }
+
         if (!info.getRootLeash().isValid()) {
             // Invalid root-leash implies that the transition is empty/no-op, so just do
             // housekeeping and return.
@@ -474,6 +491,10 @@
     }
 
     private void playTransition(@NonNull ActiveTransition active) {
+        for (int i = 0; i < mObservers.size(); ++i) {
+            mObservers.get(i).onTransitionStarting(active.mToken);
+        }
+
         setupAnimHierarchy(active.mInfo, active.mStartT, active.mFinishT);
 
         // If a handler already chose to run this animation, try delegating to it first.
@@ -546,6 +567,10 @@
                 active.mHandler.onTransitionConsumed(
                         active.mToken, abort, abort ? null : active.mFinishT);
             }
+            for (int i = 0; i < mObservers.size(); ++i) {
+                mObservers.get(i).onTransitionMerged(
+                        active.mToken, mActiveTransitions.get(0).mToken);
+            }
             return;
         }
         final ActiveTransition active = mActiveTransitions.get(activeIdx);
@@ -555,6 +580,9 @@
             active.mHandler.onTransitionConsumed(
                     transition, true /* aborted */, null /* finishTransaction */);
         }
+        for (int i = 0; i < mObservers.size(); ++i) {
+            mObservers.get(i).onTransitionFinished(active.mToken, active.mAborted);
+        }
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
                 "Transition animation finished (abort=%b), notifying core %s", abort, transition);
         // Merge all relevant transactions together
@@ -593,6 +621,9 @@
                         transition, true /* aborted */, null /* finishTransaction */);
             }
             mOrganizer.finishTransition(aborted.mToken, null /* wct */, null /* wctCB */);
+            for (int i = 0; i < mObservers.size(); ++i) {
+                mObservers.get(i).onTransitionFinished(active.mToken, true);
+            }
         }
         if (mActiveTransitions.size() <= activeIdx) {
             ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "All active transition animations "
@@ -792,6 +823,52 @@
         default void setAnimScaleSetting(float scale) {}
     }
 
+    /**
+     * Interface for something that needs to know the lifecycle of some transitions, but never
+     * handles any transition by itself.
+     */
+    public interface TransitionObserver {
+        /**
+         * Called when the transition is ready to play. It may later be merged into other
+         * transitions. Note this doesn't mean this transition will be played anytime soon.
+         *
+         * @param transition the unique token of this transition
+         * @param startTransaction the transaction given to the handler to be applied before the
+         *                         transition animation. This will be applied when the transition
+         *                         handler that handles this transition starts the transition.
+         * @param finishTransaction the transaction given to the handler to be applied after the
+         *                          transition animation. The Transition system will apply it when
+         *                          finishCallback is called by the transition handler.
+         */
+        void onTransitionReady(@NonNull IBinder transition, @NonNull TransitionInfo info,
+                @NonNull SurfaceControl.Transaction startTransaction,
+                @NonNull SurfaceControl.Transaction finishTransaction);
+
+        /**
+         * Called when the transition is starting to play. It isn't called for merged transitions.
+         *
+         * @param transition the unique token of this transition
+         */
+        void onTransitionStarting(@NonNull IBinder transition);
+
+        /**
+         * Called when a transition is merged into another transition. There won't be any following
+         * lifecycle calls for the merged transition.
+         *
+         * @param merged the unique token of the transition that's merged to another one
+         * @param playing the unique token of the transition that accepts the merge
+         */
+        void onTransitionMerged(@NonNull IBinder merged, @NonNull IBinder playing);
+
+        /**
+         * Called when the transition is finished. This isn't called for merged transitions.
+         *
+         * @param transition the unique token of this transition
+         * @param aborted {@code true} if this transition is aborted; {@code false} otherwise.
+         */
+        void onTransitionFinished(@NonNull IBinder transition, boolean aborted);
+    }
+
     @BinderThread
     private class TransitionPlayerImpl extends ITransitionPlayer.Stub {
         @Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
index 08d6c50..e7695926 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
@@ -51,7 +51,6 @@
     private final Choreographer mMainChoreographer;
     private final DisplayController mDisplayController;
     private final SyncTransactionQueue mSyncQueue;
-
     private FreeformTaskTransitionStarter mTransitionStarter;
 
     public CaptionWindowDecorViewModel(
@@ -168,6 +167,14 @@
                 } 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);
+                }
             }
         }
 
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 dc212fc..98b5ee9 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
@@ -161,12 +161,13 @@
      */
     private void setupRootView() {
         View caption = mResult.mRootView.findViewById(R.id.caption);
-
         caption.setOnTouchListener(mOnCaptionTouchListener);
         View maximize = caption.findViewById(R.id.maximize_window);
         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);
     }
 
     void setCaptionColor(int captionColor) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
index 7517e8a..f865649 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
@@ -59,6 +59,7 @@
 
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.compatui.CompatUIController;
+import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellInit;
 
 import org.junit.Before;
@@ -85,10 +86,12 @@
     @Mock
     private CompatUIController mCompatUI;
     @Mock
-    private ShellInit mShellInit;
+    private ShellExecutor mTestExecutor;
+    @Mock
+    private ShellCommandHandler mShellCommandHandler;
 
-    ShellTaskOrganizer mOrganizer;
-    private final ShellExecutor mTestExecutor = mock(ShellExecutor.class);
+    private ShellTaskOrganizer mOrganizer;
+    private ShellInit mShellInit;
 
     private class TrackingTaskListener implements ShellTaskOrganizer.TaskListener {
         final ArrayList<RunningTaskInfo> appeared = new ArrayList<>();
@@ -132,8 +135,11 @@
             doReturn(ParceledListSlice.<TaskAppearedInfo>emptyList())
                     .when(mTaskOrganizerController).registerTaskOrganizer(any());
         } catch (RemoteException e) {}
-        mOrganizer = spy(new ShellTaskOrganizer(mShellInit, mTaskOrganizerController,
-                mCompatUI, Optional.empty(), Optional.empty(), mTestExecutor));
+        mShellInit = spy(new ShellInit(mTestExecutor));
+        mOrganizer = spy(new ShellTaskOrganizer(mShellInit, mShellCommandHandler,
+                mTaskOrganizerController, mCompatUI, Optional.empty(), Optional.empty(),
+                mTestExecutor));
+        mShellInit.init();
     }
 
     @Test
@@ -142,9 +148,12 @@
     }
 
     @Test
-    public void testRegisterOrganizer_sendRegisterTaskOrganizer() throws RemoteException {
-        mOrganizer.registerOrganizer();
+    public void instantiate_addDumpCallback() {
+        verify(mShellCommandHandler, times(1)).addDumpCallback(any(), any());
+    }
 
+    @Test
+    public void testInit_sendRegisterTaskOrganizer() throws RemoteException {
         verify(mTaskOrganizerController).registerTaskOrganizer(any(ITaskOrganizer.class));
     }
 
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 ba81602..5b3b8fd 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
@@ -29,6 +29,7 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -61,6 +62,7 @@
 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.ShellInit;
 
 import org.junit.Before;
 import org.junit.Ignore;
@@ -81,6 +83,7 @@
 
     private static final String ANIMATION_ENABLED = "1";
     private final TestShellExecutor mShellExecutor = new TestShellExecutor();
+    private ShellInit mShellInit;
 
     @Rule
     public TestableContext mContext =
@@ -110,10 +113,12 @@
         Settings.Global.putString(mContentResolver, Settings.Global.ENABLE_BACK_ANIMATION,
                 ANIMATION_ENABLED);
         mTestableLooper = TestableLooper.get(this);
-        mController = new BackAnimationController(
+        mShellInit = spy(new ShellInit(mShellExecutor));
+        mController = new BackAnimationController(mShellInit,
                 mShellExecutor, new Handler(mTestableLooper.getLooper()), mTransaction,
                 mActivityTaskManager, mContext,
                 mContentResolver);
+        mShellInit.init();
         mEventTime = 0;
         mShellExecutor.flushAll();
     }
@@ -160,6 +165,11 @@
     }
 
     @Test
+    public void instantiateController_addInitCallback() {
+        verify(mShellInit, times(1)).addInitCallback(any(), any());
+    }
+
+    @Test
     @Ignore("b/207481538")
     public void crossActivity_screenshotAttachedAndVisible() {
         SurfaceControl screenshotSurface = new SurfaceControl();
@@ -233,10 +243,12 @@
     public void animationDisabledFromSettings() throws RemoteException {
         // Toggle the setting off
         Settings.Global.putString(mContentResolver, Settings.Global.ENABLE_BACK_ANIMATION, "0");
-        mController = new BackAnimationController(
+        ShellInit shellInit = new ShellInit(mShellExecutor);
+        mController = new BackAnimationController(shellInit,
                 mShellExecutor, new Handler(mTestableLooper.getLooper()), mTransaction,
                 mActivityTaskManager, mContext,
                 mContentResolver);
+        shellInit.init();
         mController.setBackToLauncherCallback(mIOnBackInvokedCallback);
 
         RemoteAnimationTarget animationTarget = createAnimationTarget();
@@ -272,9 +284,14 @@
         // the previous transition is finished.
         doMotionEvent(MotionEvent.ACTION_DOWN, 0);
         verifyNoMoreInteractions(mIOnBackInvokedCallback);
+        mController.onBackToLauncherAnimationFinished();
+
+        // Verify that more events from a rejected swipe cannot start animation.
+        doMotionEvent(MotionEvent.ACTION_MOVE, 100);
+        doMotionEvent(MotionEvent.ACTION_UP, 0);
+        verifyNoMoreInteractions(mIOnBackInvokedCallback);
 
         // Verify that we start accepting gestures again once transition finishes.
-        mController.onBackToLauncherAnimationFinished();
         doMotionEvent(MotionEvent.ACTION_DOWN, 0);
         doMotionEvent(MotionEvent.ACTION_MOVE, 100);
         verify(mIOnBackInvokedCallback).onBackStarted();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayLayoutTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayLayoutTest.java
index 514390f..d467b39 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayLayoutTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayLayoutTest.java
@@ -47,6 +47,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
 
 /**
  * Tests for {@link DisplayLayout}.
@@ -62,6 +63,7 @@
     public void setup() {
         mMockitoSession = mockitoSession()
                 .initMocks(this)
+                .strictness(Strictness.WARN)
                 .mockStatic(SystemBarUtils.class)
                 .startMocking();
     }
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 828c13e..6292130 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
@@ -29,6 +29,7 @@
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
@@ -54,6 +55,7 @@
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.compatui.letterboxedu.LetterboxEduWindowManager;
 import com.android.wm.shell.sysui.ShellController;
+import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.transition.Transitions;
 
 import org.junit.Before;
@@ -79,6 +81,7 @@
     private static final int TASK_ID = 12;
 
     private CompatUIController mController;
+    private ShellInit mShellInit;
     private @Mock ShellController mMockShellController;
     private @Mock DisplayController mMockDisplayController;
     private @Mock DisplayInsetsController mMockDisplayInsetsController;
@@ -107,9 +110,10 @@
         doReturn(TASK_ID).when(mMockLetterboxEduLayout).getTaskId();
         doReturn(true).when(mMockLetterboxEduLayout).createLayout(anyBoolean());
         doReturn(true).when(mMockLetterboxEduLayout).updateCompatInfo(any(), any(), anyBoolean());
-        mController = new CompatUIController(mContext, mMockShellController, mMockDisplayController,
-                mMockDisplayInsetsController, mMockImeController, mMockSyncQueue, mMockExecutor,
-                mMockTransitionsLazy) {
+        mShellInit = spy(new ShellInit(mMockExecutor));
+        mController = new CompatUIController(mContext, mShellInit, mMockShellController,
+                mMockDisplayController, mMockDisplayInsetsController, mMockImeController,
+                mMockSyncQueue, mMockExecutor, mMockTransitionsLazy) {
             @Override
             CompatUIWindowManager createCompatUiWindowManager(Context context, TaskInfo taskInfo,
                     ShellTaskOrganizer.TaskListener taskListener) {
@@ -122,10 +126,16 @@
                 return mMockLetterboxEduLayout;
             }
         };
+        mShellInit.init();
         spyOn(mController);
     }
 
     @Test
+    public void instantiateController_addInitCallback() {
+        verify(mShellInit, times(1)).addInitCallback(any(), any());
+    }
+
+    @Test
     public void instantiateController_registerKeyguardChangeListener() {
         verify(mMockShellController, times(1)).addKeyguardChangeListener(any());
     }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutControllerTest.java
index dcc504a..6c301bb 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutControllerTest.java
@@ -17,7 +17,9 @@
 package com.android.wm.shell.hidedisplaycutout;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
@@ -29,7 +31,10 @@
 import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellController;
+import com.android.wm.shell.sysui.ShellInit;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -45,17 +50,32 @@
             InstrumentationRegistry.getInstrumentation().getTargetContext(), null);
 
     @Mock
+    private ShellCommandHandler mShellCommandHandler;
+    @Mock
     private ShellController mShellController;
     @Mock
     private HideDisplayCutoutOrganizer mMockDisplayAreaOrganizer;
 
     private HideDisplayCutoutController mHideDisplayCutoutController;
+    private ShellInit mShellInit;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        mHideDisplayCutoutController = new HideDisplayCutoutController(
-                mContext, mShellController, mMockDisplayAreaOrganizer);
+        mShellInit = spy(new ShellInit(mock(ShellExecutor.class)));
+        mHideDisplayCutoutController = new HideDisplayCutoutController(mContext, mShellInit,
+                mShellCommandHandler, mShellController, mMockDisplayAreaOrganizer);
+        mShellInit.init();
+    }
+
+    @Test
+    public void instantiateController_addInitCallback() {
+        verify(mShellInit, times(1)).addInitCallback(any(), any());
+    }
+
+    @Test
+    public void instantiateController_registerDumpCallback() {
+        verify(mShellCommandHandler, times(1)).addDumpCallback(any(), any());
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java
index a919ad0..ecfb427 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java
@@ -49,6 +49,7 @@
 import com.android.wm.shell.common.DisplayInsetsController;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellInit;
 
 import org.junit.Before;
@@ -74,6 +75,7 @@
     @Mock private WindowContainerTransaction mTransaction;
     @Mock private KidsModeSettingsObserver mObserver;
     @Mock private ShellInit mShellInit;
+    @Mock private ShellCommandHandler mShellCommandHandler;
     @Mock private DisplayInsetsController mDisplayInsetsController;
 
     KidsModeTaskOrganizer mOrganizer;
@@ -87,14 +89,20 @@
         } catch (RemoteException e) {
         }
         // NOTE: KidsModeTaskOrganizer should have a null CompatUIController.
-        mOrganizer = spy(new KidsModeTaskOrganizer(mContext, mTaskOrganizerController,
-                mSyncTransactionQueue, mDisplayController, mDisplayInsetsController,
-                Optional.empty(), Optional.empty(), mObserver, mTestExecutor, mHandler));
+        mOrganizer = spy(new KidsModeTaskOrganizer(mContext, mShellInit, mShellCommandHandler,
+                mTaskOrganizerController, mSyncTransactionQueue, mDisplayController,
+                mDisplayInsetsController, Optional.empty(), Optional.empty(), mObserver,
+                mTestExecutor, mHandler));
         doReturn(mTransaction).when(mOrganizer).getWindowContainerTransaction();
         doReturn(new InsetsState()).when(mDisplayController).getInsetsState(DEFAULT_DISPLAY);
     }
 
     @Test
+    public void instantiateController_addInitCallback() {
+        verify(mShellInit, times(1)).addInitCallback(any(), any());
+    }
+
+    @Test
     public void testKidsModeOn() {
         doReturn(true).when(mObserver).isEnabled();
 
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 dbf93ae..90645ce 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
@@ -36,7 +36,6 @@
 
 import android.graphics.Rect;
 import android.os.Handler;
-import android.os.UserHandle;
 import android.testing.AndroidTestingRunner;
 import android.util.ArrayMap;
 import android.view.Display;
@@ -49,7 +48,9 @@
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.TaskStackListenerImpl;
+import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellController;
+import com.android.wm.shell.sysui.ShellInit;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -61,18 +62,20 @@
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 public class OneHandedControllerTest extends OneHandedTestCase {
-    private int mCurrentUser = UserHandle.myUserId();
 
     Display mDisplay;
     OneHandedAccessibilityUtil mOneHandedAccessibilityUtil;
     OneHandedController mSpiedOneHandedController;
     OneHandedTimeoutHandler mSpiedTimeoutHandler;
     OneHandedState mSpiedTransitionState;
+    ShellInit mShellInit;
 
     @Mock
+    ShellCommandHandler mMockShellCommandHandler;
+    @Mock
     ShellController mMockShellController;
     @Mock
-    DisplayLayout mDisplayLayout;
+    DisplayLayout mMockDisplayLayout;
     @Mock
     DisplayController mMockDisplayController;
     @Mock
@@ -102,7 +105,7 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mDisplay = mContext.getDisplay();
-        mDisplayLayout = Mockito.mock(DisplayLayout.class);
+        mMockDisplayLayout = Mockito.mock(DisplayLayout.class);
         mSpiedTimeoutHandler = spy(new OneHandedTimeoutHandler(mMockShellMainExecutor));
         mSpiedTransitionState = spy(new OneHandedState());
 
@@ -122,11 +125,14 @@
 
         when(mMockDisplayAreaOrganizer.getLastDisplayBounds()).thenReturn(
                 new Rect(0, 0, 1080, 2400));
-        when(mMockDisplayAreaOrganizer.getDisplayLayout()).thenReturn(mDisplayLayout);
+        when(mMockDisplayAreaOrganizer.getDisplayLayout()).thenReturn(mMockDisplayLayout);
 
+        mShellInit = spy(new ShellInit(mMockShellMainExecutor));
         mOneHandedAccessibilityUtil = new OneHandedAccessibilityUtil(mContext);
         mSpiedOneHandedController = spy(new OneHandedController(
                 mContext,
+                mShellInit,
+                mMockShellCommandHandler,
                 mMockShellController,
                 mMockDisplayController,
                 mMockDisplayAreaOrganizer,
@@ -141,6 +147,17 @@
                 mMockShellMainExecutor,
                 mMockShellMainHandler)
         );
+        mShellInit.init();
+    }
+
+    @Test
+    public void instantiateController_addInitCallback() {
+        verify(mShellInit, times(1)).addInitCallback(any(), any());
+    }
+
+    @Test
+    public void instantiateController_registerDumpCallback() {
+        verify(mMockShellCommandHandler, times(1)).addDumpCallback(any(), any());
     }
 
     @Test
@@ -308,9 +325,9 @@
 
     @Test
     public void testRotation90CanNotStartOneHanded() {
-        mDisplayLayout.rotateTo(mContext.getResources(), Surface.ROTATION_90);
+        mMockDisplayLayout.rotateTo(mContext.getResources(), Surface.ROTATION_90);
         mSpiedTransitionState.setState(STATE_NONE);
-        when(mDisplayLayout.isLandscape()).thenReturn(true);
+        when(mMockDisplayLayout.isLandscape()).thenReturn(true);
         mSpiedOneHandedController.setOneHandedEnabled(true);
         mSpiedOneHandedController.setLockedDisabled(false /* locked */, false /* enabled */);
         mSpiedOneHandedController.startOneHanded();
@@ -320,10 +337,10 @@
 
     @Test
     public void testRotation180CanStartOneHanded() {
-        mDisplayLayout.rotateTo(mContext.getResources(), Surface.ROTATION_180);
+        mMockDisplayLayout.rotateTo(mContext.getResources(), Surface.ROTATION_180);
         mSpiedTransitionState.setState(STATE_NONE);
         when(mMockDisplayAreaOrganizer.isReady()).thenReturn(true);
-        when(mDisplayLayout.isLandscape()).thenReturn(false);
+        when(mMockDisplayLayout.isLandscape()).thenReturn(false);
         mSpiedOneHandedController.setOneHandedEnabled(true);
         mSpiedOneHandedController.setLockedDisabled(false /* locked */, false /* enabled */);
         mSpiedOneHandedController.startOneHanded();
@@ -333,9 +350,9 @@
 
     @Test
     public void testRotation270CanNotStartOneHanded() {
-        mDisplayLayout.rotateTo(mContext.getResources(), Surface.ROTATION_270);
+        mMockDisplayLayout.rotateTo(mContext.getResources(), Surface.ROTATION_270);
         mSpiedTransitionState.setState(STATE_NONE);
-        when(mDisplayLayout.isLandscape()).thenReturn(true);
+        when(mMockDisplayLayout.isLandscape()).thenReturn(true);
         mSpiedOneHandedController.setOneHandedEnabled(true);
         mSpiedOneHandedController.setLockedDisabled(false /* locked */, false /* enabled */);
         mSpiedOneHandedController.startOneHanded();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedStateTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedStateTest.java
index e6a8220..a39bdf0 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedStateTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedStateTest.java
@@ -41,7 +41,9 @@
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.TaskStackListenerImpl;
+import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellController;
+import com.android.wm.shell.sysui.ShellInit;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -61,6 +63,10 @@
     OneHandedState mSpiedState;
 
     @Mock
+    ShellInit mMockShellInit;
+    @Mock
+    ShellCommandHandler mMockShellCommandHandler;
+    @Mock
     ShellController mMockShellController;
     @Mock
     DisplayController mMockDisplayController;
@@ -111,6 +117,8 @@
         mOneHandedAccessibilityUtil = new OneHandedAccessibilityUtil(mContext);
         mSpiedOneHandedController = spy(new OneHandedController(
                 mContext,
+                mMockShellInit,
+                mMockShellCommandHandler,
                 mMockShellController,
                 mMockDisplayController,
                 mMockDisplayAreaOrganizer,
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 f192514..9ed8d84 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
@@ -55,7 +55,9 @@
 import com.android.wm.shell.pip.PipTaskOrganizer;
 import com.android.wm.shell.pip.PipTransitionController;
 import com.android.wm.shell.pip.PipTransitionState;
+import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellController;
+import com.android.wm.shell.sysui.ShellInit;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -74,7 +76,9 @@
 @TestableLooper.RunWithLooper
 public class PipControllerTest extends ShellTestCase {
     private PipController mPipController;
+    private ShellInit mShellInit;
 
+    @Mock private ShellCommandHandler mMockShellCommandHandler;
     @Mock private ShellController mMockShellController;
     @Mock private DisplayController mMockDisplayController;
     @Mock private PhonePipMenuController mMockPhonePipMenuController;
@@ -105,19 +109,31 @@
             ((Runnable) invocation.getArgument(0)).run();
             return null;
         }).when(mMockExecutor).execute(any());
-        mPipController = new PipController(mContext, mMockShellController, mMockDisplayController,
-                mMockPipAppOpsListener, mMockPipBoundsAlgorithm,
-                mMockPipKeepClearAlgorithm,
+        mShellInit = spy(new ShellInit(mMockExecutor));
+        mPipController = new PipController(mContext, mShellInit, mMockShellCommandHandler,
+                mMockShellController, mMockDisplayController, mMockPipAppOpsListener,
+                mMockPipBoundsAlgorithm, mMockPipKeepClearAlgorithm,
                 mMockPipBoundsState, mMockPipMotionHelper, mMockPipMediaController,
                 mMockPhonePipMenuController, mMockPipTaskOrganizer, mMockPipTransitionState,
                 mMockPipTouchHandler, mMockPipTransitionController, mMockWindowManagerShellWrapper,
                 mMockTaskStackListener, mPipParamsChangedForwarder,
                 mMockOneHandedController, mMockExecutor);
+        mShellInit.init();
         when(mMockPipBoundsAlgorithm.getSnapAlgorithm()).thenReturn(mMockPipSnapAlgorithm);
         when(mMockPipTouchHandler.getMotionHelper()).thenReturn(mMockPipMotionHelper);
     }
 
     @Test
+    public void instantiatePipController_addInitCallback() {
+        verify(mShellInit, times(1)).addInitCallback(any(), any());
+    }
+
+    @Test
+    public void instantiateController_registerDumpCallback() {
+        verify(mMockShellCommandHandler, times(1)).addDumpCallback(any(), any());
+    }
+
+    @Test
     public void instantiatePipController_registerConfigChangeListener() {
         verify(mMockShellController, times(1)).addConfigurationChangeListener(any());
     }
@@ -149,9 +165,10 @@
         when(mockPackageManager.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)).thenReturn(false);
         when(spyContext.getPackageManager()).thenReturn(mockPackageManager);
 
-        assertNull(PipController.create(spyContext, mMockShellController, mMockDisplayController,
-                mMockPipAppOpsListener, mMockPipBoundsAlgorithm,
-                mMockPipKeepClearAlgorithm,
+        ShellInit shellInit = new ShellInit(mMockExecutor);
+        assertNull(PipController.create(spyContext, shellInit, mMockShellCommandHandler,
+                mMockShellController, mMockDisplayController, mMockPipAppOpsListener,
+                mMockPipBoundsAlgorithm, mMockPipKeepClearAlgorithm,
                 mMockPipBoundsState, mMockPipMotionHelper, mMockPipMediaController,
                 mMockPhonePipMenuController, mMockPipTaskOrganizer, mMockPipTransitionState,
                 mMockPipTouchHandler, mMockPipTransitionController, mMockWindowManagerShellWrapper,
@@ -217,7 +234,7 @@
         mPipController.mDisplaysChangedListener.onDisplayConfigurationChanged(
                 displayId, new Configuration());
 
-        verify(mMockPipMotionHelper).movePip(any(Rect.class));
+        verify(mMockPipTaskOrganizer).scheduleFinishResizePip(any(Rect.class));
     }
 
     @Test
@@ -233,7 +250,7 @@
         mPipController.mDisplaysChangedListener.onDisplayConfigurationChanged(
                 displayId, new Configuration());
 
-        verify(mMockPipMotionHelper, never()).movePip(any(Rect.class));
+        verify(mMockPipTaskOrganizer, never()).scheduleFinishResizePip(any(Rect.class));
     }
 
     @Test
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 d406a4e..81bb609 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
@@ -23,7 +23,9 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.isA;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.reset;
@@ -48,6 +50,7 @@
 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.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.util.GroupedRecentTaskInfo;
 import com.android.wm.shell.util.SplitBounds;
@@ -73,21 +76,35 @@
     @Mock
     private TaskStackListenerImpl mTaskStackListener;
     @Mock
-    private ShellInit mShellInit;
+    private ShellCommandHandler mShellCommandHandler;
 
     private ShellTaskOrganizer mShellTaskOrganizer;
     private RecentTasksController mRecentTasksController;
+    private ShellInit mShellInit;
     private ShellExecutor mMainExecutor;
 
     @Before
     public void setUp() {
         mMainExecutor = new TestShellExecutor();
         when(mContext.getPackageManager()).thenReturn(mock(PackageManager.class));
+        mShellInit = spy(new ShellInit(mMainExecutor));
         mRecentTasksController = spy(new RecentTasksController(mContext, mShellInit,
-                mTaskStackListener, mMainExecutor));
-        mShellTaskOrganizer = new ShellTaskOrganizer(mShellInit,
+                mShellCommandHandler, mTaskStackListener, mMainExecutor));
+        mShellTaskOrganizer = new ShellTaskOrganizer(mShellInit, mShellCommandHandler,
                 null /* sizeCompatUI */, Optional.empty(), Optional.of(mRecentTasksController),
                 mMainExecutor);
+        mShellInit.init();
+    }
+
+    @Test
+    public void instantiateController_addInitCallback() {
+        verify(mShellInit, times(1)).addInitCallback(any(), isA(RecentTasksController.class));
+    }
+
+    @Test
+    public void instantiateController_addDumpCallback() {
+        verify(mShellCommandHandler, times(1)).addDumpCallback(any(),
+                isA(RecentTasksController.class));
     }
 
     @Test
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 10788f9..5a68361 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
@@ -20,12 +20,14 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 
+import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
@@ -53,6 +55,7 @@
 import com.android.wm.shell.common.TransactionPool;
 import com.android.wm.shell.draganddrop.DragAndDropController;
 import com.android.wm.shell.recents.RecentTasksController;
+import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellController;
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.transition.Transitions;
@@ -72,8 +75,9 @@
 @RunWith(AndroidJUnit4.class)
 public class SplitScreenControllerTests extends ShellTestCase {
 
-    @Mock ShellController mShellController;
     @Mock ShellInit mShellInit;
+    @Mock ShellController mShellController;
+    @Mock ShellCommandHandler mShellCommandHandler;
     @Mock ShellTaskOrganizer mTaskOrganizer;
     @Mock SyncTransactionQueue mSyncQueue;
     @Mock RootTaskDisplayAreaOrganizer mRootTDAOrganizer;
@@ -93,9 +97,10 @@
     public void setup() {
         MockitoAnnotations.initMocks(this);
         mSplitScreenController = spy(new SplitScreenController(mContext, mShellInit,
-                mShellController, mTaskOrganizer, mSyncQueue, mRootTDAOrganizer, mDisplayController,
-                mDisplayImeController, mDisplayInsetsController, mDragAndDropController,
-                mTransitions, mTransactionPool, mIconProvider, mRecentTasks, mMainExecutor));
+                mShellCommandHandler, mShellController, mTaskOrganizer, mSyncQueue,
+                mRootTDAOrganizer, mDisplayController, mDisplayImeController,
+                mDisplayInsetsController, mDragAndDropController, mTransitions, mTransactionPool,
+                mIconProvider, mRecentTasks, mMainExecutor));
     }
 
     @Test
@@ -104,14 +109,31 @@
     }
 
     @Test
+    public void instantiateController_registerDumpCallback() {
+        doReturn(mMainExecutor).when(mTaskOrganizer).getExecutor();
+        when(mDisplayController.getDisplayLayout(anyInt())).thenReturn(new DisplayLayout());
+        mSplitScreenController.onInit();
+        verify(mShellCommandHandler, times(1)).addDumpCallback(any(), any());
+    }
+
+    @Test
+    public void instantiateController_registerCommandCallback() {
+        doReturn(mMainExecutor).when(mTaskOrganizer).getExecutor();
+        when(mDisplayController.getDisplayLayout(anyInt())).thenReturn(new DisplayLayout());
+        mSplitScreenController.onInit();
+        verify(mShellCommandHandler, times(1)).addCommandCallback(eq("splitscreen"), any(), any());
+    }
+
+    @Test
     public void testControllerRegistersKeyguardChangeListener() {
+        doReturn(mMainExecutor).when(mTaskOrganizer).getExecutor();
         when(mDisplayController.getDisplayLayout(anyInt())).thenReturn(new DisplayLayout());
         mSplitScreenController.onInit();
         verify(mShellController, times(1)).addKeyguardChangeListener(any());
     }
 
     @Test
-    public void testIsLaunchingAdjacently_notInSplitScreen() {
+    public void testShouldAddMultipleTaskFlag_notInSplitScreen() {
         doReturn(false).when(mSplitScreenController).isSplitScreenVisible();
         doReturn(true).when(mSplitScreenController).isValidToEnterSplitScreen(any());
 
@@ -120,7 +142,7 @@
         ActivityManager.RunningTaskInfo focusTaskInfo =
                 createTaskInfo(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, startIntent);
         doReturn(focusTaskInfo).when(mSplitScreenController).getFocusingTaskInfo();
-        assertTrue(mSplitScreenController.isLaunchingAdjacently(
+        assertTrue(mSplitScreenController.shouldAddMultipleTaskFlag(
                 startIntent, SPLIT_POSITION_TOP_OR_LEFT));
 
         // Verify launching different activity returns false.
@@ -128,28 +150,40 @@
         focusTaskInfo =
                 createTaskInfo(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, diffIntent);
         doReturn(focusTaskInfo).when(mSplitScreenController).getFocusingTaskInfo();
-        assertFalse(mSplitScreenController.isLaunchingAdjacently(
+        assertFalse(mSplitScreenController.shouldAddMultipleTaskFlag(
                 startIntent, SPLIT_POSITION_TOP_OR_LEFT));
     }
 
     @Test
-    public void testIsLaunchingAdjacently_inSplitScreen() {
+    public void testShouldAddMultipleTaskFlag_inSplitScreen() {
         doReturn(true).when(mSplitScreenController).isSplitScreenVisible();
-
-        // Verify launching the same activity returns true.
         Intent startIntent = createStartIntent("startActivity");
-        ActivityManager.RunningTaskInfo pairingTaskInfo =
+        ActivityManager.RunningTaskInfo sameTaskInfo =
                 createTaskInfo(WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD, startIntent);
-        doReturn(pairingTaskInfo).when(mSplitScreenController).getTaskInfo(anyInt());
-        assertTrue(mSplitScreenController.isLaunchingAdjacently(
+        Intent diffIntent = createStartIntent("diffActivity");
+        ActivityManager.RunningTaskInfo differentTaskInfo =
+                createTaskInfo(WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD, diffIntent);
+
+        // Verify launching the same activity return false.
+        doReturn(sameTaskInfo).when(mSplitScreenController)
+                .getTaskInfo(SPLIT_POSITION_TOP_OR_LEFT);
+        assertFalse(mSplitScreenController.shouldAddMultipleTaskFlag(
                 startIntent, SPLIT_POSITION_TOP_OR_LEFT));
 
-        // Verify launching different activity returns false.
-        Intent diffIntent = createStartIntent("diffActivity");
-        pairingTaskInfo =
-                createTaskInfo(WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD, diffIntent);
-        doReturn(pairingTaskInfo).when(mSplitScreenController).getTaskInfo(anyInt());
-        assertFalse(mSplitScreenController.isLaunchingAdjacently(
+        // Verify launching the same activity as adjacent returns true.
+        doReturn(differentTaskInfo).when(mSplitScreenController)
+                .getTaskInfo(SPLIT_POSITION_TOP_OR_LEFT);
+        doReturn(sameTaskInfo).when(mSplitScreenController)
+                .getTaskInfo(SPLIT_POSITION_BOTTOM_OR_RIGHT);
+        assertTrue(mSplitScreenController.shouldAddMultipleTaskFlag(
+                startIntent, SPLIT_POSITION_TOP_OR_LEFT));
+
+        // Verify launching different activity from adjacent returns false.
+        doReturn(differentTaskInfo).when(mSplitScreenController)
+                .getTaskInfo(SPLIT_POSITION_TOP_OR_LEFT);
+        doReturn(differentTaskInfo).when(mSplitScreenController)
+                .getTaskInfo(SPLIT_POSITION_BOTTOM_OR_RIGHT);
+        assertFalse(mSplitScreenController.shouldAddMultipleTaskFlag(
                 startIntent, SPLIT_POSITION_TOP_OR_LEFT));
     }
 
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 02311ba..39e58ff 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
@@ -45,6 +45,8 @@
     @Mock
     private ShellInit mShellInit;
     @Mock
+    private ShellCommandHandler mShellCommandHandler;
+    @Mock
     private ShellExecutor mExecutor;
 
     private ShellController mController;
@@ -56,7 +58,7 @@
         MockitoAnnotations.initMocks(this);
         mKeyguardChangeListener = new TestKeyguardChangeListener();
         mConfigChangeListener = new TestConfigurationChangeListener();
-        mController = new ShellController(mShellInit, mExecutor);
+        mController = new ShellController(mShellInit, mShellCommandHandler, mExecutor);
         mController.onConfigurationChanged(getConfigurationCopy());
     }
 
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 388792b..c6492be 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
@@ -22,6 +22,7 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE;
 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
 import static android.view.WindowManager.TRANSIT_CHANGE;
@@ -43,11 +44,13 @@
 import static org.junit.Assert.assertNull;
 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;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -59,8 +62,6 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.RemoteException;
-import android.view.IDisplayWindowListener;
-import android.view.IWindowManager;
 import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.WindowManager;
@@ -82,6 +83,7 @@
 import com.android.wm.shell.ShellTestCase;
 import com.android.wm.shell.TestShellExecutor;
 import com.android.wm.shell.common.DisplayController;
+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.ShellInit;
@@ -89,6 +91,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.InOrder;
 
 import java.util.ArrayList;
 
@@ -551,64 +554,77 @@
         final @Surface.Rotation int upsideDown = displays
                 .getDisplayLayout(DEFAULT_DISPLAY).getUpsideDownRotation();
 
+        TransitionInfo.Change displayChange = new ChangeBuilder(TRANSIT_CHANGE)
+                .setFlags(FLAG_IS_DISPLAY).setRotate().build();
+        // Set non-square display so nav bar won't be allowed to move.
+        displayChange.getStartAbsBounds().set(0, 0, 1000, 2000);
         final TransitionInfo normalDispRotate = new TransitionInfoBuilder(TRANSIT_CHANGE)
-                .addChange(new ChangeBuilder(TRANSIT_CHANGE).setFlags(FLAG_IS_DISPLAY).setRotate()
-                        .build())
+                .addChange(displayChange)
                 .addChange(new ChangeBuilder(TRANSIT_CHANGE).setTask(taskInfo).setRotate().build())
                 .build();
-        assertFalse(DefaultTransitionHandler.isRotationSeamless(normalDispRotate, displays));
+        assertEquals(ROTATION_ANIMATION_ROTATE, DefaultTransitionHandler.getRotationAnimationHint(
+                displayChange, normalDispRotate, displays));
 
         // Seamless if all tasks are seamless
         final TransitionInfo rotateSeamless = new TransitionInfoBuilder(TRANSIT_CHANGE)
-                .addChange(new ChangeBuilder(TRANSIT_CHANGE).setFlags(FLAG_IS_DISPLAY).setRotate()
-                        .build())
+                .addChange(displayChange)
                 .addChange(new ChangeBuilder(TRANSIT_CHANGE).setTask(taskInfo)
                         .setRotate(ROTATION_ANIMATION_SEAMLESS).build())
                 .build();
-        assertTrue(DefaultTransitionHandler.isRotationSeamless(rotateSeamless, displays));
+        assertEquals(ROTATION_ANIMATION_SEAMLESS, DefaultTransitionHandler.getRotationAnimationHint(
+                displayChange, rotateSeamless, displays));
 
         // Not seamless if there is PiP (or any other non-seamless task)
         final TransitionInfo pipDispRotate = new TransitionInfoBuilder(TRANSIT_CHANGE)
-                .addChange(new ChangeBuilder(TRANSIT_CHANGE).setFlags(FLAG_IS_DISPLAY).setRotate()
-                        .build())
+                .addChange(displayChange)
                 .addChange(new ChangeBuilder(TRANSIT_CHANGE).setTask(taskInfo)
                         .setRotate(ROTATION_ANIMATION_SEAMLESS).build())
                 .addChange(new ChangeBuilder(TRANSIT_CHANGE).setTask(taskInfoPip)
                         .setRotate().build())
                 .build();
-        assertFalse(DefaultTransitionHandler.isRotationSeamless(pipDispRotate, displays));
-
-        // Not seamless if one of rotations is upside-down
-        final TransitionInfo seamlessUpsideDown = new TransitionInfoBuilder(TRANSIT_CHANGE)
-                .addChange(new ChangeBuilder(TRANSIT_CHANGE).setFlags(FLAG_IS_DISPLAY)
-                        .setRotate(upsideDown, ROTATION_ANIMATION_UNSPECIFIED).build())
-                .addChange(new ChangeBuilder(TRANSIT_CHANGE).setTask(taskInfo)
-                        .setRotate(upsideDown, ROTATION_ANIMATION_SEAMLESS).build())
-                .build();
-        assertFalse(DefaultTransitionHandler.isRotationSeamless(seamlessUpsideDown, displays));
-
-        // Not seamless if system alert windows
-        final TransitionInfo seamlessButAlert = new TransitionInfoBuilder(TRANSIT_CHANGE)
-                .addChange(new ChangeBuilder(TRANSIT_CHANGE).setFlags(
-                        FLAG_IS_DISPLAY | FLAG_DISPLAY_HAS_ALERT_WINDOWS).setRotate().build())
-                .addChange(new ChangeBuilder(TRANSIT_CHANGE).setTask(taskInfo)
-                        .setRotate(ROTATION_ANIMATION_SEAMLESS).build())
-                .build();
-        assertFalse(DefaultTransitionHandler.isRotationSeamless(seamlessButAlert, displays));
+        assertEquals(ROTATION_ANIMATION_ROTATE, DefaultTransitionHandler.getRotationAnimationHint(
+                displayChange, pipDispRotate, displays));
 
         // Not seamless if there is no changed task.
         final TransitionInfo noTask = new TransitionInfoBuilder(TRANSIT_CHANGE)
-                .addChange(new ChangeBuilder(TRANSIT_CHANGE).setFlags(FLAG_IS_DISPLAY)
-                        .setRotate().build())
+                .addChange(displayChange)
                 .build();
-        assertFalse(DefaultTransitionHandler.isRotationSeamless(noTask, displays));
+        assertEquals(ROTATION_ANIMATION_ROTATE, DefaultTransitionHandler.getRotationAnimationHint(
+                displayChange, noTask, displays));
 
-        // Seamless if display is explicitly seamless.
-        final TransitionInfo seamlessDisplay = new TransitionInfoBuilder(TRANSIT_CHANGE)
-                .addChange(new ChangeBuilder(TRANSIT_CHANGE).setFlags(FLAG_IS_DISPLAY)
+        // Not seamless if one of rotations is upside-down
+        displayChange = new ChangeBuilder(TRANSIT_CHANGE).setFlags(FLAG_IS_DISPLAY)
+                .setRotate(upsideDown, ROTATION_ANIMATION_UNSPECIFIED).build();
+        final TransitionInfo seamlessUpsideDown = new TransitionInfoBuilder(TRANSIT_CHANGE)
+                .addChange(displayChange)
+                .addChange(new ChangeBuilder(TRANSIT_CHANGE).setTask(taskInfo)
+                        .setRotate(upsideDown, ROTATION_ANIMATION_SEAMLESS).build())
+                .build();
+        assertEquals(ROTATION_ANIMATION_ROTATE, DefaultTransitionHandler.getRotationAnimationHint(
+                displayChange, seamlessUpsideDown, displays));
+
+        // Not seamless if system alert windows
+        displayChange = new ChangeBuilder(TRANSIT_CHANGE)
+                .setFlags(FLAG_IS_DISPLAY | FLAG_DISPLAY_HAS_ALERT_WINDOWS).setRotate().build();
+        final TransitionInfo seamlessButAlert = new TransitionInfoBuilder(TRANSIT_CHANGE)
+                .addChange(displayChange)
+                .addChange(new ChangeBuilder(TRANSIT_CHANGE).setTask(taskInfo)
                         .setRotate(ROTATION_ANIMATION_SEAMLESS).build())
                 .build();
-        assertTrue(DefaultTransitionHandler.isRotationSeamless(seamlessDisplay, displays));
+        assertEquals(ROTATION_ANIMATION_ROTATE, DefaultTransitionHandler.getRotationAnimationHint(
+                displayChange, seamlessButAlert, displays));
+
+        // Seamless if display is explicitly seamless.
+        displayChange = new ChangeBuilder(TRANSIT_CHANGE).setFlags(FLAG_IS_DISPLAY)
+                .setRotate(ROTATION_ANIMATION_SEAMLESS).build();
+        final TransitionInfo seamlessDisplay = new TransitionInfoBuilder(TRANSIT_CHANGE)
+                .addChange(displayChange)
+                // The animation hint of task will be ignored.
+                .addChange(new ChangeBuilder(TRANSIT_CHANGE).setTask(taskInfo)
+                        .setRotate(ROTATION_ANIMATION_ROTATE).build())
+                .build();
+        assertEquals(ROTATION_ANIMATION_SEAMLESS, DefaultTransitionHandler.getRotationAnimationHint(
+                displayChange, seamlessDisplay, displays));
     }
 
     @Test
@@ -688,6 +704,204 @@
         verify(runnable4, times(1)).run();
     }
 
+    @Test
+    public void testObserverLifecycle_basicTransitionFlow() {
+        Transitions transitions = createTestTransitions();
+        Transitions.TransitionObserver observer = mock(Transitions.TransitionObserver.class);
+        transitions.registerObserver(observer);
+        transitions.replaceDefaultHandlerForTest(mDefaultHandler);
+
+        IBinder transitToken = new Binder();
+        transitions.requestStartTransition(transitToken,
+                new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, null /* remote */));
+        TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN)
+                .addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
+        SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class);
+        SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class);
+        transitions.onTransitionReady(transitToken, info, startT, finishT);
+
+        InOrder observerOrder = inOrder(observer);
+        observerOrder.verify(observer).onTransitionReady(transitToken, info, startT, finishT);
+        observerOrder.verify(observer).onTransitionStarting(transitToken);
+        verify(observer, times(0)).onTransitionFinished(eq(transitToken), anyBoolean());
+        mDefaultHandler.finishAll();
+        mMainExecutor.flushAll();
+        verify(observer).onTransitionFinished(transitToken, false);
+    }
+
+    @Test
+    public void testObserverLifecycle_queueing() {
+        Transitions transitions = createTestTransitions();
+        Transitions.TransitionObserver observer = mock(Transitions.TransitionObserver.class);
+        transitions.registerObserver(observer);
+        transitions.replaceDefaultHandlerForTest(mDefaultHandler);
+
+        IBinder transitToken1 = new Binder();
+        transitions.requestStartTransition(transitToken1,
+                new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, null /* remote */));
+        TransitionInfo info1 = new TransitionInfoBuilder(TRANSIT_OPEN)
+                .addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
+        SurfaceControl.Transaction startT1 = mock(SurfaceControl.Transaction.class);
+        SurfaceControl.Transaction finishT1 = mock(SurfaceControl.Transaction.class);
+        transitions.onTransitionReady(transitToken1, info1, startT1, finishT1);
+        verify(observer).onTransitionReady(transitToken1, info1, startT1, finishT1);
+
+        IBinder transitToken2 = new Binder();
+        transitions.requestStartTransition(transitToken2,
+                new TransitionRequestInfo(TRANSIT_CLOSE, null /* trigger */, null /* remote */));
+        TransitionInfo info2 = new TransitionInfoBuilder(TRANSIT_CLOSE)
+                .addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
+        SurfaceControl.Transaction startT2 = mock(SurfaceControl.Transaction.class);
+        SurfaceControl.Transaction finishT2 = mock(SurfaceControl.Transaction.class);
+        transitions.onTransitionReady(transitToken2, info2, startT2, finishT2);
+        verify(observer, times(1)).onTransitionReady(transitToken2, info2, startT2, finishT2);
+        verify(observer, times(0)).onTransitionStarting(transitToken2);
+        verify(observer, times(0)).onTransitionFinished(eq(transitToken1), anyBoolean());
+        verify(observer, times(0)).onTransitionFinished(eq(transitToken2), anyBoolean());
+
+        mDefaultHandler.finishAll();
+        mMainExecutor.flushAll();
+        // first transition finished
+        verify(observer, times(1)).onTransitionFinished(transitToken1, false);
+        verify(observer, times(1)).onTransitionStarting(transitToken2);
+        verify(observer, times(0)).onTransitionFinished(eq(transitToken2), anyBoolean());
+
+        mDefaultHandler.finishAll();
+        mMainExecutor.flushAll();
+        verify(observer, times(1)).onTransitionFinished(transitToken2, false);
+    }
+
+
+    @Test
+    public void testObserverLifecycle_merging() {
+        Transitions transitions = createTestTransitions();
+        Transitions.TransitionObserver observer = mock(Transitions.TransitionObserver.class);
+        transitions.registerObserver(observer);
+        mDefaultHandler.setSimulateMerge(true);
+        transitions.replaceDefaultHandlerForTest(mDefaultHandler);
+
+        IBinder transitToken1 = new Binder();
+        transitions.requestStartTransition(transitToken1,
+                new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, null /* remote */));
+        TransitionInfo info1 = new TransitionInfoBuilder(TRANSIT_OPEN)
+                .addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
+        SurfaceControl.Transaction startT1 = mock(SurfaceControl.Transaction.class);
+        SurfaceControl.Transaction finishT1 = mock(SurfaceControl.Transaction.class);
+        transitions.onTransitionReady(transitToken1, info1, startT1, finishT1);
+
+        IBinder transitToken2 = new Binder();
+        transitions.requestStartTransition(transitToken2,
+                new TransitionRequestInfo(TRANSIT_CLOSE, null /* trigger */, null /* remote */));
+        TransitionInfo info2 = new TransitionInfoBuilder(TRANSIT_CLOSE)
+                .addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
+        SurfaceControl.Transaction startT2 = mock(SurfaceControl.Transaction.class);
+        SurfaceControl.Transaction finishT2 = mock(SurfaceControl.Transaction.class);
+        transitions.onTransitionReady(transitToken2, info2, startT2, finishT2);
+
+        InOrder observerOrder = inOrder(observer);
+        observerOrder.verify(observer).onTransitionReady(transitToken2, info2, startT2, finishT2);
+        observerOrder.verify(observer).onTransitionMerged(transitToken2, transitToken1);
+        verify(observer, times(0)).onTransitionFinished(eq(transitToken1), anyBoolean());
+
+        mDefaultHandler.finishAll();
+        mMainExecutor.flushAll();
+        // transition + merged all finished.
+        verify(observer, times(1)).onTransitionFinished(transitToken1, false);
+        // Merged transition won't receive any lifecycle calls beyond ready
+        verify(observer, times(0)).onTransitionStarting(transitToken2);
+        verify(observer, times(0)).onTransitionFinished(eq(transitToken2), anyBoolean());
+    }
+
+    @Test
+    public void testObserverLifecycle_mergingAfterQueueing() {
+        Transitions transitions = createTestTransitions();
+        Transitions.TransitionObserver observer = mock(Transitions.TransitionObserver.class);
+        transitions.registerObserver(observer);
+        mDefaultHandler.setSimulateMerge(true);
+        transitions.replaceDefaultHandlerForTest(mDefaultHandler);
+
+        // Make a test handler that only responds to multi-window triggers AND only animates
+        // Change transitions.
+        final WindowContainerTransaction handlerWCT = new WindowContainerTransaction();
+        TestTransitionHandler testHandler = new TestTransitionHandler() {
+            @Override
+            public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
+                    @NonNull SurfaceControl.Transaction startTransaction,
+                    @NonNull SurfaceControl.Transaction finishTransaction,
+                    @NonNull Transitions.TransitionFinishCallback finishCallback) {
+                for (TransitionInfo.Change chg : info.getChanges()) {
+                    if (chg.getMode() == TRANSIT_CHANGE) {
+                        return super.startAnimation(transition, info, startTransaction,
+                                finishTransaction, finishCallback);
+                    }
+                }
+                return false;
+            }
+
+            @Nullable
+            @Override
+            public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
+                    @NonNull TransitionRequestInfo request) {
+                final RunningTaskInfo task = request.getTriggerTask();
+                return (task != null && task.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW)
+                        ? handlerWCT : null;
+            }
+        };
+        transitions.addHandler(testHandler);
+
+        // Use test handler to play an animation
+        IBinder transitToken1 = new Binder();
+        RunningTaskInfo mwTaskInfo =
+                createTaskInfo(1, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
+        transitions.requestStartTransition(transitToken1,
+                new TransitionRequestInfo(TRANSIT_CHANGE, mwTaskInfo, null /* remote */));
+        TransitionInfo change = new TransitionInfoBuilder(TRANSIT_CHANGE)
+                .addChange(TRANSIT_CHANGE).build();
+        SurfaceControl.Transaction startT1 = mock(SurfaceControl.Transaction.class);
+        SurfaceControl.Transaction finishT1 = mock(SurfaceControl.Transaction.class);
+        transitions.onTransitionReady(transitToken1, change, startT1, finishT1);
+
+        // Request the second transition that should be handled by the default handler
+        IBinder transitToken2 = new Binder();
+        TransitionInfo open = new TransitionInfoBuilder(TRANSIT_OPEN)
+                .addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
+        transitions.requestStartTransition(transitToken2,
+                new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, null /* remote */));
+        SurfaceControl.Transaction startT2 = mock(SurfaceControl.Transaction.class);
+        SurfaceControl.Transaction finishT2 = mock(SurfaceControl.Transaction.class);
+        transitions.onTransitionReady(transitToken2, open, startT2, finishT2);
+        verify(observer).onTransitionReady(transitToken2, open, startT2, finishT2);
+        verify(observer, times(0)).onTransitionStarting(transitToken2);
+
+        // Request the third transition that should be merged into the second one
+        IBinder transitToken3 = new Binder();
+        transitions.requestStartTransition(transitToken3,
+                new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, null /* remote */));
+        SurfaceControl.Transaction startT3 = mock(SurfaceControl.Transaction.class);
+        SurfaceControl.Transaction finishT3 = mock(SurfaceControl.Transaction.class);
+        transitions.onTransitionReady(transitToken3, open, startT3, finishT3);
+        verify(observer, times(0)).onTransitionStarting(transitToken2);
+        verify(observer).onTransitionReady(transitToken3, open, startT3, finishT3);
+        verify(observer, times(0)).onTransitionStarting(transitToken3);
+
+        testHandler.finishAll();
+        mMainExecutor.flushAll();
+
+        verify(observer).onTransitionFinished(transitToken1, false);
+
+        mDefaultHandler.finishAll();
+        mMainExecutor.flushAll();
+
+        InOrder observerOrder = inOrder(observer);
+        observerOrder.verify(observer).onTransitionStarting(transitToken2);
+        observerOrder.verify(observer).onTransitionMerged(transitToken3, transitToken2);
+        observerOrder.verify(observer).onTransitionFinished(transitToken2, false);
+
+        // Merged transition won't receive any lifecycle calls beyond ready
+        verify(observer, times(0)).onTransitionStarting(transitToken3);
+        verify(observer, times(0)).onTransitionFinished(eq(transitToken3), anyBoolean());
+    }
+
     class TransitionInfoBuilder {
         final TransitionInfo mInfo;
 
@@ -834,16 +1048,13 @@
     }
 
     private DisplayController createTestDisplayController() {
-        IWindowManager mockWM = mock(IWindowManager.class);
-        final IDisplayWindowListener[] displayListener = new IDisplayWindowListener[1];
-        try {
-            doReturn(new int[]{DEFAULT_DISPLAY}).when(mockWM).registerDisplayWindowListener(any());
-        } catch (RemoteException e) {
-            // No remote stuff happening, so this can't be hit
-        }
-        ShellInit shellInit = new ShellInit(mMainExecutor);
-        DisplayController out = new DisplayController(mContext, mockWM, shellInit, mMainExecutor);
-        shellInit.init();
+        DisplayLayout displayLayout = mock(DisplayLayout.class);
+        doReturn(Surface.ROTATION_180).when(displayLayout).getUpsideDownRotation();
+        // By default we ignore nav bar in deciding if a seamless rotation is allowed.
+        doReturn(true).when(displayLayout).allowSeamlessRotationDespiteNavBarMoving();
+
+        DisplayController out = mock(DisplayController.class);
+        doReturn(displayLayout).when(out).getDisplayLayout(DEFAULT_DISPLAY);
         return out;
     }
 
@@ -854,17 +1065,4 @@
         shellInit.init();
         return t;
     }
-//
-//    private class TestDisplayController extends DisplayController {
-//        private final DisplayLayout mTestDisplayLayout;
-//        TestDisplayController() {
-//            super(mContext, mock(IWindowManager.class), mMainExecutor);
-//            mTestDisplayLayout = new DisplayLayout();
-//            mTestDisplayLayout.
-//        }
-//
-//        @Override
-//        DisplayLayout
-//    }
-
 }
diff --git a/libs/hwui/jni/android_graphics_Canvas.cpp b/libs/hwui/jni/android_graphics_Canvas.cpp
index 0ef80ee..132234b 100644
--- a/libs/hwui/jni/android_graphics_Canvas.cpp
+++ b/libs/hwui/jni/android_graphics_Canvas.cpp
@@ -407,14 +407,28 @@
         indices = (const uint16_t*)(indexA.ptr() + indexIndex);
     }
 
-    SkVertices::VertexMode mode = static_cast<SkVertices::VertexMode>(modeHandle);
+    SkVertices::VertexMode vertexMode = static_cast<SkVertices::VertexMode>(modeHandle);
     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-    get_canvas(canvasHandle)->drawVertices(SkVertices::MakeCopy(mode, vertexCount,
-                                           reinterpret_cast<const SkPoint*>(verts),
-                                           reinterpret_cast<const SkPoint*>(texs),
-                                           reinterpret_cast<const SkColor*>(colors),
-                                           indexCount, indices).get(),
-                                           SkBlendMode::kModulate, *paint);
+
+    // Preserve legacy Skia behavior: ignore the shader if there are no texs set.
+    Paint noShaderPaint;
+    if (jtexs == NULL) {
+        noShaderPaint = Paint(*paint);
+        noShaderPaint.setShader(nullptr);
+        paint = &noShaderPaint;
+    }
+    // Since https://skia-review.googlesource.com/c/skia/+/473676, Skia will blend paint and vertex
+    // colors when no shader is provided. This ternary uses kDst to mimic the old behavior of
+    // ignoring the paint and using the vertex colors directly when no shader is provided.
+    SkBlendMode blendMode = paint->getShader() ? SkBlendMode::kModulate : SkBlendMode::kDst;
+
+    get_canvas(canvasHandle)
+            ->drawVertices(SkVertices::MakeCopy(
+                                   vertexMode, vertexCount, reinterpret_cast<const SkPoint*>(verts),
+                                   reinterpret_cast<const SkPoint*>(texs),
+                                   reinterpret_cast<const SkColor*>(colors), indexCount, indices)
+                                   .get(),
+                           blendMode, *paint);
 }
 
 static void drawNinePatch(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
diff --git a/packages/SettingsLib/ButtonPreference/src/com/android/settingslib/widget/ButtonPreference.java b/packages/SettingsLib/ButtonPreference/src/com/android/settingslib/widget/ButtonPreference.java
index 56d2967..f46de06 100644
--- a/packages/SettingsLib/ButtonPreference/src/com/android/settingslib/widget/ButtonPreference.java
+++ b/packages/SettingsLib/ButtonPreference/src/com/android/settingslib/widget/ButtonPreference.java
@@ -133,6 +133,11 @@
     }
 
     @Override
+    public CharSequence getTitle() {
+        return mTitle;
+    }
+
+    @Override
     public void setIcon(Drawable icon) {
         mIcon = icon;
         if (mButton == null || icon == null) {
diff --git a/packages/SettingsLib/res/values-af/arrays.xml b/packages/SettingsLib/res/values-af/arrays.xml
index 1de7668..a7e44d3 100644
--- a/packages/SettingsLib/res/values-af/arrays.xml
+++ b/packages/SettingsLib/res/values-af/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"Gebruik stelselkeuse (verstek)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>-oudio"</item>
+    <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>-oudio"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"Gebruik stelselkeuse (verstek)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>-oudio"</item>
+    <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>-oudio"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"Gebruik stelselkeuse (verstek)"</item>
     <item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index ed4104c..dd36b49 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -660,8 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Weer"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Luggehalte"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Uitsaai-inligting"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
-    <skip />
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Huiskontroles"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Kies \'n profielprent"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Verstekgebruikerikoon"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"Fisieke sleutelbord"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 82dd336..2018778 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"የአየር ሁኔታ"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"የአየር ጥራት"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"የCast መረጃ"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"የቤት ውስጥ ቁጥጥሮች"</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"የመገለጫ ሥዕል ይምረጡ"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"ነባሪ የተጠቃሚ አዶ"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 49ebbbc..65c8edc 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"الطقس"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"جودة الهواء"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"معلومات البث"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"إدارة آلية للمنزل"</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"اختيار صورة الملف الشخصي"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"رمز المستخدم التلقائي"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 2296eca..402c615e 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"বতৰ"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"বায়ুৰ গুণগত মান"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"কাষ্টৰ তথ্য"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"গৃহ নিয়ন্ত্ৰণ"</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"এখন প্ৰ’ফাইল চিত্ৰ বাছনি কৰক"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"ডিফ’ল্ট ব্যৱহাৰকাৰীৰ চিহ্ন"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 75a4ef3..89b91e6 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Hava"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Havanın keyfiyyəti"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Yayım məlumatı"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Əsas səhifə kontrolları"</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"Profil şəkli seçin"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Defolt istifadəçi ikonası"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml b/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml
index 337da26..63b08fa 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"Koristi izbor sistema (podrazumevano)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audio"</item>
+    <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audio"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"Koristi izbor sistema (podrazumevano)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audio"</item>
+    <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audio"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"Koristi izbor sistema (podrazumevano)"</item>
     <item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 3231198..13c3f41 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -660,8 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Vreme"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Kvalitet vazduha"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Podaci o prebacivanju"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
-    <skip />
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Upravljanje domom"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"SmartSpace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Odaberite sliku profila"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Podrazumevana ikona korisnika"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"Fizička tastatura"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 54384c0..75d974a 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Надвор\'е"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Якасць паветра"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Даныя пра трансляцыю"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Кіраванне домам"</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"Выберыце відарыс профілю"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Стандартны карыстальніцкі значок"</string>
diff --git a/packages/SettingsLib/res/values-bg/arrays.xml b/packages/SettingsLib/res/values-bg/arrays.xml
index 1aad6ca7..849e694 100644
--- a/packages/SettingsLib/res/values-bg/arrays.xml
+++ b/packages/SettingsLib/res/values-bg/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"Използване на сист. избор (стандартно)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"Разширено аудиокодиране (AAC)"</item>
+    <item msgid="1049450003868150455">"Аудио: <xliff:g id="APTX">aptX™</xliff:g> от <xliff:g id="QUALCOMM">Qualcomm®</xliff:g>"</item>
+    <item msgid="2908219194098827570">"Аудио: <xliff:g id="APTX_HD">aptX™ HD</xliff:g> от <xliff:g id="QUALCOMM">Qualcomm®</xliff:g>"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"Използване на сист. избор (стандартно)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"Разширено аудиокодиране (AAC)"</item>
+    <item msgid="8627333814413492563">"Аудио: <xliff:g id="APTX">aptX™</xliff:g> от <xliff:g id="QUALCOMM">Qualcomm®</xliff:g>"</item>
+    <item msgid="3517061573669307965">"Аудио: <xliff:g id="APTX_HD">aptX™ HD</xliff:g> от <xliff:g id="QUALCOMM">Qualcomm®</xliff:g>"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"Използване на сист. избор (стандартно)"</item>
     <item msgid="8003118270854840095">"44,1 кХц"</item>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 18b54f3..c146ef5 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -660,8 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Времето"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Качество на въздуха"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Предаване: Инф."</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
-    <skip />
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Контроли за дома"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Изберете снимка на потребителския профил"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Икона за основния потребител"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"Физическа клавиатура"</string>
diff --git a/packages/SettingsLib/res/values-bn/arrays.xml b/packages/SettingsLib/res/values-bn/arrays.xml
index 5e6bb95..a3bc4fd 100644
--- a/packages/SettingsLib/res/values-bn/arrays.xml
+++ b/packages/SettingsLib/res/values-bn/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"সিস্টেমের নির্বাচন ব্যবহার করুন (ডিফল্ট)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> অডিও"</item>
+    <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> অডিও"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"সিস্টেমের নির্বাচন ব্যবহার করুন (ডিফল্ট)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> অডিও"</item>
+    <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> অডিও"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"সিস্টেমের নির্বাচন ব্যবহার করুন (ডিফল্ট)"</item>
     <item msgid="8003118270854840095">"৪৪.১ kHz"</item>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 217cfe9..1d1472e 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -661,6 +661,7 @@
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"এয়ার কোয়ালিটি"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"কাস্ট সম্পর্কিত তথ্য"</string>
     <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"হোম কন্ট্রোল"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"একটি প্রোফাইল ছবি বেছে নিন"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"ডিফল্ট ব্যবহারকারীর আইকন"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"ফিজিক্যাল কীবোর্ড"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index da81766..d85fa56 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -265,7 +265,7 @@
     <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, otklanjanje grešaka, programer"</string>
     <string name="bugreport_in_power" msgid="8664089072534638709">"Prečica za izvještaj o greškama"</string>
     <string name="bugreport_in_power_summary" msgid="1885529649381831775">"Vidite dugme za prijavu grešaka u meniju napajanja"</string>
-    <string name="keep_screen_on" msgid="1187161672348797558">"Ne zaključavaj ekran"</string>
+    <string name="keep_screen_on" msgid="1187161672348797558">"Ne zaključavaj"</string>
     <string name="keep_screen_on_summary" msgid="1510731514101925829">"Ekran neće prelaziti u stanje mirovanja tokom punjenja"</string>
     <string name="bt_hci_snoop_log" msgid="7291287955649081448">"Omogući Bluetooth HCI snoop zapis"</string>
     <string name="bt_hci_snoop_log_summary" msgid="6808538971394092284">"Snimite Bluetooth pakete. (Uključite/isključite Bluetooth nakon što promijenite ovu postavku)"</string>
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Vremenska prognoza"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Kvalitet zraka"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Podaci o emitiranju"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Kontrole doma"</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"Odaberite sliku profila"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Zadana ikona korisnika"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 38f1948..9ddba82 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Temps"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Qualitat de l\'aire"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Informació d\'emissió"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Domòtica"</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"Tria una foto de perfil"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Icona d\'usuari predeterminat"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 33f6489..7b959f4 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Počasí"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Kvalita vzduchu"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info o odesílání"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Ovládání domácnosti"</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"Vyberte profilový obrázek"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Výchozí uživatelská ikona"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 44fa025..951d417 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Vejr"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Luftkvalitet"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Cast-oplysninger"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Styring af hjem"</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"Vælg et profilbillede"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Ikon for standardbruger"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index dc332e2..3bd4d46 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Wetter"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Luftqualität"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Streaming-Info"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Smart-Home-Steuerung"</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"Profilbild auswählen"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Standardmäßiges Nutzersymbol"</string>
diff --git a/packages/SettingsLib/res/values-el/arrays.xml b/packages/SettingsLib/res/values-el/arrays.xml
index 70000e1..b95f6fc 100644
--- a/packages/SettingsLib/res/values-el/arrays.xml
+++ b/packages/SettingsLib/res/values-el/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"Χρήση επιλογής συστήματος (Προεπιλογή)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"Ήχος <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+    <item msgid="2908219194098827570">"Ήχος <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"Χρήση επιλογής συστήματος (Προεπιλογή)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"Ήχος <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+    <item msgid="3517061573669307965">"Ήχος <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"Χρήση επιλογής συστήματος (Προεπιλογή)"</item>
     <item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 378b0cd..2979e78 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -660,8 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Καιρός"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Ποιότητα αέρα"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Πληροφορίες ηθοποιών"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
-    <skip />
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Οικιακοί έλεγχοι"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Επιλογή φωτογραφίας προφίλ"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Προεπιλεγμένο εικονίδιο χρήστη"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"Φυσικό πληκτρολόγιο"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/arrays.xml b/packages/SettingsLib/res/values-en-rAU/arrays.xml
index fc6f791..327e4e9 100644
--- a/packages/SettingsLib/res/values-en-rAU/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rAU/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"Use system selection (default)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audio"</item>
+    <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audio"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"Use system selection (default)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audio"</item>
+    <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audio"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"Use system selection (default)"</item>
     <item msgid="8003118270854840095">"44.1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index f95c997..426a6d2 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -661,6 +661,7 @@
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Air quality"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Cast info"</string>
     <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Home Controls"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Choose a profile picture"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Default user icon"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"Physical keyboard"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/arrays.xml b/packages/SettingsLib/res/values-en-rCA/arrays.xml
index fc6f791..327e4e9 100644
--- a/packages/SettingsLib/res/values-en-rCA/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rCA/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"Use system selection (default)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audio"</item>
+    <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audio"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"Use system selection (default)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audio"</item>
+    <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audio"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"Use system selection (default)"</item>
     <item msgid="8003118270854840095">"44.1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 330b764..dc3691b 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -661,6 +661,7 @@
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Air quality"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Cast info"</string>
     <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Home Controls"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Choose a profile picture"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Default user icon"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"Physical keyboard"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/arrays.xml b/packages/SettingsLib/res/values-en-rGB/arrays.xml
index fc6f791..327e4e9 100644
--- a/packages/SettingsLib/res/values-en-rGB/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rGB/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"Use system selection (default)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audio"</item>
+    <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audio"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"Use system selection (default)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audio"</item>
+    <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audio"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"Use system selection (default)"</item>
     <item msgid="8003118270854840095">"44.1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index f95c997..426a6d2 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -661,6 +661,7 @@
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Air quality"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Cast info"</string>
     <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Home Controls"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Choose a profile picture"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Default user icon"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"Physical keyboard"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/arrays.xml b/packages/SettingsLib/res/values-en-rIN/arrays.xml
index fc6f791..327e4e9 100644
--- a/packages/SettingsLib/res/values-en-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rIN/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"Use system selection (default)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audio"</item>
+    <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audio"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"Use system selection (default)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audio"</item>
+    <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audio"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"Use system selection (default)"</item>
     <item msgid="8003118270854840095">"44.1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index f95c997..426a6d2 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -661,6 +661,7 @@
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Air quality"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Cast info"</string>
     <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Home Controls"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Choose a profile picture"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Default user icon"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"Physical keyboard"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/arrays.xml b/packages/SettingsLib/res/values-en-rXC/arrays.xml
index 34db380..8af0a4a 100644
--- a/packages/SettingsLib/res/values-en-rXC/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rXC/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎‎‏‎‏‎‎‎‎‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‏‏‎‎‎‏‎‏‏‏‏‎‏‏‏‏‎‏‎‎‎map13‎‏‎‎‏‎"</item>
     <item msgid="8147982633566548515">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‎‏‎‎‏‏‎‏‏‏‎‎‏‏‎‎‎‎‏‎‎‏‎‎‎‎‏‏‎‏‏‏‎‎‏‎‎‏‎‎‏‏‎‎‏‎‎‎‏‎‎‎‏‏‎map14‎‏‎‎‏‎"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‏‎‏‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‎‎‏‏‏‎‏‎‎‏‎‎‏‏‏‎‎‎‏‎‏‏‏‎‎‎‎‏‏‎‏‎‏‏‏‎‏‏‎Use System Selection (Default)‎‏‎‎‏‎"</item>
+    <item msgid="4055460186095649420">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‎‎‎‎‏‎‎‎‏‏‏‏‏‏‎‎‎‏‏‏‎‎‎‏‏‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‎‎‎‏‎‎‎‎‎‏‎‏‎‎‎‏‏‎‎‎SBC‎‏‎‎‏‎"</item>
+    <item msgid="720249083677397051">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‏‎‏‎‏‏‏‎‎‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‎‎‎‏‎‏‎‎‎‎‎‎‏‏‏‎‏‏‎AAC‎‏‎‎‏‎"</item>
+    <item msgid="1049450003868150455">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‏‏‎‏‎‎‏‎‎‎‎‎‏‏‎‎‏‎‏‎‎‏‏‎‏‏‏‏‏‏‎‎‎‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‎‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="QUALCOMM">Qualcomm®</xliff:g>‎‏‎‎‏‏‏‎ ‎‏‎‎‏‏‎<xliff:g id="APTX">aptX™</xliff:g>‎‏‎‎‏‏‏‎ audio‎‏‎‎‏‎"</item>
+    <item msgid="2908219194098827570">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‎‏‏‏‏‏‎‎‏‎‏‏‎‏‏‎‎‏‎‎‏‏‏‎‏‏‏‏‎‎‎‎‎‏‎‎‏‏‎‎‏‎‎‎‏‎‎‏‏‎<xliff:g id="QUALCOMM">Qualcomm®</xliff:g>‎‏‎‎‏‏‏‎ ‎‏‎‎‏‏‎<xliff:g id="APTX_HD">aptX™ HD</xliff:g>‎‏‎‎‏‏‏‎ audio‎‏‎‎‏‎"</item>
+    <item msgid="3825367753087348007">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‏‎‏‎‎‎‏‎‏‏‎‎‏‏‎‏‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‏‎‏‎‎‎‎‎‎‎‎‏‎‏‏‎‏‏‎‏‎‎‏‎‎‏‏‏‎LDAC‎‏‎‎‏‎"</item>
+    <item msgid="328951785723550863">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‏‏‏‎‎‏‎‎‏‎‎‎‎‏‎‏‎‏‎‏‏‏‏‏‎‏‎‎‎‎‎‎‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‎‏‏‏‎‎‏‎‎‎‏‏‏‏‎LC3‎‏‎‎‏‎"</item>
+    <item msgid="506175145534048710">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‏‏‏‏‏‎‎‎‎‎‏‏‎‎‏‎‎‏‎‏‏‏‎‎‏‏‏‎‎‏‏‏‎‏‏‏‏‏‎‏‏‎‎‎‎‎‏‎‎‏‎‎‏‏‏‎‎‎‏‏‎‎Opus‎‏‎‎‏‎"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‎‏‏‏‎‏‏‎‏‎‏‎‏‎‎‏‏‏‏‎‎‏‎‏‎‎‏‎‏‎‎‎‏‏‎‎‏‎‎‏‏‏‎‏‏‏‎‎‎‎‎Use System Selection (Default)‎‏‎‎‏‎"</item>
+    <item msgid="9024885861221697796">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‏‏‎‏‏‎‏‎‏‎‏‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‎‎‎‎‏‎‎‎‏‎‎‏‎‎‎‎‎‏‎‎‎SBC‎‏‎‎‏‎"</item>
+    <item msgid="4688890470703790013">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‎‎‏‎‎‎‏‎‎‏‎‎‏‎‎‏‎‎‏‎‎‎‎‏‎‏‎‎‏‎‏‎‎‎‏‎‎‎‎‎‎‏‏‎‏‏‏‎‏‏‏‏‎‏‏‏‏‎‏‎AAC‎‏‎‎‏‎"</item>
+    <item msgid="8627333814413492563">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‏‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎‎‏‎‏‎‎‎‎‎‏‏‎‏‏‎‏‎‏‎‏‎‎‎‎‎‎‎‏‎‏‎‏‎‎‏‏‎‎‏‎‎‏‏‎<xliff:g id="QUALCOMM">Qualcomm®</xliff:g>‎‏‎‎‏‏‏‎ ‎‏‎‎‏‏‎<xliff:g id="APTX">aptX™</xliff:g>‎‏‎‎‏‏‏‎ audio‎‏‎‎‏‎"</item>
+    <item msgid="3517061573669307965">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‎‏‏‏‏‎‎‎‏‏‏‎‎‏‏‎‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‏‏‏‏‎‎‎‏‎‎‎‏‏‎‎‎‏‏‏‏‎‏‎‎‏‎‎‏‏‎<xliff:g id="QUALCOMM">Qualcomm®</xliff:g>‎‏‎‎‏‏‏‎ ‎‏‎‎‏‏‎<xliff:g id="APTX_HD">aptX™ HD</xliff:g>‎‏‎‎‏‏‏‎ audio‎‏‎‎‏‎"</item>
+    <item msgid="2553206901068987657">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‏‏‎‏‏‎‏‏‏‎‏‏‎‏‎‎‎‎‎‎‏‎‎‏‏‎‎‎‏‎‏‎‎‎‎‏‎‎‏‎‏‎‏‏‏‏‏‏‎‏‎‎‎‎‏‎‎‏‎LDAC‎‏‎‎‏‎"</item>
+    <item msgid="3940992993241040716">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‏‏‎‏‎‏‏‎‎‎‏‎‎‏‏‏‎‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‏‏‎‏‏‏‏‏‎‎‎‎‏‏‏‎‏‎‎‏‏‎‎‎LC3‎‏‎‎‏‎"</item>
+    <item msgid="7940970833006181407">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‏‎‎‏‎‎‏‎‎‎‏‎‎‏‎‎‎‏‏‏‏‎‎‎‎‎‏‏‏‏‏‎Opus‎‏‎‎‏‎"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‏‎‎‏‏‎‏‏‏‎‎‏‎‏‏‎‎‎‎‎‎‎‏‏‏‎‎‏‏‎‏‏‎‎‏‏‏‏‎‏‏‏‏‏‎‏‎‏‎‎‎‏‏‎‎‏‏‏‏‎Use System Selection (Default)‎‏‎‎‏‎"</item>
     <item msgid="8003118270854840095">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‎‏‎‎‎‎‏‏‎‎‏‎‎‏‏‎‏‎‏‎‏‎‎‎‏‏‏‏‎‏‏‎‏‏‏‏‎‏‏‎‏‏‏‏‏‏‎‎‎‏‏‏‏‏‎44.1 kHz‎‏‎‎‏‎"</item>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index a0a9351..8360f01 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -661,6 +661,7 @@
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‏‎‎‎‎‏‎‏‏‎‎‏‎‏‎‏‎‏‏‏‏‎‏‎‏‎‏‏‎‎‏‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎Air Quality‎‏‎‎‏‎"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‎‎‎‎‎‎‎‏‏‎‎‏‎‎‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‏‎‎‏‏‏‏‏‎‎‏‎‎‎‎‎‎‏‏‏‎‏‏‎‎‏‏‏‎‎‎Cast Info‎‏‎‎‏‎"</string>
     <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‎‏‎‏‏‎‎‎‎‎‎‏‏‎‎‏‎‎‎‏‏‎‎‏‎‏‎‏‏‏‎‎‎‏‏‏‎‏‎‎‏‏‏‏‏‎‏‏‎Home Controls‎‏‎‎‏‎"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‎‏‎‎‏‎‎‎‎‎‏‏‎‏‏‎‎‎‎‎‎‎‏‏‎‎‎‎‎‏‏‎‎‎‏‎‎‏‎‎‎‏‎‎‏‎‏‏‎‎‎‏‎‏‏‎‎‎‎‎Smartspace‎‏‎‎‏‎"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‏‏‎‎‏‏‎‎‏‎‎‏‎‎‏‎‏‎‎‎‎‏‏‎‏‎‎‏‎‎‎‏‏‎‏‏‎‎‎‏‎‏‏‎‏‏‎‏‏‏‎‎‎Choose a profile picture‎‏‎‎‏‎"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‎‏‎‏‏‏‏‎‏‎‎‏‎‏‎‎‏‏‏‎‎‏‎‏‏‏‎‏‏‎‏‎‏‎‎‎‎‎‎‏‏‏‎‏‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‎Default user icon‎‏‎‎‏‎"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‎‏‎‏‏‎‎‎‏‏‏‎‏‏‎‏‏‎‏‏‏‎‎‏‎‎‎‏‎‏‎‎‎‎‎‎‎‎‏‏‏‎‏‎‏‏‏‎‎‎‏‎‏‎‏‎‏‎‎‎Physical keyboard‎‏‎‎‏‎"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 88be9a8..d0f2c64 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Clima"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Calidad del aire"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info de reparto"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Control de la casa"</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"Elige una foto de perfil"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Ícono de usuario predeterminado"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index ddfd4c9..e75c13c 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Tiempo"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Calidad del aire"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info. de emisión"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Domótica"</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"Elige una imagen de perfil"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Icono de usuario predeterminado"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 6b6edda..022063c 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Ilm"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Õhukvaliteet"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Osatäitjate teave"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Kodu juhtimine"</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"Valige profiilipilt"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Vaikekasutajaikoon"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 9597c46..ba8b1ad 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -662,6 +662,8 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Igorpenari buruzko informazioa"</string>
     <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
     <skip />
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
+    <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"Aukeratu profileko argazki bat"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Erabiltzaile lehenetsiaren ikonoa"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"Teklatu fisikoa"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 26f2260..911426c 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"آب‌وهوا"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"کیفیت هوا"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"اطلاعات پخش محتوا"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"کنترل لوازم خانگی"</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"انتخاب عکس نمایه"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"نماد کاربر پیش‌فرض"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 4ad9631..670bcae 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Sää"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Ilmanlaatu"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Striimaustiedot"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Kodin ohjaus"</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"Valitse profiilikuva"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Oletuskäyttäjäkuvake"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/arrays.xml b/packages/SettingsLib/res/values-fr-rCA/arrays.xml
index 12acbb6..808c3f2 100644
--- a/packages/SettingsLib/res/values-fr-rCA/arrays.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"Utiliser sélect. du système (par défaut)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+    <item msgid="2908219194098827570">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"Utiliser sélect. du système (par défaut)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+    <item msgid="3517061573669307965">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"Utiliser sélect. du système (par défaut)"</item>
     <item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index f6927d6..5d6aaeb 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -660,8 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Météo"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Qualité de l\'air"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info diffusion"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
-    <skip />
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Domotique"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Aperçu"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Choisir une photo de profil"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Icône d\'utilisateur par défaut"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"Clavier physique"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 3c620d1..dad8668 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Météo"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Qualité de l\'air"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Infos distribution"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Domotique"</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"Choisissez une photo de profil"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Icône de l\'utilisateur par défaut"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index f23608e..3fd7f43 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -662,6 +662,8 @@
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Datos da emisión"</string>
     <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
     <skip />
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
+    <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"Escolle unha imaxe do perfil"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Icona do usuario predeterminado"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"Teclado físico"</string>
diff --git a/packages/SettingsLib/res/values-gu/arrays.xml b/packages/SettingsLib/res/values-gu/arrays.xml
index 7e668e7..e527d81 100644
--- a/packages/SettingsLib/res/values-gu/arrays.xml
+++ b/packages/SettingsLib/res/values-gu/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"સિસ્ટમ પસંદગીનો ઉપયોગ કરો (ડિફૉલ્ટ)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> ઑડિયો"</item>
+    <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> ઑડિયો"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"સિસ્ટમ પસંદગીનો ઉપયોગ કરો (ડિફૉલ્ટ)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> ઑડિયો"</item>
+    <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> ઑડિયો"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"સિસ્ટમ પસંદગીનો ઉપયોગ કરો (ડિફૉલ્ટ)"</item>
     <item msgid="8003118270854840095">"44.1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 3882b63..eb84599 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -660,8 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"હવામાન"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"હવાની ક્વૉલિટી"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"કાસ્ટ વિશેની માહિતી"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
-    <skip />
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"ઘરેલુ સાધન નિયંત્રણો"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"પ્રોફાઇલ ફોટો પસંદ કરો"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"ડિફૉલ્ટ વપરાશકર્તાનું આઇકન"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"ભૌતિક કીબોર્ડ"</string>
diff --git a/packages/SettingsLib/res/values-hi/arrays.xml b/packages/SettingsLib/res/values-hi/arrays.xml
index 13da75b..9b8d83e 100644
--- a/packages/SettingsLib/res/values-hi/arrays.xml
+++ b/packages/SettingsLib/res/values-hi/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"सिस्टम से चुने जाने का उपयोग करें (डिफ़ॉल्ट)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> ऑडियो"</item>
+    <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> ऑडियो"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"सिस्टम से चुने जाने का इस्तेमाल करें (डिफ़ॉल्ट)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> ऑडियो"</item>
+    <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> ऑडियो"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"सिस्टम से चुने जाने का उपयोग करें (डिफ़ॉल्ट)"</item>
     <item msgid="8003118270854840095">"44.1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 6d0c0de..e529756 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -660,8 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"मौसम"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"हवा की क्वालिटी"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"कास्टिंग की जानकारी"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
-    <skip />
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"होम कंट्रोल"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"स्मार्टस्पेस"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"प्रोफ़ाइल फ़ोटो चुनें"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"उपयोगकर्ता के लिए डिफ़ॉल्ट आइकॉन"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"फ़िज़िकल कीबोर्ड"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 7ee089c..598f65f 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Vremenska prognoza"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Kvaliteta zraka"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Inform. o emitiranju"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Upravlj. kuć. uređ."</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"Odabir profilne slike"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Ikona zadanog korisnika"</string>
diff --git a/packages/SettingsLib/res/values-hu/arrays.xml b/packages/SettingsLib/res/values-hu/arrays.xml
index a5f37ea..409d600 100644
--- a/packages/SettingsLib/res/values-hu/arrays.xml
+++ b/packages/SettingsLib/res/values-hu/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"Rendszerérték (alapértelmezett)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"Hang: <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+    <item msgid="2908219194098827570">"Hang: <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"Rendszerérték (alapértelmezett)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"Hang: <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+    <item msgid="3517061573669307965">"Hang: <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"Rendszerérték (alapértelmezett)"</item>
     <item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index f5f60fa..8eae4d0 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -660,8 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Időjárás"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Levegőminőség"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Átküldési információ"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
-    <skip />
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Otthonvezérlés"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Profilkép választása"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Alapértelmezett felhasználó ikonja"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"Fizikai billentyűzet"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index b9e7d16..2a5fbfb 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Եղանակ"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Օդի որակը"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Հեռարձակման տվյալներ"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Տան կարգավորումներ"</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"Պրոֆիլի նկար ընտրեք"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Օգտատիրոջ կանխադրված պատկերակ"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index e5f1728..08ec2b1 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Cuaca"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Kualitas Udara"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info Transmisi"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Kontrol Rumah"</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"Pilih foto profil"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Ikon pengguna default"</string>
diff --git a/packages/SettingsLib/res/values-is/arrays.xml b/packages/SettingsLib/res/values-is/arrays.xml
index 9d481f8..0b5b978 100644
--- a/packages/SettingsLib/res/values-is/arrays.xml
+++ b/packages/SettingsLib/res/values-is/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"Nota val kerfisins (sjálfgefið)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> hljóð"</item>
+    <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> hljóð"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"Nota val kerfisins (sjálfgefið)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> hljóð"</item>
+    <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> hljóð"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"Nota val kerfisins (sjálfgefið)"</item>
     <item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 32fe1c8..dc2036f 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -660,8 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Veður"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Loftgæði"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Útsendingaruppl."</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
-    <skip />
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Heimastýringar"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Veldu prófílmynd"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Tákn sjálfgefins notanda"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"Vélbúnaðarlyklaborð"</string>
diff --git a/packages/SettingsLib/res/values-it/arrays.xml b/packages/SettingsLib/res/values-it/arrays.xml
index 62450da3..ae1e515 100644
--- a/packages/SettingsLib/res/values-it/arrays.xml
+++ b/packages/SettingsLib/res/values-it/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"Usa selezione di sistema (predefinita)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+    <item msgid="2908219194098827570">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"Usa selezione di sistema (predefinita)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+    <item msgid="3517061573669307965">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"Usa selezione di sistema (predefinita)"</item>
     <item msgid="8003118270854840095">"44.1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 891c545..201fb48 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -660,8 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Meteo"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Qualità dell\'aria"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info sul cast"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
-    <skip />
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Controlli della casa"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Scegli un\'immagine del profilo"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Icona dell\'utente predefinito"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"Tastiera fisica"</string>
diff --git a/packages/SettingsLib/res/values-iw/arrays.xml b/packages/SettingsLib/res/values-iw/arrays.xml
index 49f3fcf..5d72aff 100644
--- a/packages/SettingsLib/res/values-iw/arrays.xml
+++ b/packages/SettingsLib/res/values-iw/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"שימוש בבחירת המערכת (ברירת המחדל)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"אודיו <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+    <item msgid="2908219194098827570">"אודיו <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"שימוש בבחירת המערכת (ברירת המחדל)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"אודיו <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+    <item msgid="3517061573669307965">"אודיו <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"שימוש בבחירת המערכת (ברירת המחדל)"</item>
     <item msgid="8003118270854840095">"44.1 קילו-הרץ"</item>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index a665c54..e6f1bcb 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -661,6 +661,7 @@
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"איכות האוויר"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"פרטי ההעברה"</string>
     <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"בית חכם"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"בחירה של תמונת פרופיל"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"סמל המשתמש שמוגדר כברירת מחדל"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"מקלדת פיזית"</string>
diff --git a/packages/SettingsLib/res/values-ja/arrays.xml b/packages/SettingsLib/res/values-ja/arrays.xml
index d73cc43..775e31c 100644
--- a/packages/SettingsLib/res/values-ja/arrays.xml
+++ b/packages/SettingsLib/res/values-ja/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"システムの選択(デフォルト)を使用"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> オーディオ"</item>
+    <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> オーディオ"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"システムの選択(デフォルト)を使用"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> オーディオ"</item>
+    <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> オーディオ"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"システムの選択(デフォルト)を使用"</item>
     <item msgid="8003118270854840095">"44.1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 7c6fc5d..c42679b 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -660,8 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"天気"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"大気質"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"キャスト情報"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
-    <skip />
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"スマートホーム"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"プロフィール写真の選択"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"デフォルト ユーザー アイコン"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"物理キーボード"</string>
diff --git a/packages/SettingsLib/res/values-ka/arrays.xml b/packages/SettingsLib/res/values-ka/arrays.xml
index c0d6f97..f3545b6 100644
--- a/packages/SettingsLib/res/values-ka/arrays.xml
+++ b/packages/SettingsLib/res/values-ka/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"სისტემის არჩეულის გამოყენება (ნაგულისხმევი)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> აუდიო"</item>
+    <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> აუდიო"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"სისტემის არჩეულის გამოყენება (ნაგულისხმევი)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> აუდიო"</item>
+    <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> აუდიო"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"სისტემის არჩეულის გამოყენება (ნაგულისხმევი)"</item>
     <item msgid="8003118270854840095">"44,1 კჰც"</item>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 1b6e69b..cd206e6 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -661,6 +661,7 @@
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"ჰაერის ხარისხი"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"ტრანსლირების ინფო"</string>
     <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"სახლის მართვა"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"ჭკვიანი სივრცე"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"აირჩიეთ პროფილის სურათი"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"მომხმარებლის ნაგულისხმევი ხატულა"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"ფიზიკური კლავიატურა"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index b32c1c1..d0b8c0d 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Ауа райы"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Ауа сапасы"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Трансляция ақпараты"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Үйді басқару элементтері"</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"Профиль суретін таңдау"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Әдепкі пайдаланушы белгішесі"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index dd48c54..fa759a6 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"អាកាសធាតុ"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"គុណភាព​ខ្យល់"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"ព័ត៌មានអំពីការបញ្ជូន"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"ការគ្រប់គ្រង​ផ្ទះ"</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"ជ្រើសរើស​រូបភាព​កម្រង​ព័ត៌មាន"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"រូបអ្នកប្រើប្រាស់លំនាំដើម"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 619fa72..5b0d684 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"ಹವಾಮಾನ"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"ವಾಯು ಗುಣಮಟ್ಟ"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"ಬಿತ್ತರಿಸಿದ ಮಾಹಿತಿ"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"ಹೋಮ್ ನಿಯಂತ್ರಣಗಳು"</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"ಪ್ರೊಫೈಲ್ ಚಿತ್ರವನ್ನು ಆಯ್ಕೆ ಮಾಡಿ"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"ಡೀಫಾಲ್ಟ್ ಬಳಕೆದಾರರ ಐಕಾನ್"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 510781e..ae9c19f 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -385,7 +385,7 @@
     <string name="force_msaa" msgid="4081288296137775550">"4x MSAA 강제 사용"</string>
     <string name="force_msaa_summary" msgid="9070437493586769500">"OpenGL ES 2.0 앱에서 4x MSAA 사용"</string>
     <string name="show_non_rect_clip" msgid="7499758654867881817">"사각형이 아닌 클립 작업 디버그"</string>
-    <string name="track_frame_time" msgid="522674651937771106">"프로필 HWUI 렌더링"</string>
+    <string name="track_frame_time" msgid="522674651937771106">"HWUI 렌더링 프로파일"</string>
     <string name="enable_gpu_debug_layers" msgid="4986675516188740397">"GPU 디버그 레이어 사용 설정"</string>
     <string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"디버그 앱에 GPU 디버그 레이어 로드 허용"</string>
     <string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"상세 공급업체 로깅 사용 설정"</string>
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"날씨"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"대기 상태"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"전송 정보"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"홈 컨트롤"</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"프로필 사진 선택하기"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"기본 사용자 아이콘"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 8a41afe..e85e6af 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Аба ырайы"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Абанын сапаты"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Тышкы экранга чыгаруу маалыматы"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Үйдү көзөмөлдөө"</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"Профилдин сүрөтүн тандоо"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Демейки колдонуучунун сүрөтчөсү"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 86d7aae..ace4276 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"ສະພາບອາກາດ"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"ຄຸນນະພາບ​ອາກາດ"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"ຂໍ້ມູນການສົ່ງສັນຍານ"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"ການຄວບຄຸມເຮືອນ"</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"ເລືອກຮູບໂປຣໄຟລ໌"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"ໄອຄອນຜູ້ໃຊ້ເລີ່ມຕົ້ນ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index f28523c..b309db6 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Orai"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Oro kokybė"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Perdav. informacija"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Namų sist. valdikl."</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"Pasirinkite profilio nuotrauką"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Numatytojo naudotojo piktograma"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 0dcc20b..6bbc051 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Laikapstākļi"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Gaisa kvalitāte"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Apraides informācija"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Mājas kontrolierīces"</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"Profila attēla izvēle"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Noklusējuma lietotāja ikona"</string>
diff --git a/packages/SettingsLib/res/values-mk/arrays.xml b/packages/SettingsLib/res/values-mk/arrays.xml
index 9c46f21..41427c1 100644
--- a/packages/SettingsLib/res/values-mk/arrays.xml
+++ b/packages/SettingsLib/res/values-mk/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"Користи избор на системот (стандардно)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> аудио"</item>
+    <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> аудио"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"Користи избор на системот (стандардно)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> аудио"</item>
+    <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> аудио"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"Користи избор на системот (стандардно)"</item>
     <item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 4aff21b..eb9cbfd 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -660,8 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Временска прогноза"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Квалитет на воздух"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Инфо за улогите"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
-    <skip />
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Контроли за домот"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Изберете профилна слика"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Икона за стандарден корисник"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"Физичка тастатура"</string>
diff --git a/packages/SettingsLib/res/values-ml/arrays.xml b/packages/SettingsLib/res/values-ml/arrays.xml
index 4715e2a..98e3bd6 100644
--- a/packages/SettingsLib/res/values-ml/arrays.xml
+++ b/packages/SettingsLib/res/values-ml/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"സിസ്റ്റം സെലക്ഷൻ ഉപയോഗിക്കൂ ‌(ഡിഫോൾട്ട്)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> ഓഡിയോ"</item>
+    <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> ഓഡിയോ"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"സിസ്റ്റം സെലക്ഷൻ ഉപയോഗിക്കൂ ‌(ഡിഫോൾട്ട്)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> ഓഡിയോ"</item>
+    <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> ഓഡിയോ"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"സിസ്റ്റം സെലക്ഷൻ ഉപയോഗിക്കൂ ‌(ഡിഫോൾട്ട്)"</item>
     <item msgid="8003118270854840095">"44.1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 85a3218..3d99eda 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -661,6 +661,7 @@
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"വായു നിലവാരം"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"കാസ്റ്റ് വിവരങ്ങൾ"</string>
     <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"ഹോം കൺട്രോളുകൾ"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"പ്രൊഫൈൽ ചിത്രം തിരഞ്ഞെടുക്കുക"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"ഡിഫോൾട്ട് ഉപയോക്തൃ ഐക്കൺ"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"ഫിസിക്കൽ കീബോർഡ്"</string>
diff --git a/packages/SettingsLib/res/values-mn/arrays.xml b/packages/SettingsLib/res/values-mn/arrays.xml
index 63fa53b..f3c10d7 100644
--- a/packages/SettingsLib/res/values-mn/arrays.xml
+++ b/packages/SettingsLib/res/values-mn/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"Системийн сонголтыг ашиглах (Өгөгдмөл)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> аудио"</item>
+    <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> аудио"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"Системийн сонголтыг ашиглах (Өгөгдмөл)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> аудио"</item>
+    <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> аудио"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"Системийн сонголтыг ашиглах (Өгөгдмөл)"</item>
     <item msgid="8003118270854840095">"44.1 кГц"</item>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index d45434e..c2f241c 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -661,6 +661,7 @@
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Агаарын чанар"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Дамжуулах мэдээлэл"</string>
     <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Гэрийн удирдлага"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Профайл зураг сонгох"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Өгөгдмөл хэрэглэгчийн дүрс тэмдэг"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"Биет гар"</string>
diff --git a/packages/SettingsLib/res/values-mr/arrays.xml b/packages/SettingsLib/res/values-mr/arrays.xml
index a54f990..c37baaa2 100644
--- a/packages/SettingsLib/res/values-mr/arrays.xml
+++ b/packages/SettingsLib/res/values-mr/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"सिस्टीम निवड वापरा (डीफॉल्ट)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> ऑडिओ"</item>
+    <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> ऑडिओ"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"सिस्टम निवड वापरा (डीफॉल्ट)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> ऑडिओ"</item>
+    <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> ऑडिओ"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"सिस्टम निवड वापरा (डीफॉल्ट)"</item>
     <item msgid="8003118270854840095">"44.1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 8de5904..13ea9c9 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -661,6 +661,7 @@
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"हवेची गुणवत्ता"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"कास्टसंबंधित माहिती"</string>
     <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"होम कंट्रोल"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"स्मार्टस्पेस"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"प्रोफाइल फोटो निवडा"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"डीफॉल्ट वापरकर्ता आयकन"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"वास्तविक कीबोर्ड"</string>
diff --git a/packages/SettingsLib/res/values-ms/arrays.xml b/packages/SettingsLib/res/values-ms/arrays.xml
index b26ed23..b19f038 100644
--- a/packages/SettingsLib/res/values-ms/arrays.xml
+++ b/packages/SettingsLib/res/values-ms/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"Gunakan Pilihan Sistem (Lalai)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+    <item msgid="2908219194098827570">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"Gunakan Pilihan Sistem (Lalai)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+    <item msgid="3517061573669307965">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"Gunakan Pilihan Sistem (Lalai)"</item>
     <item msgid="8003118270854840095">"44.1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 2cfafdf..9ff2170 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -660,8 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Cuaca"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Kualiti Udara"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Maklumat Pelakon"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
-    <skip />
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Kawalan Rumah"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Pilih gambar profil"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Ikon pengguna lalai"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"Papan kekunci fizikal"</string>
diff --git a/packages/SettingsLib/res/values-my/arrays.xml b/packages/SettingsLib/res/values-my/arrays.xml
index ed95dfe..3398c5b 100644
--- a/packages/SettingsLib/res/values-my/arrays.xml
+++ b/packages/SettingsLib/res/values-my/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"စနစ်ရွေးချယ်မှုကို အသုံးပြုပါ (မူရင်း)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> အသံ"</item>
+    <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> အသံ"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"စနစ်ရွေးချယ်မှုကို အသုံးပြုပါ (မူရင်း)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> အသံ"</item>
+    <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> အသံ"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"စနစ်ရွေးချယ်မှုကို အသုံးပြုပါ (မူရင်း)"</item>
     <item msgid="8003118270854840095">"၄၄.၁ kHz"</item>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 74351c5..0492dac 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -660,8 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"မိုးလေဝသ"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"လေထုအရည်အသွေး"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"ကာစ် အချက်အလက်"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
-    <skip />
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"အိမ်သတ်မှတ်ချက်များ"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"ပရိုဖိုင်ပုံ ရွေးပါ"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"မူရင်းအသုံးပြုသူ သင်္ကေတ"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"ပကတိ ကီးဘုတ်"</string>
diff --git a/packages/SettingsLib/res/values-nb/arrays.xml b/packages/SettingsLib/res/values-nb/arrays.xml
index 317c2db..7e65fa0 100644
--- a/packages/SettingsLib/res/values-nb/arrays.xml
+++ b/packages/SettingsLib/res/values-nb/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"Bruk systemvalg (standard)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>-lyd"</item>
+    <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>-lyd"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"Bruk systemvalg (standard)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>-lyd"</item>
+    <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>-lyd"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"Bruk systemvalg (standard)"</item>
     <item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 396ed94..7f67bd2 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -660,8 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Vær"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Luftkvalitet"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Castinformasjon"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
-    <skip />
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Hjemkontroller"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Velg et profilbilde"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Standard brukerikon"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"Fysisk tastatur"</string>
diff --git a/packages/SettingsLib/res/values-ne/arrays.xml b/packages/SettingsLib/res/values-ne/arrays.xml
index b3c3ee2..ac1f187 100644
--- a/packages/SettingsLib/res/values-ne/arrays.xml
+++ b/packages/SettingsLib/res/values-ne/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"सिस्टमको छनौट प्रयोग गरियोस् (डिफल्ट)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> अडियो"</item>
+    <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> अडियो"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"सिस्टमको छनौट प्रयोग गरियोस् (डिफल्ट)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> अडियो"</item>
+    <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> अडियो"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"सिस्टमको छनौट प्रयोग गरियोस् (डिफल्ट)"</item>
     <item msgid="8003118270854840095">"४४.१ kHz"</item>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 3944a26..522b5ee 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -660,8 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"मौसम"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"वायुको गुणस्तर"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"कास्टसम्बन्धी जानकारी"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
-    <skip />
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"घरायसी उपकरणका नियन्त्रण"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"प्रोफाइल फोटो छान्नुहोस्"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"प्रयोगकर्ताको डिफल्ट आइकन"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"भौतिक किबोर्ड"</string>
diff --git a/packages/SettingsLib/res/values-nl/arrays.xml b/packages/SettingsLib/res/values-nl/arrays.xml
index e809452..7c90eab 100644
--- a/packages/SettingsLib/res/values-nl/arrays.xml
+++ b/packages/SettingsLib/res/values-nl/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"Systeemselectie gebruiken (standaard)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audio"</item>
+    <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audio"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"Gebruik systeemselectie (standaard)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audio"</item>
+    <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audio"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"Systeemselectie gebruiken (standaard)"</item>
     <item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index b42f29a..9a90a7f 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -661,6 +661,7 @@
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Luchtkwaliteit"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Castinformatie"</string>
     <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Bediening voor in huis"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Kies een profielfoto"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Standaard gebruikersicoon"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"Fysiek toetsenbord"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 502f4531..65813a7 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"ପାଣିପାଗ"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"ବାୟୁର ଗୁଣବତ୍ତା"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"କାଷ୍ଟ ସୂଚନା"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"ହୋମ କଣ୍ଟ୍ରୋଲ"</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"ଏକ ପ୍ରୋଫାଇଲ ଛବି ବାଛନ୍ତୁ"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"ଡିଫଲ୍ଟ ଉପଯୋଗକର୍ତ୍ତା ଆଇକନ"</string>
diff --git a/packages/SettingsLib/res/values-pa/arrays.xml b/packages/SettingsLib/res/values-pa/arrays.xml
index a3fae22..0fd5c56 100644
--- a/packages/SettingsLib/res/values-pa/arrays.xml
+++ b/packages/SettingsLib/res/values-pa/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"ਸਿਸਟਮ ਚੋਣ ਦੀ ਵਰਤੋਂ ਕਰੋ (ਪੂਰਵ-ਨਿਰਧਾਰਿਤ)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> ਆਡੀਓ"</item>
+    <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> ਆਡੀਓ"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"ਸਿਸਟਮ ਚੋਣ ਦੀ ਵਰਤੋਂ ਕਰੋ (ਪੂਰਵ-ਨਿਰਧਾਰਿਤ)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> ਆਡੀਓ"</item>
+    <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> ਆਡੀਓ"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"ਸਿਸਟਮ ਚੋਣ ਦੀ ਵਰਤੋਂ ਕਰੋ (ਪੂਰਵ-ਨਿਰਧਾਰਿਤ)"</item>
     <item msgid="8003118270854840095">"44.1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 632dd3f..e111f8a 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -660,8 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"ਮੌਸਮ"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"ਹਵਾ ਦੀ ਕੁਆਲਿਟੀ"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"ਕਾਸਟ ਸੰਬੰਧੀ ਜਾਣਕਾਰੀ"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
-    <skip />
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"ਹੋਮ ਕੰਟਰੋਲ"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"ਕੋਈ ਪ੍ਰੋਫਾਈਲ ਤਸਵੀਰ ਚੁਣੋ"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"ਪੂਰਵ-ਨਿਰਧਾਰਿਤ ਵਰਤੋਂਕਾਰ ਪ੍ਰਤੀਕ"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"ਭੌਤਿਕ ਕੀ-ਬੋਰਡ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 80d864d..64d7af0 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Pogoda"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Jakość powietrza"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Obsada"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Sterowanie domem"</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"Wybierz zdjęcie profilowe"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Ikona domyślnego użytkownika"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/arrays.xml b/packages/SettingsLib/res/values-pt-rBR/arrays.xml
index 1883ef3..f218fab 100644
--- a/packages/SettingsLib/res/values-pt-rBR/arrays.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"Usar seleção do sistema (padrão)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"Áudio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+    <item msgid="2908219194098827570">"Áudio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"Usar seleção do sistema (padrão)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"Áudio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+    <item msgid="3517061573669307965">"Áudio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"Usar seleção do sistema (padrão)"</item>
     <item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 9569005..8c1e83d 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -208,7 +208,7 @@
     <string name="tts_engine_settings_title" msgid="7849477533103566291">"Configurações para <xliff:g id="TTS_ENGINE_NAME">%s</xliff:g>"</string>
     <string name="tts_engine_settings_button" msgid="477155276199968948">"Iniciar configurações do mecanismo"</string>
     <string name="tts_engine_preference_section_title" msgid="3861562305498624904">"Mecanismo preferencial"</string>
-    <string name="tts_general_section_title" msgid="8919671529502364567">"Gerais"</string>
+    <string name="tts_general_section_title" msgid="8919671529502364567">"Geral"</string>
     <string name="tts_reset_speech_pitch_title" msgid="7149398585468413246">"Redefinir o tom de voz"</string>
     <string name="tts_reset_speech_pitch_summary" msgid="6822904157021406449">"Redefinir o tom de voz para o padrão."</string>
   <string-array name="tts_rate_entries">
@@ -660,8 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Clima"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Qualidade ­do ar"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info. de transmissão"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
-    <skip />
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Automação residencial"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Escolher a foto do perfil"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Ícone de usuário padrão"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"Teclado físico"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/arrays.xml b/packages/SettingsLib/res/values-pt-rPT/arrays.xml
index 985bd51..e323455 100644
--- a/packages/SettingsLib/res/values-pt-rPT/arrays.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"Utilizar seleção do sistema (predefinido)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"Áudio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+    <item msgid="2908219194098827570">"Áudio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"Utilizar seleção do sistema (predefinido)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"Áudio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+    <item msgid="3517061573669307965">"Áudio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"Utilizar seleção do sistema (predefinido)"</item>
     <item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index aa24330..63ce593d 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -661,6 +661,7 @@
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Qualidade do ar"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info. de transmissão"</string>
     <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Ctr. domésticos"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Espaço inteligente"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Escolha uma imagem do perfil"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Ícone do utilizador predefinido"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"Teclado físico"</string>
diff --git a/packages/SettingsLib/res/values-pt/arrays.xml b/packages/SettingsLib/res/values-pt/arrays.xml
index 1883ef3..f218fab 100644
--- a/packages/SettingsLib/res/values-pt/arrays.xml
+++ b/packages/SettingsLib/res/values-pt/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"Usar seleção do sistema (padrão)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"Áudio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+    <item msgid="2908219194098827570">"Áudio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"Usar seleção do sistema (padrão)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"Áudio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+    <item msgid="3517061573669307965">"Áudio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"Usar seleção do sistema (padrão)"</item>
     <item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 9569005..8c1e83d 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -208,7 +208,7 @@
     <string name="tts_engine_settings_title" msgid="7849477533103566291">"Configurações para <xliff:g id="TTS_ENGINE_NAME">%s</xliff:g>"</string>
     <string name="tts_engine_settings_button" msgid="477155276199968948">"Iniciar configurações do mecanismo"</string>
     <string name="tts_engine_preference_section_title" msgid="3861562305498624904">"Mecanismo preferencial"</string>
-    <string name="tts_general_section_title" msgid="8919671529502364567">"Gerais"</string>
+    <string name="tts_general_section_title" msgid="8919671529502364567">"Geral"</string>
     <string name="tts_reset_speech_pitch_title" msgid="7149398585468413246">"Redefinir o tom de voz"</string>
     <string name="tts_reset_speech_pitch_summary" msgid="6822904157021406449">"Redefinir o tom de voz para o padrão."</string>
   <string-array name="tts_rate_entries">
@@ -660,8 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Clima"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Qualidade ­do ar"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info. de transmissão"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
-    <skip />
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Automação residencial"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Escolher a foto do perfil"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Ícone de usuário padrão"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"Teclado físico"</string>
diff --git a/packages/SettingsLib/res/values-ro/arrays.xml b/packages/SettingsLib/res/values-ro/arrays.xml
index f1e9986..34b0ac9 100644
--- a/packages/SettingsLib/res/values-ro/arrays.xml
+++ b/packages/SettingsLib/res/values-ro/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"Folosiți selectarea sistemului (prestabilit)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+    <item msgid="2908219194098827570">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"Folosiți selectarea sistemului (prestabilit)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+    <item msgid="3517061573669307965">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"Folosiți selectarea sistemului (prestabilit)"</item>
     <item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 75b37d5..4702b6a 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -660,8 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Meteo"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Calitatea aerului"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Informații artiști"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
-    <skip />
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Controlul locuinței"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Alegeți o fotografie de profil"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Pictograma prestabilită a utilizatorului"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"Tastatură fizică"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 568a41d..2b6250b 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Погода"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Качество воздуха"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Данные о трансляции"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Автоматизация дома"</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"Выберите фото профиля"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Значок пользователя по умолчанию"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 4f66739..9318c8d 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"කාලගුණය"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"වායු ගුණත්වය"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"විකාශ තතු"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"නිවෙස් පාලන"</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"පැතිකඩ පින්තූරයක් තේරීම"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"පෙරනිමි පරිශීලක නිරූපකය"</string>
diff --git a/packages/SettingsLib/res/values-sk/arrays.xml b/packages/SettingsLib/res/values-sk/arrays.xml
index 370b23f..bbfe969 100644
--- a/packages/SettingsLib/res/values-sk/arrays.xml
+++ b/packages/SettingsLib/res/values-sk/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"Použiť voľbu systému (predvolené)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"Zvuk: <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+    <item msgid="2908219194098827570">"Zvuk: <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"Použiť voľbu systému (predvolené)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"Zvuk: <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+    <item msgid="3517061573669307965">"Zvuk: <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"Použiť voľbu systému (predvolené)"</item>
     <item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 226381c..6dee1e3 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -660,8 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Počasie"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Kvalita vzduchu"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Informácie o prenose"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
-    <skip />
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Ovládanie domácnosti"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Výber profilovej fotky"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Predvolená ikona používateľa"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"Fyzická klávesnica"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index b16ff95..c35ee7a 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Vreme"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Kakovost zraka"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"O zasedbi"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Nadzor doma"</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"Izbira profilne slike"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Privzeta ikona uporabnika"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 028d82d..a92ef7c 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Moti"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Cilësia e ajrit"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Të dhënat e aktorëve"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Kontrollet e shtëpisë"</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"Zgjidh një fotografi profili"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Ikona e parazgjedhur e përdoruesit"</string>
diff --git a/packages/SettingsLib/res/values-sr/arrays.xml b/packages/SettingsLib/res/values-sr/arrays.xml
index 7e198bf..a95e47b 100644
--- a/packages/SettingsLib/res/values-sr/arrays.xml
+++ b/packages/SettingsLib/res/values-sr/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"Користи избор система (подразумевано)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> аудио"</item>
+    <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> аудио"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"Користи избор система (подразумевано)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> аудио"</item>
+    <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> аудио"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"Користи избор система (подразумевано)"</item>
     <item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 55252f2..dee7f9d 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -660,8 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Време"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Квалитет ваздуха"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Подаци о пребацивању"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
-    <skip />
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Управљање домом"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"SmartSpace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Одаберите слику профила"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Подразумевана икона корисника"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"Физичка тастатура"</string>
diff --git a/packages/SettingsLib/res/values-sv/arrays.xml b/packages/SettingsLib/res/values-sv/arrays.xml
index f99a85b..c63465c 100644
--- a/packages/SettingsLib/res/values-sv/arrays.xml
+++ b/packages/SettingsLib/res/values-sv/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"Använd systemval (standardinställning)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>-ljud"</item>
+    <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>-ljud"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"Använd systemval (standardinställning)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>-ljud"</item>
+    <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>-ljud"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"Använd systemval (standardinställning)"</item>
     <item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 7339868..09b3d7a 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -660,8 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Väder"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Luftkvalitet"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info om rollistan"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
-    <skip />
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Hemstyrning"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Välj en profilbild"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Ikon för standardanvändare"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"Fysiskt tangentbord"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index f8d3f9d..63a732d 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Hali ya Hewa"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Ubora wa Hewa"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Maelezo ya Wahusika"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Udhibiti wa Vifaa Nyumbani"</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"Chagua picha ya wasifu"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Aikoni chaguomsingi ya mtumiaji"</string>
diff --git a/packages/SettingsLib/res/values-ta/arrays.xml b/packages/SettingsLib/res/values-ta/arrays.xml
index a0f1fa6..957bd61 100644
--- a/packages/SettingsLib/res/values-ta/arrays.xml
+++ b/packages/SettingsLib/res/values-ta/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"சாதனத் தேர்வைப் பயன்படுத்து (இயல்பு)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> ஆடியோ"</item>
+    <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> ஆடியோ"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"சாதனத் தேர்வைப் பயன்படுத்து (இயல்பு)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> ஆடியோ"</item>
+    <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> ஆடியோ"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"சாதனத் தேர்வைப் பயன்படுத்து (இயல்பு)"</item>
     <item msgid="8003118270854840095">"44.1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index f03ef24..1f71788 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -660,8 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"வானிலை"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"காற்றின் தரம்"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"அலைபரப்புத் தகவல்"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
-    <skip />
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"ஹோம் கன்ட்ரோல்கள்"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"சுயவிவரப் படத்தைத் தேர்வுசெய்யுங்கள்"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"இயல்புநிலைப் பயனர் ஐகான்"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"கீபோர்டு"</string>
diff --git a/packages/SettingsLib/res/values-te/arrays.xml b/packages/SettingsLib/res/values-te/arrays.xml
index 18a2758..d4361e5 100644
--- a/packages/SettingsLib/res/values-te/arrays.xml
+++ b/packages/SettingsLib/res/values-te/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"సిస్టమ్ ఎంపికను ఉపయోగించండి (ఆటోమేటిక్)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> ఆడియో"</item>
+    <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> ఆడియో"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"సిస్టమ్ ఎంపికను ఉపయోగించండి (ఆటోమేటిక్)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> ఆడియో"</item>
+    <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> ఆడియో"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"సిస్టమ్ ఎంపికను ఉపయోగించండి (ఆటోమేటిక్)"</item>
     <item msgid="8003118270854840095">"44.1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 9e61db1..592810e 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -661,6 +661,7 @@
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"గాలి క్వాలిటీ"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"కాస్ట్ సమాచారం"</string>
     <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"హోమ్ కంట్రోల్స్"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"స్మార్ట్‌స్పేస్"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"ప్రొఫైల్ ఫోటోను ఎంచుకోండి"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"ఆటోమేటిక్ సెట్టింగ్ యూజర్ చిహ్నం"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"భౌతిక కీబోర్డ్"</string>
diff --git a/packages/SettingsLib/res/values-th/arrays.xml b/packages/SettingsLib/res/values-th/arrays.xml
index 04a5f4d..782e95e 100644
--- a/packages/SettingsLib/res/values-th/arrays.xml
+++ b/packages/SettingsLib/res/values-th/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"ใช้การเลือกของระบบ (ค่าเริ่มต้น)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"เสียง <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+    <item msgid="2908219194098827570">"เสียง <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"ใช้การเลือกของระบบ (ค่าเริ่มต้น)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"เสียง <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+    <item msgid="3517061573669307965">"เสียง <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"ใช้การเลือกของระบบ (ค่าเริ่มต้น)"</item>
     <item msgid="8003118270854840095">"44.1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index b68682b..aa01af7 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -660,8 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"สภาพอากาศ"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"คุณภาพอากาศ"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"ข้อมูลแคสต์"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
-    <skip />
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"ระบบควบคุมอุปกรณ์ในบ้าน"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"เลือกรูปโปรไฟล์"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"ไอคอนผู้ใช้เริ่มต้น"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"แป้นพิมพ์จริง"</string>
diff --git a/packages/SettingsLib/res/values-tl/arrays.xml b/packages/SettingsLib/res/values-tl/arrays.xml
index 59cb1f3..19d3423 100644
--- a/packages/SettingsLib/res/values-tl/arrays.xml
+++ b/packages/SettingsLib/res/values-tl/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"Gamitin ang Pagpili ng System (Default)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> na audio"</item>
+    <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> na audio"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"Gamitin ang Pagpili ng System (Default)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> na audio"</item>
+    <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> na audio"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"Gamitin ang Pagpili ng System (Default)"</item>
     <item msgid="8003118270854840095">"44.1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 9663c75..c2f2035 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -660,8 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Lagay ng Panahon"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Kalidad ng Hangin"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Impormasyon ng Cast"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
-    <skip />
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Home Controls"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Pumili ng larawan sa profile"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Icon ng default na user"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"Pisikal na keyboard"</string>
diff --git a/packages/SettingsLib/res/values-tr/arrays.xml b/packages/SettingsLib/res/values-tr/arrays.xml
index 5ed35fa..37891ae 100644
--- a/packages/SettingsLib/res/values-tr/arrays.xml
+++ b/packages/SettingsLib/res/values-tr/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"Sistem Seçimini Kullan (Varsayılan)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> ses"</item>
+    <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> ses"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"Sistem Seçimini Kullan (Varsayılan)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> ses"</item>
+    <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> ses"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"Sistem Seçimini Kullan (Varsayılan)"</item>
     <item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 982c663..0bc9cc2 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -660,8 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Hava durumu"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Hava Kalitesi"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Yayın Bilgisi"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
-    <skip />
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Ev Kontrolleri"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Profil fotoğrafı seçin"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Varsayılan kullanıcı simgesi"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"Fiziksel klavye"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 4e1a8e0..03e3ef9 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Погода"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Якість повітря"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Акторський склад"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Автоматизація дому"</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"Виберіть зображення профілю"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Значок користувача за умовчанням"</string>
diff --git a/packages/SettingsLib/res/values-ur/arrays.xml b/packages/SettingsLib/res/values-ur/arrays.xml
index d097458..db9941e 100644
--- a/packages/SettingsLib/res/values-ur/arrays.xml
+++ b/packages/SettingsLib/res/values-ur/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"سسٹم انتخاب کا استعمال کریں (ڈیفالٹ)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> آڈیو"</item>
+    <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> آڈیو"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"سسٹم انتخاب کا استعمال کریں (ڈیفالٹ)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> آڈیو"</item>
+    <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> آڈیو"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"سسٹم انتخاب کا استعمال کریں (ڈیفالٹ)"</item>
     <item msgid="8003118270854840095">"44.1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 41c53aa..cac1b6c 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -661,6 +661,7 @@
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"ہوا کا معیار"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"کاسٹ کرنے کی معلومات"</string>
     <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"ہوم کنٹرولز"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"پروفائل کی تصویر منتخب کریں"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"ڈیفالٹ صارف کا آئیکن"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"فزیکل کی بورڈ"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 5be68d5..cae3814 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Ob-havo"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Havo sifati"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Translatsiya axboroti"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Uy boshqaruvi"</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"Profil rasmini tanlash"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Foydalanuvchining standart belgisi"</string>
diff --git a/packages/SettingsLib/res/values-vi/arrays.xml b/packages/SettingsLib/res/values-vi/arrays.xml
index 31867e2..ee599d6 100644
--- a/packages/SettingsLib/res/values-vi/arrays.xml
+++ b/packages/SettingsLib/res/values-vi/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"Sử dụng lựa chọn của hệ thống (Mặc định)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"Âm thanh <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+    <item msgid="2908219194098827570">"Âm thanh <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"Sử dụng lựa chọn của hệ thống (Mặc định)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"Âm thanh <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+    <item msgid="3517061573669307965">"Âm thanh <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"Sử dụng lựa chọn của hệ thống (Mặc định)"</item>
     <item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index fa8be1e..1995e705 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -660,8 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Thời tiết"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Chất lượng không khí"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Thông tin về dàn nghệ sĩ"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
-    <skip />
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Điều khiển nhà"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Chọn một ảnh hồ sơ"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Biểu tượng người dùng mặc định"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"Bàn phím thực"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 3291dad..c478085 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -660,7 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"天气"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"空气质量"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"投放信息"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"家居控制"</string>
+    <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
     <skip />
     <string name="avatar_picker_title" msgid="8492884172713170652">"选择个人资料照片"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"默认用户图标"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/arrays.xml b/packages/SettingsLib/res/values-zh-rHK/arrays.xml
index 87f3825..a84f0e2 100644
--- a/packages/SettingsLib/res/values-zh-rHK/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"使用系統選擇 (預設)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> 音訊"</item>
+    <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> 音訊"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"使用系統選擇 (預設)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> 音訊"</item>
+    <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> 音訊"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"使用系統選擇 (預設)"</item>
     <item msgid="8003118270854840095">"44.1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 5b1d845..b4667a8 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -660,8 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"天氣"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"空氣質素"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"投放資料"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
-    <skip />
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"智能家居"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"智慧空間"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"選擇個人檔案相片"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"預設使用者圖示"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"實體鍵盤"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/arrays.xml b/packages/SettingsLib/res/values-zh-rTW/arrays.xml
index 529287f..66aaa56b 100644
--- a/packages/SettingsLib/res/values-zh-rTW/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"map13"</item>
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"系統自動選擇 (預設)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"AAC"</item>
+    <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> 音訊"</item>
+    <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> 音訊"</item>
+    <item msgid="3825367753087348007">"LDAC"</item>
+    <item msgid="328951785723550863">"LC3"</item>
+    <item msgid="506175145534048710">"Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"系統自動選擇 (預設)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"AAC"</item>
+    <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> 音訊"</item>
+    <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> 音訊"</item>
+    <item msgid="2553206901068987657">"LDAC"</item>
+    <item msgid="3940992993241040716">"LC3"</item>
+    <item msgid="7940970833006181407">"Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"系統自動選擇 (預設)"</item>
     <item msgid="8003118270854840095">"44.1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 6b3b45e..8097022 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -660,8 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"天氣"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"空氣品質"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"演出者資訊"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
-    <skip />
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"居家控制系統"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"智慧空間"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"選擇個人資料相片"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"預設使用者圖示"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"實體鍵盤"</string>
diff --git a/packages/SettingsLib/res/values-zu/arrays.xml b/packages/SettingsLib/res/values-zu/arrays.xml
index 59ead86..0494f1c 100644
--- a/packages/SettingsLib/res/values-zu/arrays.xml
+++ b/packages/SettingsLib/res/values-zu/arrays.xml
@@ -85,10 +85,26 @@
     <item msgid="7073042887003102964">"Imephu13"</item>
     <item msgid="8147982633566548515">"Imephu14"</item>
   </string-array>
-    <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
-    <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
-    <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+  <string-array name="bluetooth_a2dp_codec_titles">
+    <item msgid="2494959071796102843">"Sebenzisa ukukhetha kwesistimu (Okuzenzakalelayo)"</item>
+    <item msgid="4055460186095649420">"SBC"</item>
+    <item msgid="720249083677397051">"I-AAC"</item>
+    <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> umsindo"</item>
+    <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> umsindo"</item>
+    <item msgid="3825367753087348007">"I-LDAC"</item>
+    <item msgid="328951785723550863">"I-LC3"</item>
+    <item msgid="506175145534048710">"I-Opus"</item>
+  </string-array>
+  <string-array name="bluetooth_a2dp_codec_summaries">
+    <item msgid="8868109554557331312">"Sebenzisa ukukhetha kwesistimu (Okuzenzakalelayo)"</item>
+    <item msgid="9024885861221697796">"SBC"</item>
+    <item msgid="4688890470703790013">"I-AAC"</item>
+    <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> umsindo"</item>
+    <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> umsindo"</item>
+    <item msgid="2553206901068987657">"I-LDAC"</item>
+    <item msgid="3940992993241040716">"I-LC3"</item>
+    <item msgid="7940970833006181407">"I-Opus"</item>
+  </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"Sebenzisa ukukhetha kwesistimu (Okuzenzakalelayo)"</item>
     <item msgid="8003118270854840095">"44.1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index d5a52c3..2321ace 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -660,8 +660,8 @@
     <string name="dream_complication_title_weather" msgid="598609151677172783">"Isimo sezulu"</string>
     <string name="dream_complication_title_aqi" msgid="4587552608957834110">"Ikhwalithi Yomoya"</string>
     <string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Ulwazi Lokusakaza"</string>
-    <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
-    <skip />
+    <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Izilawuli Zasekhaya"</string>
+    <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"I-Smartspace"</string>
     <string name="avatar_picker_title" msgid="8492884172713170652">"Khetha isithombe sephrofayela"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Isithonjana somsebenzisi sokuzenzakalelayo"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"Ikhibhodi ephathekayo"</string>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 5795fd4..11cb9c1 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -264,12 +264,12 @@
 
     <!-- Bluetooth settings.  The user-visible string that is used whenever referring to the Hearing Aid profile. -->
     <string name="bluetooth_profile_hearing_aid">Hearing Aids</string>
-    <!-- Bluetooth settings.  The user-visible string that is used whenever referring to the LE_AUDIO profile. -->
-    <string name="bluetooth_profile_le_audio">LE_AUDIO</string>
+    <!-- Bluetooth settings.  The user-visible string that is used whenever referring to the LE audio profile. -->
+    <string name="bluetooth_profile_le_audio">LE audio</string>
     <!-- Bluetooth settings.  Connection options screen.  The summary for the Hearing Aid checkbox preference when Hearing Aid is connected. -->
     <string name="bluetooth_hearing_aid_profile_summary_connected">Connected to Hearing Aids</string>
-    <!-- Bluetooth settings.  Connection options screen.  The summary for the LE_AUDIO checkbox preference when LE_AUDIO is connected. -->
-    <string name="bluetooth_le_audio_profile_summary_connected">Connected to LE_AUDIO</string>
+    <!-- Bluetooth settings.  Connection options screen.  The summary for the LE audio checkbox preference when LE audio is connected. -->
+    <string name="bluetooth_le_audio_profile_summary_connected">Connected to LE audio</string>
 
     <!-- Bluetooth settings.  Connection options screen.  The summary for the A2DP checkbox preference when A2DP is connected. -->
     <string name="bluetooth_a2dp_profile_summary_connected">Connected to media audio</string>
@@ -962,6 +962,9 @@
     <!-- UI debug setting: enable freeform window support summary [CHAR LIMIT=150] -->
     <string name="enable_freeform_support_summary">Enable support for experimental freeform windows.</string>
 
+    <!-- UI debug setting: enable desktop mode [CHAR LIMIT=25] -->
+    <string name="desktop_mode">Desktop mode</string>
+
     <!-- Local (desktop) backup password menu title [CHAR LIMIT=25] -->
     <string name="local_backup_password_title">Desktop backup password</string>
     <!-- Summary text of the "local backup password" setting when the user has not supplied a password -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
index 7fbd100..cd3242a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
@@ -297,6 +297,9 @@
                     mCachedDevices.remove(i);
                 }
             }
+
+            // To clear the SetMemberPair flag when the Bluetooth is turning off.
+            mOngoingSetMemberPair = null;
         }
     }
 
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/ButtonPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/ButtonPreferenceTest.java
index 625b214..d78f8e7 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/ButtonPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/ButtonPreferenceTest.java
@@ -63,6 +63,7 @@
 
         final Button button = mPreference.getButton();
         assertThat(button.getText().toString()).isEqualTo(testTitle);
+        assertThat(mPreference.getTitle().toString()).isEqualTo(testTitle);
     }
 
     @Test
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index b1ce3bf..2209ff5 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -98,6 +98,7 @@
                     Settings.System.VOLUME_VOICE, // deprecated since API 2?
                     Settings.System.WHEN_TO_MAKE_WIFI_CALLS, // bug?
                     Settings.System.WINDOW_ORIENTATION_LISTENER_LOG, // used for debugging only
+                    Settings.System.DESKTOP_MODE, // developer setting for internal prototyping
                     Settings.System.MIN_REFRESH_RATE, // depends on hardware capabilities
                     Settings.System.PEAK_REFRESH_RATE, // depends on hardware capabilities
                     Settings.System.SCREEN_BRIGHTNESS_FLOAT,
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
index ff64c78..d427a57 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
@@ -485,7 +485,13 @@
         val out = mutableListOf<List<PositionedGlyphs>>()
         for (lineNo in 0 until layout.lineCount) { // Shape all lines.
             val lineStart = layout.getLineStart(lineNo)
-            val count = layout.getLineEnd(lineNo) - lineStart
+            var count = layout.getLineEnd(lineNo) - lineStart
+            // Do not render the last character in the line if it's a newline and unprintable
+            val last = lineStart + count - 1
+            if (last > lineStart && last < layout.text.length && layout.text[last] == '\n') {
+                count--
+            }
+
             val runs = mutableListOf<PositionedGlyphs>()
             TextShaper.shapeText(layout.text, lineStart, count, layout.textDirectionHeuristic,
                     paint) { _, _, glyphs, _ ->
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/BindServiceViaContextDetector.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/BindServiceViaContextDetector.kt
new file mode 100644
index 0000000..925fae0e
--- /dev/null
+++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/BindServiceViaContextDetector.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.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
+
+@Suppress("UnstableApiUsage")
+class BindServiceViaContextDetector : Detector(), SourceCodeScanner {
+
+    override fun getApplicableMethodNames(): List<String> {
+        return listOf("bindService", "bindServiceAsUser", "unbindService")
+    }
+
+    override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
+        if (context.evaluator.isMemberInSubClassOf(method, "android.content.Context")) {
+            context.report(
+                    ISSUE,
+                    method,
+                    context.getNameLocation(node),
+                    "Binding or unbinding services are synchronous calls, please make " +
+                            "sure you're on a @Background Executor."
+            )
+        }
+    }
+
+    companion object {
+        @JvmField
+        val ISSUE: Issue =
+            Issue.create(
+                id = "BindServiceViaContextDetector",
+                briefDescription = "Service bound/unbound via Context, please make sure " +
+                        "you're on a background thread.",
+                explanation =
+                "Binding or unbinding services are synchronous calls to ActivityManager, " +
+                        "they usually take multiple milliseconds to complete and will make" +
+                        "the caller drop frames. Make sure you're on a @Background Executor.",
+                category = Category.PERFORMANCE,
+                priority = 8,
+                severity = Severity.WARNING,
+                implementation =
+                Implementation(BindServiceViaContextDetector::class.java, Scope.JAVA_FILE_SCOPE)
+            )
+    }
+}
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/GetMainLooperViaContextDetector.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/GetMainLooperViaContextDetector.kt
new file mode 100644
index 0000000..a629eee
--- /dev/null
+++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/GetMainLooperViaContextDetector.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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
+
+@Suppress("UnstableApiUsage")
+class GetMainLooperViaContextDetector : Detector(), SourceCodeScanner {
+
+    override fun getApplicableMethodNames(): List<String> {
+        return listOf("getMainThreadHandler", "getMainLooper", "getMainExecutor")
+    }
+
+    override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
+        if (context.evaluator.isMemberInSubClassOf(method, "android.content.Context")) {
+            context.report(
+                    ISSUE,
+                    method,
+                    context.getNameLocation(node),
+                    "Please inject a @Main Executor instead."
+            )
+        }
+    }
+
+    companion object {
+        @JvmField
+        val ISSUE: Issue =
+                Issue.create(
+                        id = "GetMainLooperViaContextDetector",
+                        briefDescription = "Please use idiomatic SystemUI executors, injecting " +
+                                "them via Dagger.",
+                        explanation = "Injecting the @Main Executor is preferred in order to make" +
+                                "dependencies explicit and increase testability. It's much " +
+                                "easier to pass a FakeExecutor on your test ctor than to " +
+                                "deal with loopers in unit tests.",
+                        category = Category.LINT,
+                        priority = 8,
+                        severity = Severity.WARNING,
+                        implementation = Implementation(GetMainLooperViaContextDetector::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
new file mode 100644
index 0000000..b72d03d
--- /dev/null
+++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/RegisterReceiverViaContextDetector.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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
+
+class RegisterReceiverViaContextDetector : Detector(), SourceCodeScanner {
+
+    override fun getApplicableMethodNames(): List<String> {
+        return listOf("registerReceiver", "registerReceiverAsUser", "registerReceiverForAllUsers")
+    }
+
+    override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
+        if (context.evaluator.isMemberInSubClassOf(method, "android.content.Context")) {
+            context.report(
+                    ISSUE,
+                    method,
+                    context.getNameLocation(node),
+                    "BroadcastReceivers should be registered via BroadcastDispatcher."
+            )
+        }
+    }
+
+    companion object {
+        @JvmField
+        val ISSUE: Issue =
+            Issue.create(
+                    id = "RegisterReceiverViaContextDetector",
+                    briefDescription = "Broadcast registrations via Context are blocking " +
+                            "calls. Please use BroadcastDispatcher.",
+                    explanation =
+                    "Context#registerReceiver is a blocking call to the system server, " +
+                            "making it very likely that you'll drop a frame. Please use " +
+                            "BroadcastDispatcher instead (or move this call to a " +
+                            "@Background Executor.)",
+                    category = Category.PERFORMANCE,
+                    priority = 8,
+                    severity = Severity.WARNING,
+                    implementation = Implementation(RegisterReceiverViaContextDetector::class.java,
+                            Scope.JAVA_FILE_SCOPE)
+            )
+    }
+}
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SoftwareBitmapDetector.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SoftwareBitmapDetector.kt
new file mode 100644
index 0000000..a584894
--- /dev/null
+++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SoftwareBitmapDetector.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.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.PsiElement
+import com.intellij.psi.PsiField
+import org.jetbrains.uast.UReferenceExpression
+
+@Suppress("UnstableApiUsage")
+class SoftwareBitmapDetector : Detector(), SourceCodeScanner {
+
+    override fun getApplicableReferenceNames(): List<String> {
+        return mutableListOf("ALPHA_8", "RGB_565", "ARGB_8888", "RGBA_F16", "RGBA_1010102")
+    }
+
+    override fun visitReference(
+            context: JavaContext,
+            reference: UReferenceExpression,
+            referenced: PsiElement
+    ) {
+
+        val evaluator = context.evaluator
+        if (evaluator.isMemberInClass(referenced as? PsiField, "android.graphics.Bitmap.Config")) {
+            context.report(
+                    ISSUE,
+                    referenced,
+                    context.getNameLocation(referenced),
+                    "Usage of Config.HARDWARE is highly encouraged."
+            )
+        }
+    }
+
+    companion object {
+        @JvmField
+        val ISSUE: Issue =
+            Issue.create(
+                id = "SoftwareBitmapDetector",
+                briefDescription = "Software bitmap detected. Please use Config.HARDWARE instead.",
+                explanation =
+                "Software bitmaps occupy twice as much memory, when compared to Config.HARDWARE. " +
+                        "In case you need to manipulate the pixels, please consider to either use" +
+                        "a shader (encouraged), or a short lived software bitmap.",
+                category = Category.PERFORMANCE,
+                priority = 8,
+                severity = Severity.WARNING,
+                implementation = Implementation(SoftwareBitmapDetector::class.java,
+                        Scope.JAVA_FILE_SCOPE)
+            )
+    }
+}
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
index 397a110..c7c73d3 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
@@ -27,7 +27,13 @@
 class SystemUIIssueRegistry : IssueRegistry() {
 
     override val issues: List<Issue>
-        get() = listOf(BroadcastSentViaContextDetector.ISSUE)
+        get() = listOf(
+                BindServiceViaContextDetector.ISSUE,
+                BroadcastSentViaContextDetector.ISSUE,
+                GetMainLooperViaContextDetector.ISSUE,
+                RegisterReceiverViaContextDetector.ISSUE,
+                SoftwareBitmapDetector.ISSUE,
+        )
 
     override val api: Int
         get() = CURRENT_API
diff --git a/packages/SystemUI/checks/tests/com/android/systemui/lint/BindServiceViaContextDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/systemui/lint/BindServiceViaContextDetectorTest.kt
new file mode 100644
index 0000000..bf685f7
--- /dev/null
+++ b/packages/SystemUI/checks/tests/com/android/systemui/lint/BindServiceViaContextDetectorTest.kt
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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
+
+class BindServiceViaContextDetectorTest : LintDetectorTest() {
+
+    override fun getDetector(): Detector = BindServiceViaContextDetector()
+    override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
+
+    override fun getIssues(): List<Issue> = listOf(
+            BindServiceViaContextDetector.ISSUE)
+
+    private val explanation = "Binding or unbinding services are synchronous calls"
+
+    @Test
+    fun testBindService() {
+        lint().files(
+                TestFiles.java(
+                        """
+                    package test.pkg;
+                    import android.content.Context;
+
+                    public class TestClass1 {
+                        public void bind(Context context) {
+                          Intent intent = new Intent(Intent.ACTION_VIEW);
+                          context.bindService(intent, null, 0);
+                        }
+                    }
+                """
+                ).indented(),
+                *stubs)
+                .issues(BindServiceViaContextDetector.ISSUE)
+                .run()
+                .expectWarningCount(1)
+                .expectContains(explanation)
+    }
+
+    @Test
+    fun testBindServiceAsUser() {
+        lint().files(
+                TestFiles.java(
+                        """
+                    package test.pkg;
+                    import android.content.Context;
+                    import android.os.UserHandle;
+
+                    public class TestClass1 {
+                        public void bind(Context context) {
+                          Intent intent = new Intent(Intent.ACTION_VIEW);
+                          context.bindServiceAsUser(intent, null, 0, UserHandle.ALL);
+                        }
+                    }
+                """
+                ).indented(),
+                *stubs)
+                .issues(BindServiceViaContextDetector.ISSUE)
+                .run()
+                .expectWarningCount(1)
+                .expectContains(explanation)
+    }
+
+    @Test
+    fun testUnbindService() {
+        lint().files(
+                TestFiles.java(
+                        """
+                    package test.pkg;
+                    import android.content.Context;
+                    import android.content.ServiceConnection;
+
+                    public class TestClass1 {
+                        public void unbind(Context context, ServiceConnection connection) {
+                          context.unbindService(connection);
+                        }
+                    }
+                """
+                ).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)
+}
diff --git a/packages/SystemUI/checks/tests/com/android/systemui/lint/GetMainLooperViaContextDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/systemui/lint/GetMainLooperViaContextDetectorTest.kt
new file mode 100644
index 0000000..ec761cd
--- /dev/null
+++ b/packages/SystemUI/checks/tests/com/android/systemui/lint/GetMainLooperViaContextDetectorTest.kt
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.systemui.lint
+
+import com.android.tools.lint.checks.infrastructure.LintDetectorTest
+import com.android.tools.lint.checks.infrastructure.TestFile
+import com.android.tools.lint.checks.infrastructure.TestFiles
+import com.android.tools.lint.checks.infrastructure.TestLintTask
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+import org.junit.Test
+
+class GetMainLooperViaContextDetectorTest : LintDetectorTest() {
+
+    override fun getDetector(): Detector = GetMainLooperViaContextDetector()
+    override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
+
+    override fun getIssues(): List<Issue> = listOf(GetMainLooperViaContextDetector.ISSUE)
+
+    private val explanation = "Please inject a @Main Executor instead."
+
+    @Test
+    fun testGetMainThreadHandler() {
+        lint().files(
+                TestFiles.java(
+                        """
+                    package test.pkg;
+                    import android.content.Context;
+                    import android.os.Handler;
+
+                    public class TestClass1 {
+                        public void test(Context context) {
+                          Handler mainThreadHandler = context.getMainThreadHandler();
+                        }
+                    }
+                """
+                ).indented(),
+                *stubs)
+                .issues(GetMainLooperViaContextDetector.ISSUE)
+                .run()
+                .expectWarningCount(1)
+                .expectContains(explanation)
+    }
+
+    @Test
+    fun testGetMainLooper() {
+        lint().files(
+                TestFiles.java(
+                        """
+                    package test.pkg;
+                    import android.content.Context;
+                    import android.os.Looper;
+
+                    public class TestClass1 {
+                        public void test(Context context) {
+                          Looper mainLooper = context.getMainLooper();
+                        }
+                    }
+                """
+                ).indented(),
+                *stubs)
+                .issues(GetMainLooperViaContextDetector.ISSUE)
+                .run()
+                .expectWarningCount(1)
+                .expectContains(explanation)
+    }
+
+    @Test
+    fun testGetMainExecutor() {
+        lint().files(
+                TestFiles.java(
+                        """
+                    package test.pkg;
+                    import android.content.Context;
+                    import java.util.concurrent.Executor;
+
+                    public class TestClass1 {
+                        public void test(Context context) {
+                          Executor mainExecutor = context.getMainExecutor();
+                        }
+                    }
+                """
+                ).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)
+}
diff --git a/packages/SystemUI/checks/tests/com/android/systemui/lint/RegisterReceiverViaContextDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/systemui/lint/RegisterReceiverViaContextDetectorTest.kt
new file mode 100644
index 0000000..76c0519
--- /dev/null
+++ b/packages/SystemUI/checks/tests/com/android/systemui/lint/RegisterReceiverViaContextDetectorTest.kt
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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
+
+class RegisterReceiverViaContextDetectorTest : LintDetectorTest() {
+
+    override fun getDetector(): Detector = RegisterReceiverViaContextDetector()
+    override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
+
+    override fun getIssues(): List<Issue> = listOf(
+            RegisterReceiverViaContextDetector.ISSUE)
+
+    private val explanation = "BroadcastReceivers should be registered via BroadcastDispatcher."
+
+    @Test
+    fun testRegisterReceiver() {
+        lint().files(
+                TestFiles.java(
+                        """
+                    package test.pkg;
+                    import android.content.BroadcastReceiver;
+                    import android.content.Context;
+                    import android.content.IntentFilter;
+
+                    public class TestClass1 {
+                        public void bind(Context context, BroadcastReceiver receiver,
+                            IntentFilter filter) {
+                          context.registerReceiver(receiver, filter, 0);
+                        }
+                    }
+                """
+                ).indented(),
+                *stubs)
+                .issues(RegisterReceiverViaContextDetector.ISSUE)
+                .run()
+                .expectWarningCount(1)
+                .expectContains(explanation)
+    }
+
+    @Test
+    fun testRegisterReceiverAsUser() {
+        lint().files(
+                TestFiles.java(
+                        """
+                    package test.pkg;
+                    import android.content.BroadcastReceiver;
+                    import android.content.Context;
+                    import android.content.IntentFilter;
+                    import android.os.Handler;
+                    import android.os.UserHandle;
+
+                    public class TestClass1 {
+                        public void bind(Context context, BroadcastReceiver receiver,
+                            IntentFilter filter, Handler handler) {
+                          context.registerReceiverAsUser(receiver, UserHandle.ALL, filter,
+                            "permission", handler);
+                        }
+                    }
+                """
+                ).indented(),
+                *stubs)
+                .issues(RegisterReceiverViaContextDetector.ISSUE)
+                .run()
+                .expectWarningCount(1)
+                .expectContains(explanation)
+    }
+
+    @Test
+    fun testRegisterReceiverForAllUsers() {
+        lint().files(
+                TestFiles.java(
+                        """
+                    package test.pkg;
+                    import android.content.BroadcastReceiver;
+                    import android.content.Context;
+                    import android.content.IntentFilter;
+                    import android.os.Handler;
+                    import android.os.UserHandle;
+
+                    public class TestClass1 {
+                        public void bind(Context context, BroadcastReceiver receiver,
+                            IntentFilter filter, Handler handler) {
+                          context.registerReceiverForAllUsers(receiver, filter, "permission",
+                            handler);
+                        }
+                    }
+                """
+                ).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)
+}
diff --git a/packages/SystemUI/checks/tests/com/android/systemui/lint/SoftwareBitmapDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/systemui/lint/SoftwareBitmapDetectorTest.kt
new file mode 100644
index 0000000..890f2b8
--- /dev/null
+++ b/packages/SystemUI/checks/tests/com/android/systemui/lint/SoftwareBitmapDetectorTest.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.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 SoftwareBitmapDetectorTest : LintDetectorTest() {
+
+    override fun getDetector(): Detector = SoftwareBitmapDetector()
+    override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
+
+    override fun getIssues(): List<Issue> = listOf(SoftwareBitmapDetector.ISSUE)
+
+    private val explanation = "Usage of Config.HARDWARE is highly encouraged."
+
+    @Test
+    fun testSoftwareBitmap() {
+        lint().files(
+                TestFiles.java(
+                        """
+                    import android.graphics.Bitmap;
+
+                    public class TestClass1 {
+                        public void test() {
+                          Bitmap.createBitmap(300, 300, Bitmap.Config.RGB_565);
+                          Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888);
+                        }
+                    }
+                """
+                ).indented(),
+                *stubs)
+                .issues(SoftwareBitmapDetector.ISSUE)
+                .run()
+                .expectWarningCount(2)
+                .expectContains(explanation)
+    }
+
+    @Test
+    fun testHardwareBitmap() {
+        lint().files(
+                TestFiles.java(
+                        """
+                    import android.graphics.Bitmap;
+
+                    public class TestClass1 {
+                        public void test() {
+                          Bitmap.createBitmap(300, 300, Bitmap.Config.HARDWARE);
+                        }
+                    }
+                """
+                ).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)
+}
diff --git a/packages/SystemUI/compose/core/Android.bp b/packages/SystemUI/compose/core/Android.bp
new file mode 100644
index 0000000..4cfe392
--- /dev/null
+++ b/packages/SystemUI/compose/core/Android.bp
@@ -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 {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_packages_SystemUI_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+android_library {
+    name: "SystemUIComposeCore",
+    manifest: "AndroidManifest.xml",
+
+    srcs: [
+        "src/**/*.kt",
+    ],
+
+    static_libs: [
+        "androidx.compose.runtime_runtime",
+        "androidx.compose.material3_material3",
+    ],
+
+    kotlincflags: ["-Xjvm-default=all"],
+}
diff --git a/packages/SystemUI/compose/core/AndroidManifest.xml b/packages/SystemUI/compose/core/AndroidManifest.xml
new file mode 100644
index 0000000..83c442d
--- /dev/null
+++ b/packages/SystemUI/compose/core/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.systemui.compose.core">
+
+
+</manifest>
diff --git a/packages/SystemUI/compose/core/TEST_MAPPING b/packages/SystemUI/compose/core/TEST_MAPPING
new file mode 100644
index 0000000..dc243d2
--- /dev/null
+++ b/packages/SystemUI/compose/core/TEST_MAPPING
@@ -0,0 +1,37 @@
+{
+  "presubmit": [
+    {
+      "name": "SystemUIComposeCoreTests",
+      "options": [
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    },
+    {
+      "name": "SystemUIComposeFeaturesTests",
+      "options": [
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    },
+    {
+      "name": "SystemUIComposeGalleryTests",
+      "options": [
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/compose/core/src/com/android/systemui/compose/SystemUiController.kt b/packages/SystemUI/compose/core/src/com/android/systemui/compose/SystemUiController.kt
new file mode 100644
index 0000000..c9470c8
--- /dev/null
+++ b/packages/SystemUI/compose/core/src/com/android/systemui/compose/SystemUiController.kt
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.compose
+
+import android.app.Activity
+import android.content.Context
+import android.content.ContextWrapper
+import android.os.Build
+import android.view.View
+import android.view.Window
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.Stable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.compositeOver
+import androidx.compose.ui.graphics.luminance
+import androidx.compose.ui.graphics.toArgb
+import androidx.compose.ui.platform.LocalView
+import androidx.compose.ui.window.DialogWindowProvider
+import androidx.core.view.ViewCompat
+import androidx.core.view.WindowCompat
+import androidx.core.view.WindowInsetsCompat
+
+/**
+ * *************************************************************************************************
+ * This file was forked from
+ * https://github.com/google/accompanist/blob/main/systemuicontroller/src/main/java/com/google/accompanist/systemuicontroller/SystemUiController.kt
+ * and will be removed once it lands in AndroidX.
+ */
+
+/**
+ * A class which provides easy-to-use utilities for updating the System UI bar colors within Jetpack
+ * Compose.
+ *
+ * @sample com.google.accompanist.sample.systemuicontroller.SystemUiControllerSample
+ */
+@Stable
+interface SystemUiController {
+
+    /**
+     * Property which holds the status bar visibility. If set to true, show the status bar,
+     * otherwise hide the status bar.
+     */
+    var isStatusBarVisible: Boolean
+
+    /**
+     * Property which holds the navigation bar visibility. If set to true, show the navigation bar,
+     * otherwise hide the navigation bar.
+     */
+    var isNavigationBarVisible: Boolean
+
+    /**
+     * Property which holds the status & navigation bar visibility. If set to true, show both bars,
+     * otherwise hide both bars.
+     */
+    var isSystemBarsVisible: Boolean
+        get() = isNavigationBarVisible && isStatusBarVisible
+        set(value) {
+            isStatusBarVisible = value
+            isNavigationBarVisible = value
+        }
+
+    /**
+     * Set the status bar color.
+     *
+     * @param color The **desired** [Color] to set. This may require modification if running on an
+     * API level that only supports white status bar icons.
+     * @param darkIcons Whether dark status bar icons would be preferable.
+     * @param transformColorForLightContent A lambda which will be invoked to transform [color] if
+     * dark icons were requested but are not available. Defaults to applying a black scrim.
+     *
+     * @see statusBarDarkContentEnabled
+     */
+    fun setStatusBarColor(
+        color: Color,
+        darkIcons: Boolean = color.luminance() > 0.5f,
+        transformColorForLightContent: (Color) -> Color = BlackScrimmed
+    )
+
+    /**
+     * Set the navigation bar color.
+     *
+     * @param color The **desired** [Color] to set. This may require modification if running on an
+     * API level that only supports white navigation bar icons. Additionally this will be ignored
+     * and [Color.Transparent] will be used on API 29+ where gesture navigation is preferred or the
+     * system UI automatically applies background protection in other navigation modes.
+     * @param darkIcons Whether dark navigation bar icons would be preferable.
+     * @param navigationBarContrastEnforced Whether the system should ensure that the navigation bar
+     * has enough contrast when a fully transparent background is requested. Only supported on API
+     * 29+.
+     * @param transformColorForLightContent A lambda which will be invoked to transform [color] if
+     * dark icons were requested but are not available. Defaults to applying a black scrim.
+     *
+     * @see navigationBarDarkContentEnabled
+     * @see navigationBarContrastEnforced
+     */
+    fun setNavigationBarColor(
+        color: Color,
+        darkIcons: Boolean = color.luminance() > 0.5f,
+        navigationBarContrastEnforced: Boolean = true,
+        transformColorForLightContent: (Color) -> Color = BlackScrimmed
+    )
+
+    /**
+     * Set the status and navigation bars to [color].
+     *
+     * @see setStatusBarColor
+     * @see setNavigationBarColor
+     */
+    fun setSystemBarsColor(
+        color: Color,
+        darkIcons: Boolean = color.luminance() > 0.5f,
+        isNavigationBarContrastEnforced: Boolean = true,
+        transformColorForLightContent: (Color) -> Color = BlackScrimmed
+    ) {
+        setStatusBarColor(color, darkIcons, transformColorForLightContent)
+        setNavigationBarColor(
+            color,
+            darkIcons,
+            isNavigationBarContrastEnforced,
+            transformColorForLightContent
+        )
+    }
+
+    /** Property which holds whether the status bar icons + content are 'dark' or not. */
+    var statusBarDarkContentEnabled: Boolean
+
+    /** Property which holds whether the navigation bar icons + content are 'dark' or not. */
+    var navigationBarDarkContentEnabled: Boolean
+
+    /**
+     * Property which holds whether the status & navigation bar icons + content are 'dark' or not.
+     */
+    var systemBarsDarkContentEnabled: Boolean
+        get() = statusBarDarkContentEnabled && navigationBarDarkContentEnabled
+        set(value) {
+            statusBarDarkContentEnabled = value
+            navigationBarDarkContentEnabled = value
+        }
+
+    /**
+     * Property which holds whether the system is ensuring that the navigation bar has enough
+     * contrast when a fully transparent background is requested. Only has an affect when running on
+     * Android API 29+ devices.
+     */
+    var isNavigationBarContrastEnforced: Boolean
+}
+
+/**
+ * Remembers a [SystemUiController] for the given [window].
+ *
+ * If no [window] is provided, an attempt to find the correct [Window] is made.
+ *
+ * First, if the [LocalView]'s parent is a [DialogWindowProvider], then that dialog's [Window] will
+ * be used.
+ *
+ * Second, we attempt to find [Window] for the [Activity] containing the [LocalView].
+ *
+ * If none of these are found (such as may happen in a preview), then the functionality of the
+ * returned [SystemUiController] will be degraded, but won't throw an exception.
+ */
+@Composable
+fun rememberSystemUiController(
+    window: Window? = findWindow(),
+): SystemUiController {
+    val view = LocalView.current
+    return remember(view, window) { AndroidSystemUiController(view, window) }
+}
+
+@Composable
+private fun findWindow(): Window? =
+    (LocalView.current.parent as? DialogWindowProvider)?.window
+        ?: LocalView.current.context.findWindow()
+
+private tailrec fun Context.findWindow(): Window? =
+    when (this) {
+        is Activity -> window
+        is ContextWrapper -> baseContext.findWindow()
+        else -> null
+    }
+
+/**
+ * A helper class for setting the navigation and status bar colors for a [View], gracefully
+ * degrading behavior based upon API level.
+ *
+ * Typically you would use [rememberSystemUiController] to remember an instance of this.
+ */
+internal class AndroidSystemUiController(private val view: View, private val window: Window?) :
+    SystemUiController {
+    private val windowInsetsController = window?.let { WindowCompat.getInsetsController(it, view) }
+
+    override fun setStatusBarColor(
+        color: Color,
+        darkIcons: Boolean,
+        transformColorForLightContent: (Color) -> Color
+    ) {
+        statusBarDarkContentEnabled = darkIcons
+
+        window?.statusBarColor =
+            when {
+                darkIcons && windowInsetsController?.isAppearanceLightStatusBars != true -> {
+                    // If we're set to use dark icons, but our windowInsetsController call didn't
+                    // succeed (usually due to API level), we instead transform the color to
+                    // maintain contrast
+                    transformColorForLightContent(color)
+                }
+                else -> color
+            }.toArgb()
+    }
+
+    override fun setNavigationBarColor(
+        color: Color,
+        darkIcons: Boolean,
+        navigationBarContrastEnforced: Boolean,
+        transformColorForLightContent: (Color) -> Color
+    ) {
+        navigationBarDarkContentEnabled = darkIcons
+        isNavigationBarContrastEnforced = navigationBarContrastEnforced
+
+        window?.navigationBarColor =
+            when {
+                darkIcons && windowInsetsController?.isAppearanceLightNavigationBars != true -> {
+                    // If we're set to use dark icons, but our windowInsetsController call didn't
+                    // succeed (usually due to API level), we instead transform the color to
+                    // maintain contrast
+                    transformColorForLightContent(color)
+                }
+                else -> color
+            }.toArgb()
+    }
+
+    override var isStatusBarVisible: Boolean
+        get() {
+            return ViewCompat.getRootWindowInsets(view)
+                ?.isVisible(WindowInsetsCompat.Type.statusBars()) == true
+        }
+        set(value) {
+            if (value) {
+                windowInsetsController?.show(WindowInsetsCompat.Type.statusBars())
+            } else {
+                windowInsetsController?.hide(WindowInsetsCompat.Type.statusBars())
+            }
+        }
+
+    override var isNavigationBarVisible: Boolean
+        get() {
+            return ViewCompat.getRootWindowInsets(view)
+                ?.isVisible(WindowInsetsCompat.Type.navigationBars()) == true
+        }
+        set(value) {
+            if (value) {
+                windowInsetsController?.show(WindowInsetsCompat.Type.navigationBars())
+            } else {
+                windowInsetsController?.hide(WindowInsetsCompat.Type.navigationBars())
+            }
+        }
+
+    override var statusBarDarkContentEnabled: Boolean
+        get() = windowInsetsController?.isAppearanceLightStatusBars == true
+        set(value) {
+            windowInsetsController?.isAppearanceLightStatusBars = value
+        }
+
+    override var navigationBarDarkContentEnabled: Boolean
+        get() = windowInsetsController?.isAppearanceLightNavigationBars == true
+        set(value) {
+            windowInsetsController?.isAppearanceLightNavigationBars = value
+        }
+
+    override var isNavigationBarContrastEnforced: Boolean
+        get() = Build.VERSION.SDK_INT >= 29 && window?.isNavigationBarContrastEnforced == true
+        set(value) {
+            if (Build.VERSION.SDK_INT >= 29) {
+                window?.isNavigationBarContrastEnforced = value
+            }
+        }
+}
+
+private val BlackScrim = Color(0f, 0f, 0f, 0.3f) // 30% opaque black
+private val BlackScrimmed: (Color) -> Color = { original -> BlackScrim.compositeOver(original) }
diff --git a/packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/AndroidColorScheme.kt b/packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/AndroidColorScheme.kt
new file mode 100644
index 0000000..b8639e6
--- /dev/null
+++ b/packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/AndroidColorScheme.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.compose.theme
+
+import android.annotation.ColorInt
+import android.content.Context
+import androidx.compose.runtime.staticCompositionLocalOf
+import androidx.compose.ui.graphics.Color
+import com.android.internal.R
+
+/** CompositionLocal used to pass [AndroidColorScheme] down the tree. */
+val LocalAndroidColorScheme =
+    staticCompositionLocalOf<AndroidColorScheme> {
+        throw IllegalStateException(
+            "No AndroidColorScheme configured. Make sure to use LocalAndroidColorScheme in a " +
+                "Composable surrounded by a SystemUITheme {}."
+        )
+    }
+
+/**
+ * The Android color scheme.
+ *
+ * Important: Use M3 colors from MaterialTheme.colorScheme whenever possible instead. In the future,
+ * most of the colors in this class will be removed in favor of their M3 counterpart.
+ */
+class AndroidColorScheme internal constructor(context: Context) {
+    val colorPrimary = getColor(context, R.attr.colorPrimary)
+    val colorPrimaryDark = getColor(context, R.attr.colorPrimaryDark)
+    val colorAccent = getColor(context, R.attr.colorAccent)
+    val colorAccentPrimary = getColor(context, R.attr.colorAccentPrimary)
+    val colorAccentSecondary = getColor(context, R.attr.colorAccentSecondary)
+    val colorAccentTertiary = getColor(context, R.attr.colorAccentTertiary)
+    val colorAccentPrimaryVariant = getColor(context, R.attr.colorAccentPrimaryVariant)
+    val colorAccentSecondaryVariant = getColor(context, R.attr.colorAccentSecondaryVariant)
+    val colorAccentTertiaryVariant = getColor(context, R.attr.colorAccentTertiaryVariant)
+    val colorSurface = getColor(context, R.attr.colorSurface)
+    val colorSurfaceHighlight = getColor(context, R.attr.colorSurfaceHighlight)
+    val colorSurfaceVariant = getColor(context, R.attr.colorSurfaceVariant)
+    val colorSurfaceHeader = getColor(context, R.attr.colorSurfaceHeader)
+    val colorError = getColor(context, R.attr.colorError)
+    val colorBackground = getColor(context, R.attr.colorBackground)
+    val colorBackgroundFloating = getColor(context, R.attr.colorBackgroundFloating)
+    val panelColorBackground = getColor(context, R.attr.panelColorBackground)
+    val textColorPrimary = getColor(context, R.attr.textColorPrimary)
+    val textColorSecondary = getColor(context, R.attr.textColorSecondary)
+    val textColorTertiary = getColor(context, R.attr.textColorTertiary)
+    val textColorPrimaryInverse = getColor(context, R.attr.textColorPrimaryInverse)
+    val textColorSecondaryInverse = getColor(context, R.attr.textColorSecondaryInverse)
+    val textColorTertiaryInverse = getColor(context, R.attr.textColorTertiaryInverse)
+    val textColorOnAccent = getColor(context, R.attr.textColorOnAccent)
+    val colorForeground = getColor(context, R.attr.colorForeground)
+    val colorForegroundInverse = getColor(context, R.attr.colorForegroundInverse)
+
+    private fun getColor(context: Context, attr: Int): Color {
+        val ta = context.obtainStyledAttributes(intArrayOf(attr))
+        @ColorInt val color = ta.getColor(0, 0)
+        ta.recycle()
+        return Color(color)
+    }
+}
diff --git a/packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/SystemUITheme.kt b/packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/SystemUITheme.kt
new file mode 100644
index 0000000..79e3d3d
--- /dev/null
+++ b/packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/SystemUITheme.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.compose.theme
+
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Typography
+import androidx.compose.material3.dynamicDarkColorScheme
+import androidx.compose.material3.dynamicLightColorScheme
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.ui.platform.LocalContext
+
+/** The Material 3 theme that should wrap all SystemUI Composables. */
+@Composable
+fun SystemUITheme(
+    isDarkTheme: Boolean = isSystemInDarkTheme(),
+    content: @Composable () -> Unit,
+) {
+    val context = LocalContext.current
+
+    // TODO(b/230605885): Define our typography and color scheme.
+    val colorScheme =
+        if (isDarkTheme) {
+            dynamicDarkColorScheme(context)
+        } else {
+            dynamicLightColorScheme(context)
+        }
+    val androidColorScheme = AndroidColorScheme(context)
+    val typography = Typography()
+
+    MaterialTheme(colorScheme, typography = typography) {
+        CompositionLocalProvider(
+            LocalAndroidColorScheme provides androidColorScheme,
+        ) {
+            content()
+        }
+    }
+}
diff --git a/packages/SystemUI/compose/core/tests/Android.bp b/packages/SystemUI/compose/core/tests/Android.bp
new file mode 100644
index 0000000..f8023e2
--- /dev/null
+++ b/packages/SystemUI/compose/core/tests/Android.bp
@@ -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 {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_packages_SystemUI_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+// TODO(b/230606318): Make those host tests instead of device tests.
+android_test {
+    name: "SystemUIComposeCoreTests",
+    manifest: "AndroidManifest.xml",
+    test_suites: ["device-tests"],
+    sdk_version: "current",
+    certificate: "platform",
+
+    srcs: [
+        "src/**/*.kt",
+    ],
+
+    static_libs: [
+        "SystemUIComposeCore",
+
+        "androidx.test.runner",
+        "androidx.test.ext.junit",
+
+        "androidx.compose.runtime_runtime",
+        "androidx.compose.ui_ui-test-junit4",
+        "androidx.compose.ui_ui-test-manifest",
+    ],
+
+    kotlincflags: ["-Xjvm-default=enable"],
+}
diff --git a/packages/SystemUI/compose/core/tests/AndroidManifest.xml b/packages/SystemUI/compose/core/tests/AndroidManifest.xml
new file mode 100644
index 0000000..729ab98
--- /dev/null
+++ b/packages/SystemUI/compose/core/tests/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.systemui.compose.core.tests" >
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="com.android.systemui.compose.core.tests"
+                     android:label="Tests for SystemUIComposeCore"/>
+
+</manifest>
\ No newline at end of file
diff --git a/packages/SystemUI/compose/core/tests/src/com/android/systemui/compose/theme/SystemUIThemeTest.kt b/packages/SystemUI/compose/core/tests/src/com/android/systemui/compose/theme/SystemUIThemeTest.kt
new file mode 100644
index 0000000..20249f6
--- /dev/null
+++ b/packages/SystemUI/compose/core/tests/src/com/android/systemui/compose/theme/SystemUIThemeTest.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.compose.theme
+
+import androidx.compose.material3.Text
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import org.junit.Assert.assertThrows
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class SystemUIThemeTest {
+    @get:Rule val composeRule = createComposeRule()
+
+    @Test
+    fun testThemeShowsContent() {
+        composeRule.setContent { SystemUITheme { Text("foo") } }
+
+        composeRule.onNodeWithText("foo").assertIsDisplayed()
+    }
+
+    @Test
+    fun testAndroidColorsAreAvailableInsideTheme() {
+        composeRule.setContent {
+            SystemUITheme { Text("foo", color = LocalAndroidColorScheme.current.colorAccent) }
+        }
+
+        composeRule.onNodeWithText("foo").assertIsDisplayed()
+    }
+
+    @Test
+    fun testAccessingAndroidColorsWithoutThemeThrows() {
+        assertThrows(IllegalStateException::class.java) {
+            composeRule.setContent {
+                Text("foo", color = LocalAndroidColorScheme.current.colorAccent)
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/compose/features/Android.bp b/packages/SystemUI/compose/features/Android.bp
new file mode 100644
index 0000000..40218de
--- /dev/null
+++ b/packages/SystemUI/compose/features/Android.bp
@@ -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 {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_packages_SystemUI_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+android_library {
+    name: "SystemUIComposeFeatures",
+    manifest: "AndroidManifest.xml",
+
+    srcs: [
+        "src/**/*.kt",
+    ],
+
+    static_libs: [
+        "SystemUIComposeCore",
+
+        "androidx.compose.runtime_runtime",
+        "androidx.compose.material3_material3",
+    ],
+
+    kotlincflags: ["-Xjvm-default=all"],
+}
diff --git a/packages/SystemUI/compose/features/AndroidManifest.xml b/packages/SystemUI/compose/features/AndroidManifest.xml
new file mode 100644
index 0000000..0aea99d
--- /dev/null
+++ b/packages/SystemUI/compose/features/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.systemui.compose.features">
+
+
+</manifest>
diff --git a/packages/SystemUI/compose/features/TEST_MAPPING b/packages/SystemUI/compose/features/TEST_MAPPING
new file mode 100644
index 0000000..7430acb
--- /dev/null
+++ b/packages/SystemUI/compose/features/TEST_MAPPING
@@ -0,0 +1,26 @@
+{
+  "presubmit": [
+    {
+      "name": "SystemUIComposeFeaturesTests",
+      "options": [
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    },
+    {
+      "name": "SystemUIComposeGalleryTests",
+      "options": [
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/ExampleFeature.kt b/packages/SystemUI/compose/features/src/com/android/systemui/ExampleFeature.kt
new file mode 100644
index 0000000..c58c162
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/ExampleFeature.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui
+
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.BoxWithConstraints
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import kotlin.math.roundToInt
+
+/**
+ * This is an example Compose feature, which shows a text and a count that is incremented when
+ * clicked. We also show the max width available to this component, which is displayed either next
+ * to or below the text depending on that max width.
+ */
+@Composable
+fun ExampleFeature(text: String, modifier: Modifier = Modifier) {
+    BoxWithConstraints(modifier) {
+        val maxWidth = maxWidth
+        if (maxWidth < 600.dp) {
+            Column {
+                CounterTile(text)
+                Spacer(Modifier.size(16.dp))
+                MaxWidthTile(maxWidth)
+            }
+        } else {
+            Row {
+                CounterTile(text)
+                Spacer(Modifier.size(16.dp))
+                MaxWidthTile(maxWidth)
+            }
+        }
+    }
+}
+
+@Composable
+private fun CounterTile(text: String, modifier: Modifier = Modifier) {
+    Surface(
+        modifier,
+        color = MaterialTheme.colorScheme.primaryContainer,
+        shape = RoundedCornerShape(28.dp),
+    ) {
+        var count by remember { mutableStateOf(0) }
+        Column(
+            Modifier.clickable { count++ }.padding(16.dp),
+        ) {
+            Text(text)
+            Text("I was clicked $count times.")
+        }
+    }
+}
+
+@Composable
+private fun MaxWidthTile(maxWidth: Dp, modifier: Modifier = Modifier) {
+    Surface(
+        modifier,
+        color = MaterialTheme.colorScheme.tertiaryContainer,
+        shape = RoundedCornerShape(28.dp),
+    ) {
+        Text(
+            "The max available width to me is: ${maxWidth.value.roundToInt()}dp",
+            Modifier.padding(16.dp)
+        )
+    }
+}
diff --git a/packages/SystemUI/compose/features/tests/Android.bp b/packages/SystemUI/compose/features/tests/Android.bp
new file mode 100644
index 0000000..ff534bd
--- /dev/null
+++ b/packages/SystemUI/compose/features/tests/Android.bp
@@ -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 {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_packages_SystemUI_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+// TODO(b/230606318): Make those host tests instead of device tests.
+android_test {
+    name: "SystemUIComposeFeaturesTests",
+    manifest: "AndroidManifest.xml",
+    test_suites: ["device-tests"],
+    sdk_version: "current",
+    certificate: "platform",
+
+    srcs: [
+        "src/**/*.kt",
+    ],
+
+    static_libs: [
+        "SystemUIComposeFeatures",
+
+        "androidx.test.runner",
+        "androidx.test.ext.junit",
+
+        "androidx.compose.runtime_runtime",
+        "androidx.compose.ui_ui-test-junit4",
+        "androidx.compose.ui_ui-test-manifest",
+    ],
+
+    kotlincflags: ["-Xjvm-default=enable"],
+}
diff --git a/packages/SystemUI/compose/features/tests/AndroidManifest.xml b/packages/SystemUI/compose/features/tests/AndroidManifest.xml
new file mode 100644
index 0000000..5e54c1f
--- /dev/null
+++ b/packages/SystemUI/compose/features/tests/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.systemui.compose.features.tests" >
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="com.android.systemui.compose.features.tests"
+                     android:label="Tests for SystemUIComposeFeatures"/>
+
+</manifest>
\ No newline at end of file
diff --git a/packages/SystemUI/compose/features/tests/src/com/android/systemui/ExampleFeatureTest.kt b/packages/SystemUI/compose/features/tests/src/com/android/systemui/ExampleFeatureTest.kt
new file mode 100644
index 0000000..1c2e8fa
--- /dev/null
+++ b/packages/SystemUI/compose/features/tests/src/com/android/systemui/ExampleFeatureTest.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
+
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performClick
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class ExampleFeatureTest {
+    @get:Rule val composeRule = createComposeRule()
+
+    @Test
+    fun testProvidedTextIsDisplayed() {
+        composeRule.setContent { ExampleFeature("foo") }
+
+        composeRule.onNodeWithText("foo").assertIsDisplayed()
+    }
+
+    @Test
+    fun testCountIsIncreasedWhenClicking() {
+        composeRule.setContent { ExampleFeature("foo") }
+
+        composeRule.onNodeWithText("I was clicked 0 times.").assertIsDisplayed().performClick()
+        composeRule.onNodeWithText("I was clicked 1 times.").assertIsDisplayed()
+    }
+}
diff --git a/packages/SystemUI/compose/gallery/Android.bp b/packages/SystemUI/compose/gallery/Android.bp
new file mode 100644
index 0000000..40504dc
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/Android.bp
@@ -0,0 +1,72 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_packages_SystemUI_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+android_library {
+    name: "SystemUIComposeGalleryLib",
+    manifest: "AndroidManifest.xml",
+
+    srcs: [
+        "src/**/*.kt",
+    ],
+
+    resource_dirs: [
+        "res",
+    ],
+
+    static_libs: [
+        "SystemUI-core",
+        "SystemUIComposeCore",
+        "SystemUIComposeFeatures",
+
+        "androidx.compose.runtime_runtime",
+        "androidx.compose.material3_material3",
+        "androidx.compose.material_material-icons-extended",
+        "androidx.activity_activity-compose",
+        "androidx.navigation_navigation-compose",
+
+        "androidx.appcompat_appcompat",
+    ],
+
+    kotlincflags: ["-Xjvm-default=all"],
+}
+
+android_app {
+    name: "SystemUIComposeGallery",
+    defaults: ["platform_app_defaults"],
+    manifest: "app/AndroidManifest.xml",
+
+    static_libs: [
+        "SystemUIComposeGalleryLib",
+    ],
+
+    platform_apis: true,
+    system_ext_specific: true,
+    certificate: "platform",
+    privileged: true,
+
+    optimize: {
+        proguard_flags_files: ["proguard-rules.pro"],
+    },
+
+    dxflags: ["--multi-dex"],
+}
diff --git a/packages/SystemUI/compose/gallery/AndroidManifest.xml b/packages/SystemUI/compose/gallery/AndroidManifest.xml
new file mode 100644
index 0000000..2f30651
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/AndroidManifest.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="com.android.systemui.compose.gallery">
+    <!-- To emulate a display size and density. -->
+    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+
+    <application
+        android:name="android.app.Application"
+        android:appComponentFactory="androidx.core.app.AppComponentFactory"
+        tools:replace="android:name,android:appComponentFactory">
+        <!-- Disable providers from SystemUI -->
+        <provider android:name="com.android.systemui.keyguard.KeyguardSliceProvider"
+            android:authorities="com.android.systemui.test.keyguard.disabled"
+            android:enabled="false"
+            tools:replace="android:authorities"
+            tools:node="remove" />
+        <provider android:name="com.google.android.systemui.keyguard.KeyguardSliceProviderGoogle"
+            android:authorities="com.android.systemui.test.keyguard.disabled"
+            android:enabled="false"
+            tools:replace="android:authorities"
+            tools:node="remove" />
+        <provider android:name="com.android.keyguard.clock.ClockOptionsProvider"
+            android:authorities="com.android.systemui.test.keyguard.clock.disabled"
+            android:enabled="false"
+            tools:replace="android:authorities"
+            tools:node="remove" />
+        <provider android:name="com.android.systemui.people.PeopleProvider"
+            android:authorities="com.android.systemui.test.people.disabled"
+            android:enabled="false"
+            tools:replace="android:authorities"
+            tools:node="remove" />
+        <provider android:name="androidx.core.content.FileProvider"
+            android:authorities="com.android.systemui.test.fileprovider.disabled"
+            android:enabled="false"
+            tools:replace="android:authorities"
+            tools:node="remove"/>
+    </application>
+</manifest>
diff --git a/packages/SystemUI/compose/gallery/TEST_MAPPING b/packages/SystemUI/compose/gallery/TEST_MAPPING
new file mode 100644
index 0000000..c7f8a92
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+  "presubmit": [
+    {
+      "name": "SystemUIComposeGalleryTests",
+      "options": [
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/compose/gallery/app/AndroidManifest.xml b/packages/SystemUI/compose/gallery/app/AndroidManifest.xml
new file mode 100644
index 0000000..1f3fd8c
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/app/AndroidManifest.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="com.android.systemui.compose.gallery.app">
+    <application
+        android:allowBackup="true"
+        android:icon="@mipmap/ic_launcher"
+        android:label="@string/app_name"
+        android:roundIcon="@mipmap/ic_launcher_round"
+        android:supportsRtl="true"
+        android:theme="@style/Theme.SystemUI.Gallery"
+        tools:replace="android:icon,android:theme,android:label">
+        <activity
+            android:name="com.android.systemui.compose.gallery.GalleryActivity"
+            android:exported="true"
+            android:label="@string/app_name">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/packages/SystemUI/compose/gallery/proguard-rules.pro b/packages/SystemUI/compose/gallery/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/packages/SystemUI/compose/gallery/res/drawable-v24/ic_launcher_foreground.xml b/packages/SystemUI/compose/gallery/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..966abaf
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:aapt="http://schemas.android.com/aapt"
+    android:width="108dp"
+    android:height="108dp"
+    android:viewportHeight="108"
+    android:viewportWidth="108">
+  <path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
+    <aapt:attr name="android:fillColor">
+      <gradient
+          android:endX="85.84757"
+          android:endY="92.4963"
+          android:startX="42.9492"
+          android:startY="49.59793"
+          android:type="linear">
+        <item
+            android:color="#44000000"
+            android:offset="0.0" />
+        <item
+            android:color="#00000000"
+            android:offset="1.0" />
+      </gradient>
+    </aapt:attr>
+  </path>
+  <path
+      android:fillColor="#FFFFFF"
+      android:fillType="nonZero"
+      android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
+      android:strokeColor="#00000000"
+      android:strokeWidth="1" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/compose/gallery/res/drawable/ic_launcher_background.xml b/packages/SystemUI/compose/gallery/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..61bb79e
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="108dp"
+    android:height="108dp"
+    android:viewportHeight="108"
+    android:viewportWidth="108">
+  <path
+      android:fillColor="#3DDC84"
+      android:pathData="M0,0h108v108h-108z" />
+  <path
+      android:fillColor="#00000000"
+      android:pathData="M9,0L9,108"
+      android:strokeColor="#33FFFFFF"
+      android:strokeWidth="0.8" />
+  <path
+      android:fillColor="#00000000"
+      android:pathData="M19,0L19,108"
+      android:strokeColor="#33FFFFFF"
+      android:strokeWidth="0.8" />
+  <path
+      android:fillColor="#00000000"
+      android:pathData="M29,0L29,108"
+      android:strokeColor="#33FFFFFF"
+      android:strokeWidth="0.8" />
+  <path
+      android:fillColor="#00000000"
+      android:pathData="M39,0L39,108"
+      android:strokeColor="#33FFFFFF"
+      android:strokeWidth="0.8" />
+  <path
+      android:fillColor="#00000000"
+      android:pathData="M49,0L49,108"
+      android:strokeColor="#33FFFFFF"
+      android:strokeWidth="0.8" />
+  <path
+      android:fillColor="#00000000"
+      android:pathData="M59,0L59,108"
+      android:strokeColor="#33FFFFFF"
+      android:strokeWidth="0.8" />
+  <path
+      android:fillColor="#00000000"
+      android:pathData="M69,0L69,108"
+      android:strokeColor="#33FFFFFF"
+      android:strokeWidth="0.8" />
+  <path
+      android:fillColor="#00000000"
+      android:pathData="M79,0L79,108"
+      android:strokeColor="#33FFFFFF"
+      android:strokeWidth="0.8" />
+  <path
+      android:fillColor="#00000000"
+      android:pathData="M89,0L89,108"
+      android:strokeColor="#33FFFFFF"
+      android:strokeWidth="0.8" />
+  <path
+      android:fillColor="#00000000"
+      android:pathData="M99,0L99,108"
+      android:strokeColor="#33FFFFFF"
+      android:strokeWidth="0.8" />
+  <path
+      android:fillColor="#00000000"
+      android:pathData="M0,9L108,9"
+      android:strokeColor="#33FFFFFF"
+      android:strokeWidth="0.8" />
+  <path
+      android:fillColor="#00000000"
+      android:pathData="M0,19L108,19"
+      android:strokeColor="#33FFFFFF"
+      android:strokeWidth="0.8" />
+  <path
+      android:fillColor="#00000000"
+      android:pathData="M0,29L108,29"
+      android:strokeColor="#33FFFFFF"
+      android:strokeWidth="0.8" />
+  <path
+      android:fillColor="#00000000"
+      android:pathData="M0,39L108,39"
+      android:strokeColor="#33FFFFFF"
+      android:strokeWidth="0.8" />
+  <path
+      android:fillColor="#00000000"
+      android:pathData="M0,49L108,49"
+      android:strokeColor="#33FFFFFF"
+      android:strokeWidth="0.8" />
+  <path
+      android:fillColor="#00000000"
+      android:pathData="M0,59L108,59"
+      android:strokeColor="#33FFFFFF"
+      android:strokeWidth="0.8" />
+  <path
+      android:fillColor="#00000000"
+      android:pathData="M0,69L108,69"
+      android:strokeColor="#33FFFFFF"
+      android:strokeWidth="0.8" />
+  <path
+      android:fillColor="#00000000"
+      android:pathData="M0,79L108,79"
+      android:strokeColor="#33FFFFFF"
+      android:strokeWidth="0.8" />
+  <path
+      android:fillColor="#00000000"
+      android:pathData="M0,89L108,89"
+      android:strokeColor="#33FFFFFF"
+      android:strokeWidth="0.8" />
+  <path
+      android:fillColor="#00000000"
+      android:pathData="M0,99L108,99"
+      android:strokeColor="#33FFFFFF"
+      android:strokeWidth="0.8" />
+  <path
+      android:fillColor="#00000000"
+      android:pathData="M19,29L89,29"
+      android:strokeColor="#33FFFFFF"
+      android:strokeWidth="0.8" />
+  <path
+      android:fillColor="#00000000"
+      android:pathData="M19,39L89,39"
+      android:strokeColor="#33FFFFFF"
+      android:strokeWidth="0.8" />
+  <path
+      android:fillColor="#00000000"
+      android:pathData="M19,49L89,49"
+      android:strokeColor="#33FFFFFF"
+      android:strokeWidth="0.8" />
+  <path
+      android:fillColor="#00000000"
+      android:pathData="M19,59L89,59"
+      android:strokeColor="#33FFFFFF"
+      android:strokeWidth="0.8" />
+  <path
+      android:fillColor="#00000000"
+      android:pathData="M19,69L89,69"
+      android:strokeColor="#33FFFFFF"
+      android:strokeWidth="0.8" />
+  <path
+      android:fillColor="#00000000"
+      android:pathData="M19,79L89,79"
+      android:strokeColor="#33FFFFFF"
+      android:strokeWidth="0.8" />
+  <path
+      android:fillColor="#00000000"
+      android:pathData="M29,19L29,89"
+      android:strokeColor="#33FFFFFF"
+      android:strokeWidth="0.8" />
+  <path
+      android:fillColor="#00000000"
+      android:pathData="M39,19L39,89"
+      android:strokeColor="#33FFFFFF"
+      android:strokeWidth="0.8" />
+  <path
+      android:fillColor="#00000000"
+      android:pathData="M49,19L49,89"
+      android:strokeColor="#33FFFFFF"
+      android:strokeWidth="0.8" />
+  <path
+      android:fillColor="#00000000"
+      android:pathData="M59,19L59,89"
+      android:strokeColor="#33FFFFFF"
+      android:strokeWidth="0.8" />
+  <path
+      android:fillColor="#00000000"
+      android:pathData="M69,19L69,89"
+      android:strokeColor="#33FFFFFF"
+      android:strokeWidth="0.8" />
+  <path
+      android:fillColor="#00000000"
+      android:pathData="M79,19L79,89"
+      android:strokeColor="#33FFFFFF"
+      android:strokeWidth="0.8" />
+</vector>
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-anydpi-v26/ic_launcher.xml b/packages/SystemUI/compose/gallery/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..03eed25
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+  <background android:drawable="@drawable/ic_launcher_background" />
+  <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>
\ No newline at end of file
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-anydpi-v26/ic_launcher_round.xml b/packages/SystemUI/compose/gallery/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..03eed25
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+  <background android:drawable="@drawable/ic_launcher_background" />
+  <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>
\ No newline at end of file
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-hdpi/ic_launcher.webp b/packages/SystemUI/compose/gallery/res/mipmap-hdpi/ic_launcher.webp
new file mode 100644
index 0000000..c209e78
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/mipmap-hdpi/ic_launcher.webp
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-hdpi/ic_launcher_round.webp b/packages/SystemUI/compose/gallery/res/mipmap-hdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..b2dfe3d
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/mipmap-hdpi/ic_launcher_round.webp
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-mdpi/ic_launcher.webp b/packages/SystemUI/compose/gallery/res/mipmap-mdpi/ic_launcher.webp
new file mode 100644
index 0000000..4f0f1d6
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/mipmap-mdpi/ic_launcher.webp
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-mdpi/ic_launcher_round.webp b/packages/SystemUI/compose/gallery/res/mipmap-mdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..62b611d
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/mipmap-mdpi/ic_launcher_round.webp
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-xhdpi/ic_launcher.webp b/packages/SystemUI/compose/gallery/res/mipmap-xhdpi/ic_launcher.webp
new file mode 100644
index 0000000..948a307
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/mipmap-xhdpi/ic_launcher.webp
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-xhdpi/ic_launcher_round.webp b/packages/SystemUI/compose/gallery/res/mipmap-xhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..1b9a695
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/mipmap-xhdpi/ic_launcher_round.webp
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-xxhdpi/ic_launcher.webp b/packages/SystemUI/compose/gallery/res/mipmap-xxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..28d4b77
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/mipmap-xxhdpi/ic_launcher.webp
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-xxhdpi/ic_launcher_round.webp b/packages/SystemUI/compose/gallery/res/mipmap-xxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9287f508
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/mipmap-xxhdpi/ic_launcher_round.webp
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-xxxhdpi/ic_launcher.webp b/packages/SystemUI/compose/gallery/res/mipmap-xxxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..aa7d642
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/mipmap-xxxhdpi/ic_launcher.webp
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/mipmap-xxxhdpi/ic_launcher_round.webp b/packages/SystemUI/compose/gallery/res/mipmap-xxxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9126ae3
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/mipmap-xxxhdpi/ic_launcher_round.webp
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/values/colors.xml b/packages/SystemUI/compose/gallery/res/values/colors.xml
new file mode 100644
index 0000000..a2fcbff
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/values/colors.xml
@@ -0,0 +1,19 @@
+<?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>
+    <color name="ic_launcher_background">#FFFFFF</color>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/compose/gallery/res/values/strings.xml b/packages/SystemUI/compose/gallery/res/values/strings.xml
new file mode 100644
index 0000000..86bdb05
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/values/strings.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>
+    <!-- Application name [CHAR LIMIT=NONE] -->
+    <string name="app_name">SystemUI Gallery</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/compose/gallery/res/values/themes.xml b/packages/SystemUI/compose/gallery/res/values/themes.xml
new file mode 100644
index 0000000..45fa1f5d
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/values/themes.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources xmlns:tools="http://schemas.android.com/tools">
+    <style name="Theme.SystemUI.Gallery">
+        <item name="android:windowActionBar">false</item>
+        <item name="android:windowNoTitle">true</item>
+
+        <item name="android:statusBarColor" tools:targetApi="l">
+            @android:color/transparent
+        </item>
+        <item name="android:navigationBarColor" tools:targetApi="l">
+            @android:color/transparent
+        </item>
+        <item name="android:windowLightStatusBar">true</item>
+    </style>
+</resources>
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ColorsScreen.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ColorsScreen.kt
new file mode 100644
index 0000000..dfa1b26
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ColorsScreen.kt
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.compose.gallery
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.border
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.unit.dp
+import com.android.systemui.compose.theme.LocalAndroidColorScheme
+
+/** The screen that shows all the Material 3 colors. */
+@Composable
+fun MaterialColorsScreen() {
+    val colors = MaterialTheme.colorScheme
+    ColorsScreen(
+        listOf(
+            "primary" to colors.primary,
+            "onPrimary" to colors.onPrimary,
+            "primaryContainer" to colors.primaryContainer,
+            "onPrimaryContainer" to colors.onPrimaryContainer,
+            "inversePrimary" to colors.inversePrimary,
+            "secondary" to colors.secondary,
+            "onSecondary" to colors.onSecondary,
+            "secondaryContainer" to colors.secondaryContainer,
+            "onSecondaryContainer" to colors.onSecondaryContainer,
+            "tertiary" to colors.tertiary,
+            "onTertiary" to colors.onTertiary,
+            "tertiaryContainer" to colors.tertiaryContainer,
+            "onTertiaryContainer" to colors.onTertiaryContainer,
+            "background" to colors.background,
+            "onBackground" to colors.onBackground,
+            "surface" to colors.surface,
+            "onSurface" to colors.onSurface,
+            "surfaceVariant" to colors.surfaceVariant,
+            "onSurfaceVariant" to colors.onSurfaceVariant,
+            "inverseSurface" to colors.inverseSurface,
+            "inverseOnSurface" to colors.inverseOnSurface,
+            "error" to colors.error,
+            "onError" to colors.onError,
+            "errorContainer" to colors.errorContainer,
+            "onErrorContainer" to colors.onErrorContainer,
+            "outline" to colors.outline,
+        )
+    )
+}
+
+/** The screen that shows all the Android colors. */
+@Composable
+fun AndroidColorsScreen() {
+    val colors = LocalAndroidColorScheme.current
+    ColorsScreen(
+        listOf(
+            "colorPrimary" to colors.colorPrimary,
+            "colorPrimaryDark" to colors.colorPrimaryDark,
+            "colorAccent" to colors.colorAccent,
+            "colorAccentPrimary" to colors.colorAccentPrimary,
+            "colorAccentSecondary" to colors.colorAccentSecondary,
+            "colorAccentTertiary" to colors.colorAccentTertiary,
+            "colorAccentPrimaryVariant" to colors.colorAccentPrimaryVariant,
+            "colorAccentSecondaryVariant" to colors.colorAccentSecondaryVariant,
+            "colorAccentTertiaryVariant" to colors.colorAccentTertiaryVariant,
+            "colorSurface" to colors.colorSurface,
+            "colorSurfaceHighlight" to colors.colorSurfaceHighlight,
+            "colorSurfaceVariant" to colors.colorSurfaceVariant,
+            "colorSurfaceHeader" to colors.colorSurfaceHeader,
+            "colorError" to colors.colorError,
+            "colorBackground" to colors.colorBackground,
+            "colorBackgroundFloating" to colors.colorBackgroundFloating,
+            "panelColorBackground" to colors.panelColorBackground,
+            "textColorPrimary" to colors.textColorPrimary,
+            "textColorSecondary" to colors.textColorSecondary,
+            "textColorTertiary" to colors.textColorTertiary,
+            "textColorPrimaryInverse" to colors.textColorPrimaryInverse,
+            "textColorSecondaryInverse" to colors.textColorSecondaryInverse,
+            "textColorTertiaryInverse" to colors.textColorTertiaryInverse,
+            "textColorOnAccent" to colors.textColorOnAccent,
+            "colorForeground" to colors.colorForeground,
+            "colorForegroundInverse" to colors.colorForegroundInverse,
+        )
+    )
+}
+
+@Composable
+private fun ColorsScreen(
+    colors: List<Pair<String, Color>>,
+) {
+    LazyColumn(
+        Modifier.fillMaxWidth(),
+    ) {
+        colors.forEach { (name, color) -> item { ColorTile(color, name) } }
+    }
+}
+
+@Composable
+private fun ColorTile(
+    color: Color,
+    name: String,
+) {
+    Row(
+        Modifier.padding(16.dp),
+        verticalAlignment = Alignment.CenterVertically,
+    ) {
+        val shape = RoundedCornerShape(16.dp)
+        Spacer(
+            Modifier.border(1.dp, MaterialTheme.colorScheme.onBackground, shape)
+                .background(color, shape)
+                .size(64.dp)
+        )
+        Spacer(Modifier.width(16.dp))
+        Text(name)
+    }
+}
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ConfigurationControls.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ConfigurationControls.kt
new file mode 100644
index 0000000..990d060
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ConfigurationControls.kt
@@ -0,0 +1,210 @@
+package com.android.systemui.compose.gallery
+
+import android.graphics.Point
+import android.os.UserHandle
+import android.view.Display
+import android.view.WindowManagerGlobal
+import androidx.compose.foundation.layout.RowScope
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.lazy.LazyRow
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.DarkMode
+import androidx.compose.material.icons.filled.FormatSize
+import androidx.compose.material.icons.filled.FormatTextdirectionLToR
+import androidx.compose.material.icons.filled.FormatTextdirectionRToL
+import androidx.compose.material.icons.filled.InvertColors
+import androidx.compose.material.icons.filled.LightMode
+import androidx.compose.material.icons.filled.Smartphone
+import androidx.compose.material.icons.filled.Tablet
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.Icon
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextButton
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.unit.dp
+import kotlin.math.max
+import kotlin.math.min
+
+enum class FontScale(val scale: Float) {
+    Small(0.85f),
+    Normal(1f),
+    Big(1.15f),
+    Bigger(1.30f),
+}
+
+/** A configuration panel that allows to toggle the theme, font scale and layout direction. */
+@Composable
+fun ConfigurationControls(
+    theme: Theme,
+    fontScale: FontScale,
+    layoutDirection: LayoutDirection,
+    onChangeTheme: () -> Unit,
+    onChangeLayoutDirection: () -> Unit,
+    onChangeFontScale: () -> Unit,
+    modifier: Modifier = Modifier,
+) {
+    // The display we are emulating, if any.
+    var emulatedDisplayName by rememberSaveable { mutableStateOf<String?>(null) }
+    val emulatedDisplay =
+        emulatedDisplayName?.let { name -> EmulatedDisplays.firstOrNull { it.name == name } }
+
+    LaunchedEffect(emulatedDisplay) {
+        val wm = WindowManagerGlobal.getWindowManagerService()
+
+        val defaultDisplayId = Display.DEFAULT_DISPLAY
+        if (emulatedDisplay == null) {
+            wm.clearForcedDisplayDensityForUser(defaultDisplayId, UserHandle.myUserId())
+            wm.clearForcedDisplaySize(defaultDisplayId)
+        } else {
+            val density = emulatedDisplay.densityDpi
+
+            // Emulate the display and make sure that we use the maximum available space possible.
+            val initialSize = Point()
+            wm.getInitialDisplaySize(defaultDisplayId, initialSize)
+            val width = emulatedDisplay.width
+            val height = emulatedDisplay.height
+            val minOfSize = min(width, height)
+            val maxOfSize = max(width, height)
+            if (initialSize.x < initialSize.y) {
+                wm.setForcedDisplaySize(defaultDisplayId, minOfSize, maxOfSize)
+            } else {
+                wm.setForcedDisplaySize(defaultDisplayId, maxOfSize, minOfSize)
+            }
+            wm.setForcedDisplayDensityForUser(defaultDisplayId, density, UserHandle.myUserId())
+        }
+    }
+
+    // TODO(b/231131244): Fork FlowRow from Accompanist and use that instead to make sure that users
+    // don't miss any available configuration.
+    LazyRow(modifier) {
+        // Dark/light theme.
+        item {
+            TextButton(onChangeTheme) {
+                val text: String
+                val icon: ImageVector
+
+                when (theme) {
+                    Theme.System -> {
+                        icon = Icons.Default.InvertColors
+                        text = "System"
+                    }
+                    Theme.Dark -> {
+                        icon = Icons.Default.DarkMode
+                        text = "Dark"
+                    }
+                    Theme.Light -> {
+                        icon = Icons.Default.LightMode
+                        text = "Light"
+                    }
+                }
+
+                Icon(icon, null)
+                Spacer(Modifier.width(8.dp))
+                Text(text)
+            }
+        }
+
+        // Font scale.
+        item {
+            TextButton(onChangeFontScale) {
+                Icon(Icons.Default.FormatSize, null)
+                Spacer(Modifier.width(8.dp))
+
+                Text(fontScale.name)
+            }
+        }
+
+        // Layout direction.
+        item {
+            TextButton(onChangeLayoutDirection) {
+                when (layoutDirection) {
+                    LayoutDirection.Ltr -> {
+                        Icon(Icons.Default.FormatTextdirectionLToR, null)
+                        Spacer(Modifier.width(8.dp))
+                        Text("LTR")
+                    }
+                    LayoutDirection.Rtl -> {
+                        Icon(Icons.Default.FormatTextdirectionRToL, null)
+                        Spacer(Modifier.width(8.dp))
+                        Text("RTL")
+                    }
+                }
+            }
+        }
+
+        // Display emulation.
+        EmulatedDisplays.forEach { display ->
+            item {
+                DisplayButton(
+                    display,
+                    emulatedDisplay == display,
+                    { emulatedDisplayName = it?.name },
+                )
+            }
+        }
+    }
+}
+
+@Composable
+private fun DisplayButton(
+    display: EmulatedDisplay,
+    selected: Boolean,
+    onChangeEmulatedDisplay: (EmulatedDisplay?) -> Unit,
+) {
+    val onClick = {
+        if (selected) {
+            onChangeEmulatedDisplay(null)
+        } else {
+            onChangeEmulatedDisplay(display)
+        }
+    }
+
+    val content: @Composable RowScope.() -> Unit = {
+        Icon(display.icon, null)
+        Spacer(Modifier.width(8.dp))
+        Text(display.name)
+    }
+
+    if (selected) {
+        Button(onClick, contentPadding = ButtonDefaults.TextButtonContentPadding, content = content)
+    } else {
+        TextButton(onClick, content = content)
+    }
+}
+
+/** The displays that can be emulated from this Gallery app. */
+private val EmulatedDisplays =
+    listOf(
+        EmulatedDisplay(
+            "Phone",
+            Icons.Default.Smartphone,
+            width = 1440,
+            height = 3120,
+            densityDpi = 560,
+        ),
+        EmulatedDisplay(
+            "Tablet",
+            Icons.Default.Tablet,
+            width = 2560,
+            height = 1600,
+            densityDpi = 320,
+        ),
+    )
+
+private data class EmulatedDisplay(
+    val name: String,
+    val icon: ImageVector,
+    val width: Int,
+    val height: Int,
+    val densityDpi: Int,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/common/data/model/Position.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ExampleFeatureScreen.kt
similarity index 60%
copy from packages/SystemUI/src/com/android/systemui/common/data/model/Position.kt
copy to packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ExampleFeatureScreen.kt
index 7c9df10..6e17214 100644
--- a/packages/SystemUI/src/com/android/systemui/common/data/model/Position.kt
+++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ExampleFeatureScreen.kt
@@ -14,10 +14,15 @@
  * limitations under the License.
  */
 
-package com.android.systemui.common.data.model
+package com.android.systemui.compose.gallery
 
-/** Models a two-dimensional position */
-data class Position(
-    val x: Int,
-    val y: Int,
-)
+import androidx.compose.foundation.layout.Column
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import com.android.systemui.ExampleFeature
+
+/** The screen that shows ExampleFeature. */
+@Composable
+fun ExampleFeatureScreen(modifier: Modifier = Modifier) {
+    Column(modifier) { ExampleFeature("This is an example feature!") }
+}
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryActivity.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryActivity.kt
new file mode 100644
index 0000000..bb2d2fe
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryActivity.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.systemui.compose.gallery
+
+import android.app.UiModeManager
+import android.content.Context
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.runtime.SideEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.graphics.Color
+import androidx.core.view.WindowCompat
+import com.android.systemui.compose.rememberSystemUiController
+
+class GalleryActivity : ComponentActivity() {
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        WindowCompat.setDecorFitsSystemWindows(window, false)
+        val uiModeManager = getSystemService(Context.UI_MODE_SERVICE) as UiModeManager
+
+        setContent {
+            var theme by rememberSaveable { mutableStateOf(Theme.System) }
+            val onChangeTheme = {
+                // Change to the next theme for a toggle behavior.
+                theme =
+                    when (theme) {
+                        Theme.System -> Theme.Dark
+                        Theme.Dark -> Theme.Light
+                        Theme.Light -> Theme.System
+                    }
+            }
+
+            val isSystemInDarkTheme = isSystemInDarkTheme()
+            val isDark = theme == Theme.Dark || (theme == Theme.System && isSystemInDarkTheme)
+            val useDarkIcons = !isDark
+            val systemUiController = rememberSystemUiController()
+            SideEffect {
+                systemUiController.setSystemBarsColor(
+                    color = Color.Transparent,
+                    darkIcons = useDarkIcons,
+                )
+
+                uiModeManager.setApplicationNightMode(
+                    when (theme) {
+                        Theme.System -> UiModeManager.MODE_NIGHT_AUTO
+                        Theme.Dark -> UiModeManager.MODE_NIGHT_YES
+                        Theme.Light -> UiModeManager.MODE_NIGHT_NO
+                    }
+                )
+            }
+
+            GalleryApp(theme, onChangeTheme)
+        }
+    }
+}
+
+enum class Theme {
+    System,
+    Dark,
+    Light,
+}
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryApp.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryApp.kt
new file mode 100644
index 0000000..c341867
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryApp.kt
@@ -0,0 +1,125 @@
+package com.android.systemui.compose.gallery
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.systemBarsPadding
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.platform.LocalLayoutDirection
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.unit.dp
+import androidx.navigation.compose.NavHost
+import androidx.navigation.compose.rememberNavController
+import com.android.systemui.compose.theme.SystemUITheme
+
+/** The gallery app screens. */
+object GalleryAppScreens {
+    val Typography = ChildScreen("typography") { TypographyScreen() }
+    val MaterialColors = ChildScreen("material_colors") { MaterialColorsScreen() }
+    val AndroidColors = ChildScreen("android_colors") { AndroidColorsScreen() }
+    val ExampleFeature = ChildScreen("example_feature") { ExampleFeatureScreen() }
+
+    val Home =
+        ParentScreen(
+            "home",
+            mapOf(
+                "Typography" to Typography,
+                "Material colors" to MaterialColors,
+                "Android colors" to AndroidColors,
+                "Example feature" to ExampleFeature,
+            )
+        )
+}
+
+/** The main content of the app, that shows [GalleryAppScreens.Home] by default. */
+@Composable
+private fun MainContent() {
+    Box(Modifier.fillMaxSize()) {
+        val navController = rememberNavController()
+        NavHost(
+            navController = navController,
+            startDestination = GalleryAppScreens.Home.identifier,
+        ) {
+            screen(GalleryAppScreens.Home, navController)
+        }
+    }
+}
+
+/**
+ * The top-level composable shown when starting the app. This composable always shows a
+ * [ConfigurationControls] at the top of the screen, above the [MainContent].
+ */
+@Composable
+fun GalleryApp(
+    theme: Theme,
+    onChangeTheme: () -> Unit,
+) {
+    val systemFontScale = LocalDensity.current.fontScale
+    var fontScale: FontScale by remember {
+        mutableStateOf(
+            FontScale.values().firstOrNull { it.scale == systemFontScale } ?: FontScale.Normal
+        )
+    }
+    val context = LocalContext.current
+    val density = Density(context.resources.displayMetrics.density, fontScale.scale)
+    val onChangeFontScale = {
+        fontScale =
+            when (fontScale) {
+                FontScale.Small -> FontScale.Normal
+                FontScale.Normal -> FontScale.Big
+                FontScale.Big -> FontScale.Bigger
+                FontScale.Bigger -> FontScale.Small
+            }
+    }
+
+    val systemLayoutDirection = LocalLayoutDirection.current
+    var layoutDirection by remember { mutableStateOf(systemLayoutDirection) }
+    val onChangeLayoutDirection = {
+        layoutDirection =
+            when (layoutDirection) {
+                LayoutDirection.Ltr -> LayoutDirection.Rtl
+                LayoutDirection.Rtl -> LayoutDirection.Ltr
+            }
+    }
+
+    CompositionLocalProvider(
+        LocalDensity provides density,
+        LocalLayoutDirection provides layoutDirection,
+    ) {
+        SystemUITheme {
+            Surface(
+                Modifier.fillMaxSize(),
+                color = MaterialTheme.colorScheme.background,
+            ) {
+                Column(Modifier.fillMaxSize().systemBarsPadding().padding(16.dp)) {
+                    ConfigurationControls(
+                        theme,
+                        fontScale,
+                        layoutDirection,
+                        onChangeTheme,
+                        onChangeLayoutDirection,
+                        onChangeFontScale,
+                    )
+
+                    Spacer(Modifier.height(4.dp))
+
+                    MainContent()
+                }
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/Screen.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/Screen.kt
new file mode 100644
index 0000000..467dac04
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/Screen.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.compose.gallery
+
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import androidx.navigation.NavController
+import androidx.navigation.NavGraphBuilder
+import androidx.navigation.compose.composable
+import androidx.navigation.compose.navigation
+
+/**
+ * A screen in an app. It is either an [ParentScreen] which lists its child screens to navigate to
+ * them or a [ChildScreen] which shows some content.
+ */
+sealed class Screen(val identifier: String)
+
+class ParentScreen(
+    identifier: String,
+    val children: Map<String, Screen>,
+) : Screen(identifier)
+
+class ChildScreen(
+    identifier: String,
+    val content: @Composable (NavController) -> Unit,
+) : Screen(identifier)
+
+/** Create the navigation graph for [screen]. */
+fun NavGraphBuilder.screen(screen: Screen, navController: NavController) {
+    when (screen) {
+        is ChildScreen -> composable(screen.identifier) { screen.content(navController) }
+        is ParentScreen -> {
+            val menuRoute = "${screen.identifier}_menu"
+            navigation(startDestination = menuRoute, route = screen.identifier) {
+                // The menu to navigate to one of the children screens.
+                composable(menuRoute) { ScreenMenu(screen, navController) }
+
+                // The content of the child screens.
+                screen.children.forEach { (_, child) -> screen(child, navController) }
+            }
+        }
+    }
+}
+
+@Composable
+private fun ScreenMenu(
+    screen: ParentScreen,
+    navController: NavController,
+) {
+    LazyColumn(verticalArrangement = Arrangement.spacedBy(8.dp)) {
+        screen.children.forEach { (name, child) ->
+            item {
+                Surface(
+                    Modifier.fillMaxWidth(),
+                    color = MaterialTheme.colorScheme.secondaryContainer,
+                    shape = CircleShape,
+                ) {
+                    Column(
+                        Modifier.clickable { navController.navigate(child.identifier) }
+                            .padding(16.dp),
+                        horizontalAlignment = Alignment.CenterHorizontally,
+                    ) {
+                        Text(name)
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/TypographyScreen.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/TypographyScreen.kt
new file mode 100644
index 0000000..147025e
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/TypographyScreen.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.compose.gallery
+
+import androidx.compose.foundation.horizontalScroll
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.style.TextOverflow
+
+/** The screen that shows the Material text styles. */
+@Composable
+fun TypographyScreen() {
+    val typography = MaterialTheme.typography
+
+    Column(
+        Modifier.fillMaxSize()
+            .horizontalScroll(rememberScrollState())
+            .verticalScroll(rememberScrollState()),
+    ) {
+        FontLine("displayLarge", typography.displayLarge)
+        FontLine("displayMedium", typography.displayMedium)
+        FontLine("displaySmall", typography.displaySmall)
+        FontLine("headlineLarge", typography.headlineLarge)
+        FontLine("headlineMedium", typography.headlineMedium)
+        FontLine("headlineSmall", typography.headlineSmall)
+        FontLine("titleLarge", typography.titleLarge)
+        FontLine("titleMedium", typography.titleMedium)
+        FontLine("titleSmall", typography.titleSmall)
+        FontLine("bodyLarge", typography.bodyLarge)
+        FontLine("bodyMedium", typography.bodyMedium)
+        FontLine("bodySmall", typography.bodySmall)
+        FontLine("labelLarge", typography.labelLarge)
+        FontLine("labelMedium", typography.labelMedium)
+        FontLine("labelSmall", typography.labelSmall)
+    }
+}
+
+@Composable
+private fun FontLine(name: String, style: TextStyle) {
+    Text(
+        "$name (${style.fontSize}/${style.lineHeight}, W${style.fontWeight?.weight})",
+        style = style,
+        maxLines = 1,
+        overflow = TextOverflow.Visible,
+    )
+}
diff --git a/packages/SystemUI/compose/gallery/tests/Android.bp b/packages/SystemUI/compose/gallery/tests/Android.bp
new file mode 100644
index 0000000..3e01f7d
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/tests/Android.bp
@@ -0,0 +1,47 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_packages_SystemUI_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+android_test {
+    name: "SystemUIComposeGalleryTests",
+    manifest: "AndroidManifest.xml",
+    test_suites: ["device-tests"],
+    sdk_version: "current",
+    certificate: "platform",
+
+    srcs: [
+        "src/**/*.kt",
+    ],
+
+    static_libs: [
+        "SystemUIComposeGalleryLib",
+
+        "androidx.test.runner",
+        "androidx.test.ext.junit",
+
+        "androidx.compose.runtime_runtime",
+        "androidx.compose.ui_ui-test-junit4",
+        "androidx.compose.ui_ui-test-manifest",
+    ],
+
+    kotlincflags: ["-Xjvm-default=enable"],
+}
diff --git a/packages/SystemUI/compose/gallery/tests/AndroidManifest.xml b/packages/SystemUI/compose/gallery/tests/AndroidManifest.xml
new file mode 100644
index 0000000..5eeb3ad
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/tests/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.systemui.compose.gallery.tests" >
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="com.android.systemui.compose.gallery.tests"
+                     android:label="Tests for SystemUIComposeGallery"/>
+
+</manifest>
\ No newline at end of file
diff --git a/packages/SystemUI/compose/gallery/tests/src/com/android/systemui/compose/gallery/ScreenshotsTests.kt b/packages/SystemUI/compose/gallery/tests/src/com/android/systemui/compose/gallery/ScreenshotsTests.kt
new file mode 100644
index 0000000..66ecc8d
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/tests/src/com/android/systemui/compose/gallery/ScreenshotsTests.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.compose.gallery
+
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.systemui.compose.theme.SystemUITheme
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class ScreenshotsTests {
+    @get:Rule val composeRule = createComposeRule()
+
+    @Test
+    fun exampleFeatureScreenshotTest() {
+        // TODO(b/230832101): Wire this with the screenshot diff testing infra. We should reuse the
+        // configuration of the features in the gallery app to populate the UIs.
+        composeRule.setContent { SystemUITheme { ExampleFeatureScreen() } }
+    }
+}
diff --git a/packages/SystemUI/compose/testing/Android.bp b/packages/SystemUI/compose/testing/Android.bp
new file mode 100644
index 0000000..293e51f
--- /dev/null
+++ b/packages/SystemUI/compose/testing/Android.bp
@@ -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 {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_packages_SystemUI_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+android_library {
+    name: "SystemUIComposeTesting",
+    manifest: "AndroidManifest.xml",
+
+    srcs: [
+        "src/**/*.kt",
+    ],
+
+    static_libs: [
+        "SystemUIComposeCore",
+        "SystemUIScreenshotLib",
+
+        "androidx.compose.runtime_runtime",
+        "androidx.compose.material3_material3",
+        "androidx.compose.ui_ui-test-junit4",
+        "androidx.compose.ui_ui-test-manifest",
+    ],
+
+    kotlincflags: ["-Xjvm-default=all"],
+}
diff --git a/packages/SystemUI/compose/testing/AndroidManifest.xml b/packages/SystemUI/compose/testing/AndroidManifest.xml
new file mode 100644
index 0000000..b1f7c3b
--- /dev/null
+++ b/packages/SystemUI/compose/testing/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="com.android.systemui.testing.compose">
+    <application
+        android:appComponentFactory="androidx.core.app.AppComponentFactory"
+        tools:replace="android:appComponentFactory">
+    </application>
+</manifest>
diff --git a/packages/SystemUI/compose/testing/src/com/android/systemui/testing/compose/ComposeScreenshotTestRule.kt b/packages/SystemUI/compose/testing/src/com/android/systemui/testing/compose/ComposeScreenshotTestRule.kt
new file mode 100644
index 0000000..e611e8b
--- /dev/null
+++ b/packages/SystemUI/compose/testing/src/com/android/systemui/testing/compose/ComposeScreenshotTestRule.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.testing.compose
+
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.platform.ViewRootForTest
+import androidx.compose.ui.test.junit4.createAndroidComposeRule
+import androidx.compose.ui.test.onRoot
+import com.android.systemui.compose.theme.SystemUITheme
+import com.android.systemui.testing.screenshot.ScreenshotActivity
+import com.android.systemui.testing.screenshot.SystemUIGoldenImagePathManager
+import com.android.systemui.testing.screenshot.UnitTestBitmapMatcher
+import com.android.systemui.testing.screenshot.drawIntoBitmap
+import org.junit.rules.RuleChain
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+import platform.test.screenshot.DeviceEmulationRule
+import platform.test.screenshot.DeviceEmulationSpec
+import platform.test.screenshot.MaterialYouColorsRule
+import platform.test.screenshot.ScreenshotTestRule
+import platform.test.screenshot.getEmulatedDevicePathConfig
+
+/** A rule for Compose screenshot diff tests. */
+class ComposeScreenshotTestRule(emulationSpec: DeviceEmulationSpec) : TestRule {
+    private val colorsRule = MaterialYouColorsRule()
+    private val deviceEmulationRule = DeviceEmulationRule(emulationSpec)
+    private val screenshotRule =
+        ScreenshotTestRule(
+            SystemUIGoldenImagePathManager(getEmulatedDevicePathConfig(emulationSpec))
+        )
+    private val composeRule = createAndroidComposeRule<ScreenshotActivity>()
+    private val delegateRule =
+        RuleChain.outerRule(colorsRule)
+            .around(deviceEmulationRule)
+            .around(screenshotRule)
+            .around(composeRule)
+    private val matcher = UnitTestBitmapMatcher
+
+    override fun apply(base: Statement, description: Description): Statement {
+        return delegateRule.apply(base, description)
+    }
+
+    /**
+     * Compare [content] with the golden image identified by [goldenIdentifier] in the context of
+     * [testSpec].
+     */
+    fun screenshotTest(
+        goldenIdentifier: String,
+        content: @Composable () -> Unit,
+    ) {
+        // Make sure that the activity draws full screen and fits the whole display instead of the
+        // system bars.
+        val activity = composeRule.activity
+        activity.mainExecutor.execute { activity.window.setDecorFitsSystemWindows(false) }
+
+        // Set the content using the AndroidComposeRule to make sure that the Activity is set up
+        // correctly.
+        composeRule.setContent {
+            SystemUITheme {
+                Surface(
+                    color = MaterialTheme.colorScheme.background,
+                ) {
+                    content()
+                }
+            }
+        }
+        composeRule.waitForIdle()
+
+        val view = (composeRule.onRoot().fetchSemanticsNode().root as ViewRootForTest).view
+        screenshotRule.assertBitmapAgainstGolden(view.drawIntoBitmap(), goldenIdentifier, matcher)
+    }
+}
diff --git a/packages/SystemUI/docs/device-entry/quickaffordance.md b/packages/SystemUI/docs/device-entry/quickaffordance.md
index a96e5339..38d636d7 100644
--- a/packages/SystemUI/docs/device-entry/quickaffordance.md
+++ b/packages/SystemUI/docs/device-entry/quickaffordance.md
@@ -6,16 +6,16 @@
 
 ## Adding a new Quick Affordance
 ### Step 1: create a new quick affordance config
-* Create a new class under the [systemui/keyguard/data/quickaffordance](../../src/com/android/systemui/keyguard/data/quickaffordance) directory
+* Create a new class under the [systemui/keyguard/domain/quickaffordance](../../src/com/android/systemui/keyguard/domain/quickaffordance) directory
 * Please make sure that the class is injected through the Dagger dependency injection system by using the `@Inject` annotation on its main constructor and the `@SysUISingleton` annotation at class level, to make sure only one instance of the class is ever instantiated
-* Have the class implement the [KeyguardQuickAffordanceConfig](../../src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfig.kt) interface, notes:
+* Have the class implement the [KeyguardQuickAffordanceConfig](../../src/com/android/systemui/keyguard/domain/quickaffordance/KeyguardQuickAffordanceConfig.kt) interface, notes:
   * The `state` Flow property must emit `State.Hidden` when the feature is not enabled!
   * It is safe to assume that `onQuickAffordanceClicked` will not be invoked if-and-only-if the previous rule is followed
   * When implementing `onQuickAffordanceClicked`, the implementation can do something or it can ask the framework to start an activity using an `Intent` provided by the implementation
-* Please include a unit test for your new implementation under [the correct directory](../../tests/src/com/android/systemui/keyguard/data/quickaffordance)
+* Please include a unit test for your new implementation under [the correct directory](../../tests/src/com/android/systemui/keyguard/domain/quickaffordance)
 
 ### Step 2: choose a position and priority
-* Add the new class as a dependency in the constructor of [KeyguardQuickAffordanceConfigs](../../src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceConfigs.kt)
+* Add the new class as a dependency in the constructor of [KeyguardQuickAffordanceRegistry](../../src/com/android/systemui/keyguard/domain/quickaffordance/KeyguardQuickAffordanceRegistry.kt)
 * Place the new class in one of the available positions in the `configsByPosition` property, note:
   * In each position, there is a list. The order matters. The order of that list is the priority order in which the framework considers each config. The first config whose state property returns `State.Visible` determines the button that is shown for that position
   * Please only add to one position. The framework treats each position individually and there is no good way to prevent the same config from making its button appear in more than one position at the same time
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher.xml b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher.xml
index 01e3de2..898935f 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher.xml
@@ -35,7 +35,7 @@
 
     <!-- need to keep this outer view in order to have a correctly sized anchor
          for the dropdown menu, as well as dropdown background in the right place -->
-    <LinearLayout
+    <com.android.keyguard.KeyguardUserSwitcherAnchor
         android:id="@+id/user_switcher_anchor"
         android:orientation="horizontal"
         android:layout_height="wrap_content"
@@ -48,7 +48,7 @@
           android:textDirection="locale"
           android:layout_width="@dimen/bouncer_user_switcher_width"
           android:layout_height="wrap_content" />
-    </LinearLayout>>
+    </com.android.keyguard.KeyguardUserSwitcherAnchor>
 
 </LinearLayout>
 
diff --git a/packages/SystemUI/res/drawable/fingerprint_dialog_error_to_fp.xml b/packages/SystemUI/res/drawable/fingerprint_dialog_error_to_fp.xml
deleted file mode 100644
index 5084ca4..0000000
--- a/packages/SystemUI/res/drawable/fingerprint_dialog_error_to_fp.xml
+++ /dev/null
@@ -1 +0,0 @@
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"><aapt:attr name="android:drawable"><vector android:height="80dp" android:width="80dp" android:viewportHeight="80" android:viewportWidth="80"><group android:name="_R_G"><group android:name="_R_G_L_3_G" android:translateX="-0.25" android:translateY="-0.25"><path android:name="_R_G_L_3_G_D_0_P_0" android:fillColor="#474747" android:fillAlpha="0" android:fillType="nonZero" android:pathData=" M40.21 0.25 C18.13,0.25 0.25,18.17 0.25,40.25 C0.25,62.33 18.13,80.25 40.21,80.25 C62.33,80.25 80.25,62.33 80.25,40.25 C80.25,18.17 62.33,0.25 40.21,0.25c "/></group><group android:name="_R_G_L_2_G" android:translateX="-0.25" android:translateY="-0.25" android:pivotX="40.25" android:pivotY="40.25" android:scaleX="0.975" android:scaleY="0.975"><path android:name="_R_G_L_2_G_D_0_P_0" android:strokeColor="#f2b8b5" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2.5" android:strokeAlpha="1" android:pathData=" M40.21 0.25 C18.13,0.25 0.25,18.17 0.25,40.25 C0.25,62.33 18.13,80.25 40.21,80.25 C62.33,80.25 80.25,62.33 80.25,40.25 C80.25,18.17 62.33,0.25 40.21,0.25c "/></group><group android:name="_R_G_L_1_G" android:translateX="9.950000000000003" android:translateY="10" android:pivotX="30" android:pivotY="30" android:scaleX="1.2" android:scaleY="1.2"><group android:name="_R_G_L_1_G_D_0_P_0_G_0_T_0" android:translateX="30" android:translateY="38.75" android:scaleX="1" android:scaleY="1"><path android:name="_R_G_L_1_G_D_0_P_0" android:fillColor="#f2b8b5" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-1.2 -1.25 C-1.2,-1.25 1.2,-1.25 1.2,-1.25 C1.2,-1.25 1.2,1.25 1.2,1.25 C1.2,1.25 -1.2,1.25 -1.2,1.25 C-1.2,1.25 -1.2,-1.25 -1.2,-1.25c "/></group><group android:name="_R_G_L_1_G_D_1_P_0_G_0_T_0" android:translateX="30" android:translateY="25" android:pivotX="0.002" android:pivotY="7.488" android:scaleX="1" android:scaleY="1"><path android:name="_R_G_L_1_G_D_1_P_0" android:fillColor="#f2b8b5" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-1.2 -7.5 C-1.2,-7.5 1.2,-7.5 1.2,-7.5 C1.2,-7.5 1.2,7.5 1.2,7.5 C1.2,7.5 -1.2,7.5 -1.2,7.5 C-1.2,7.5 -1.2,-7.5 -1.2,-7.5c "/></group></group><group android:name="_R_G_L_0_G" android:translateX="20.659" android:translateY="15.75"><path android:name="_R_G_L_0_G_D_0_P_0" android:strokeColor="#d3e3fd" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:trimPathStart="0" android:trimPathEnd="0" android:trimPathOffset="0" android:pathData=" M27.52 38.98 C26.49,39.95 25.29,40.73 23.98,41.29 C23.17,41.65 22.31,41.91 21.41,42.07 C20.74,42.19 20.05,42.25 19.34,42.25 C18.44,42.25 17.56,42.15 16.72,41.96 C15.93,41.77 15.16,41.51 14.43,41.18 C13.23,40.63 12.13,39.88 11.16,38.98 "/><path android:name="_R_G_L_0_G_D_1_P_0" android:strokeColor="#d3e3fd" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:trimPathStart="0" android:trimPathEnd="0" android:trimPathOffset="0" android:pathData=" M8.64 34.07 C7.89,31.97 7.89,29.85 7.89,29.85 C7.89,24.05 12.81,19.34 19.34,19.34 C25.87,19.34 30.8,24.05 30.8,29.85 C30.8,29.85 30.8,30.16 30.8,30.16 C30.8,32.32 29.04,34.07 26.89,34.07 C25.28,34.07 23.86,33.1 23.27,31.61 C23.27,31.61 21.96,28.34 21.96,28.34 C21.37,26.85 19.93,25.89 18.34,25.89 C16.18,25.89 14.43,27.64 14.43,29.8 C14.43,31.42 14.87,32.99 15.68,34.36 C16.22,35.26 16.93,36.08 17.77,36.75 C17.77,36.75 18.52,37.34 18.52,37.34 "/><path android:name="_R_G_L_0_G_D_2_P_0" android:strokeColor="#d3e3fd" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:trimPathStart="0" android:trimPathEnd="0" android:trimPathOffset="0" android:pathData=" M6.25 19.34 C7.48,17.3 9.46,15.58 11.9,14.42 C12.93,13.94 14.03,13.55 15.2,13.27 C16.51,12.96 17.9,12.8 19.34,12.8 C20.77,12.8 22.14,12.96 23.45,13.26 C24.9,13.6 26.26,14.12 27.48,14.78 C29.6,15.92 31.32,17.5 32.43,19.34 "/><path android:name="_R_G_L_0_G_D_3_P_0" android:strokeColor="#d3e3fd" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:trimPathStart="0" android:trimPathEnd="0" android:trimPathOffset="0" android:pathData=" M9.52 8.7 C10.98,7.91 12.58,7.28 14.28,6.86 C15.89,6.46 17.58,6.25 19.34,6.25 C21.06,6.25 22.72,6.45 24.3,6.83 C26.04,7.25 27.67,7.89 29.16,8.7 "/></group></group><group android:name="time_group"/></vector></aapt:attr><target android:name="_R_G_L_3_G_D_0_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="fillAlpha" android:duration="67" android:startOffset="0" android:valueFrom="0" android:valueTo="0" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="fillAlpha" android:duration="167" android:startOffset="67" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_2_G_D_0_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="strokeWidth" android:duration="167" android:startOffset="0" android:valueFrom="2.5" android:valueTo="0" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_2_G_D_0_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="strokeAlpha" android:duration="83" android:startOffset="0" android:valueFrom="1" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="strokeAlpha" android:duration="83" android:startOffset="83" android:valueFrom="1" android:valueTo="0" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_2_G"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleY" android:duration="0" android:startOffset="0" android:valueFrom="0" android:valueTo="0.975" android:valueType="floatType"/></set></aapt:attr></target><target android:name="_R_G_L_2_G"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleY" android:duration="0" android:startOffset="167" android:valueFrom="0.975" android:valueTo="0" android:valueType="floatType"/></set></aapt:attr></target><target android:name="_R_G_L_1_G_D_0_P_0_G_0_T_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleX" android:duration="67" android:startOffset="0" android:valueFrom="1" android:valueTo="1.1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.853,0 0.6,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleY" android:duration="67" android:startOffset="0" android:valueFrom="1" android:valueTo="1.1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.853,0 0.6,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleX" android:duration="100" android:startOffset="67" android:valueFrom="1.1" android:valueTo="0" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.92,1.06 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleY" android:duration="100" android:startOffset="67" android:valueFrom="1.1" android:valueTo="0" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.92,1.06 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_1_G_D_1_P_0_G_0_T_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleX" android:duration="67" android:startOffset="0" android:valueFrom="1" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.659,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleY" android:duration="67" android:startOffset="0" android:valueFrom="1" android:valueTo="1.1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.6,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleX" android:duration="100" android:startOffset="67" android:valueFrom="1" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.6,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleY" android:duration="100" android:startOffset="67" android:valueFrom="1.1" android:valueTo="0" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.92,1.096 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_0_G_D_0_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="trimPathEnd" android:duration="83" android:startOffset="0" android:valueFrom="0" android:valueTo="0" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.543,0 0.299,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="trimPathEnd" android:duration="250" android:startOffset="83" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.543,0 0.299,1 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_0_G_D_1_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="trimPathEnd" android:duration="83" android:startOffset="0" android:valueFrom="0" android:valueTo="0" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.543,0 0.299,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="trimPathEnd" android:duration="250" android:startOffset="83" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.543,0 0.299,1 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_0_G_D_2_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="trimPathEnd" android:duration="83" android:startOffset="0" android:valueFrom="0" android:valueTo="0" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.543,0 0.299,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="trimPathEnd" android:duration="250" android:startOffset="83" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.543,0 0.299,1 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_0_G_D_3_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="trimPathEnd" android:duration="83" android:startOffset="0" android:valueFrom="0" android:valueTo="0" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.543,0 0.299,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="trimPathEnd" android:duration="250" android:startOffset="83" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.543,0 0.299,1 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="time_group"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="translateX" android:duration="417" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/></set></aapt:attr></target></animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/fingerprint_dialog_error_to_unlock.xml b/packages/SystemUI/res/drawable/fingerprint_dialog_error_to_unlock.xml
deleted file mode 100644
index c4f8181..0000000
--- a/packages/SystemUI/res/drawable/fingerprint_dialog_error_to_unlock.xml
+++ /dev/null
@@ -1 +0,0 @@
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"><aapt:attr name="android:drawable"><vector android:height="80dp" android:width="80dp" android:viewportHeight="80" android:viewportWidth="80"><group android:name="_R_G"><group android:name="_R_G_L_3_G" android:translateX="-0.25" android:translateY="-0.25"><path android:name="_R_G_L_3_G_D_0_P_0" android:fillColor="#474747" android:fillAlpha="0" android:fillType="nonZero" android:pathData=" M40.21 0.25 C18.13,0.25 0.25,18.17 0.25,40.25 C0.25,62.33 18.13,80.25 40.21,80.25 C62.33,80.25 80.25,62.33 80.25,40.25 C80.25,18.17 62.33,0.25 40.21,0.25c "/></group><group android:name="_R_G_L_2_G" android:translateX="-0.25" android:translateY="-0.25" android:pivotX="40.25" android:pivotY="40.25" android:scaleX="0.975" android:scaleY="0.975"><path android:name="_R_G_L_2_G_D_0_P_0" android:strokeColor="#f2b8b5" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2.5" android:strokeAlpha="1" android:pathData=" M40.21 0.25 C18.13,0.25 0.25,18.17 0.25,40.25 C0.25,62.33 18.13,80.25 40.21,80.25 C62.33,80.25 80.25,62.33 80.25,40.25 C80.25,18.17 62.33,0.25 40.21,0.25c "/></group><group android:name="_R_G_L_1_G" android:translateX="9.950000000000003" android:translateY="10" android:pivotX="30" android:pivotY="30" android:scaleX="1.2" android:scaleY="1.2"><group android:name="_R_G_L_1_G_D_0_P_0_G_0_T_0" android:translateX="30" android:translateY="38.75" android:scaleX="1" android:scaleY="1"><path android:name="_R_G_L_1_G_D_0_P_0" android:fillColor="#f2b8b5" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-1.2 -1.25 C-1.2,-1.25 1.2,-1.25 1.2,-1.25 C1.2,-1.25 1.2,1.25 1.2,1.25 C1.2,1.25 -1.2,1.25 -1.2,1.25 C-1.2,1.25 -1.2,-1.25 -1.2,-1.25c "/></group><group android:name="_R_G_L_1_G_D_1_P_0_G_0_T_0" android:translateX="30" android:translateY="25" android:pivotX="0.002" android:pivotY="7.488" android:scaleX="1" android:scaleY="1"><path android:name="_R_G_L_1_G_D_1_P_0" android:fillColor="#f2b8b5" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-1.2 -7.5 C-1.2,-7.5 1.2,-7.5 1.2,-7.5 C1.2,-7.5 1.2,7.5 1.2,7.5 C1.2,7.5 -1.2,7.5 -1.2,7.5 C-1.2,7.5 -1.2,-7.5 -1.2,-7.5c "/></group></group><group android:name="_R_G_L_0_G" android:translateX="20.75" android:translateY="15.75" android:pivotX="19.341" android:pivotY="24.25" android:scaleX="0.5" android:scaleY="0"><path android:name="_R_G_L_0_G_D_0_P_0" android:strokeColor="#d3e3fd" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M30.64 30.14 C30.64,30.14 30.64,38.14 30.64,38.14 C30.64,38.77 30.36,39.32 29.91,39.69 C29.57,39.97 29.12,40.14 28.64,40.14 C28.64,40.14 10.14,40.14 10.14,40.14 C9.04,40.14 8.14,39.25 8.14,38.14 C8.14,38.14 8.14,30.14 8.14,30.14 "/><path android:name="_R_G_L_0_G_D_1_P_0" android:strokeColor="#d3e3fd" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M19.42 31.53 C18.15,31.52 18.11,30.33 18.11,30.33 C18.11,29.59 18.66,28.98 19.4,28.98 C20.13,28.98 20.69,29.59 20.69,30.33 C20.69,30.33 20.69,30.37 20.69,30.37 C20.69,30.64 20.49,30.87 20.25,30.87 C20.07,30.87 19.91,30.74 19.84,30.55 C19.84,30.55 19.69,30.14 19.69,30.14 C19.63,29.94 19.46,29.82 19.28,29.82 C19.04,29.82 18.61,30.02 18.61,30.29 C18.61,30.43 18.6,30.75 18.76,31.03 C18.87,31.21 19.21,31.77 19.96,31.41 C20.69,31.01 20.69,30.34 20.69,30.34 "/><path android:name="_R_G_L_0_G_D_2_P_0" android:strokeColor="#d3e3fd" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M8.14 30.22 C8.14,30.22 8.14,22.22 8.14,22.22 C8.14,21.71 8.33,21.25 8.64,20.9 C9,20.48 9.54,20.22 10.14,20.22 C10.14,20.22 28.64,20.22 28.64,20.22 C29.75,20.22 30.64,21.11 30.64,22.22 C30.64,22.22 30.64,30.14 30.64,30.14 "/><path android:name="_R_G_L_0_G_D_3_P_0" android:strokeColor="#d3e3fd" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M13.12 20.04 C13.12,20.04 13.11,14.15 13.11,14.15 C13.11,10.77 15.91,8.04 19.36,8.04 C22.81,8.04 25.61,10.77 25.61,14.15 C25.61,14.15 25.62,20.04 25.62,20.04 "/></group></group><group android:name="time_group"/></vector></aapt:attr><target android:name="_R_G_L_3_G_D_0_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="fillAlpha" android:duration="67" android:startOffset="0" android:valueFrom="0" android:valueTo="0" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="fillAlpha" android:duration="167" android:startOffset="67" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_2_G_D_0_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="strokeWidth" android:duration="167" android:startOffset="0" android:valueFrom="2.5" android:valueTo="0" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_2_G_D_0_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="strokeAlpha" android:duration="83" android:startOffset="0" android:valueFrom="1" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="strokeAlpha" android:duration="83" android:startOffset="83" android:valueFrom="1" android:valueTo="0" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_2_G"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleY" android:duration="0" android:startOffset="0" android:valueFrom="0" android:valueTo="0.975" android:valueType="floatType"/></set></aapt:attr></target><target android:name="_R_G_L_2_G"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleY" android:duration="0" android:startOffset="167" android:valueFrom="0.975" android:valueTo="0" android:valueType="floatType"/></set></aapt:attr></target><target android:name="_R_G_L_1_G_D_0_P_0_G_0_T_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleX" android:duration="67" android:startOffset="0" android:valueFrom="1" android:valueTo="1.1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.853,0 0.6,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleY" android:duration="67" android:startOffset="0" android:valueFrom="1" android:valueTo="1.1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.853,0 0.6,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleX" android:duration="100" android:startOffset="67" android:valueFrom="1.1" android:valueTo="0" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.92,1.06 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleY" android:duration="100" android:startOffset="67" android:valueFrom="1.1" android:valueTo="0" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.92,1.06 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_1_G_D_1_P_0_G_0_T_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleX" android:duration="67" android:startOffset="0" android:valueFrom="1" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.659,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleY" android:duration="67" android:startOffset="0" android:valueFrom="1" android:valueTo="1.1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.6,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleX" android:duration="100" android:startOffset="67" android:valueFrom="1" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.6,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleY" android:duration="100" android:startOffset="67" android:valueFrom="1.1" android:valueTo="0" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.92,1.096 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_0_G_D_3_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="pathData" android:duration="233" android:startOffset="0" android:valueFrom="M13.12 20.04 C13.12,20.04 13.11,14.15 13.11,14.15 C13.11,10.77 15.91,8.04 19.36,8.04 C22.81,8.04 25.61,10.77 25.61,14.15 C25.61,14.15 25.62,20.04 25.62,20.04 " android:valueTo="M13.12 20.04 C13.12,20.04 13.11,14.15 13.11,14.15 C13.11,10.77 15.91,8.04 19.36,8.04 C22.81,8.04 25.61,10.77 25.61,14.15 C25.61,14.15 25.62,20.04 25.62,20.04 " android:valueType="pathType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="pathData" android:duration="267" android:startOffset="233" android:valueFrom="M13.12 20.04 C13.12,20.04 13.11,14.15 13.11,14.15 C13.11,10.77 15.91,8.04 19.36,8.04 C22.81,8.04 25.61,10.77 25.61,14.15 C25.61,14.15 25.62,20.04 25.62,20.04 " android:valueTo="M37.91 20.05 C37.91,20.05 37.89,14.16 37.89,14.16 C37.89,10.79 35.15,8.05 31.86,8.03 C28.46,8.01 25.61,10.77 25.61,14.15 C25.61,14.15 25.62,20.04 25.62,20.04 " android:valueType="pathType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_0_G"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleX" android:duration="167" android:startOffset="0" android:valueFrom="0.5" android:valueTo="0.5" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.05,1.4 0.1,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleY" android:duration="167" android:startOffset="0" android:valueFrom="0.5" android:valueTo="0.5" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.05,1.4 0.1,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleX" android:duration="333" android:startOffset="167" android:valueFrom="0.5" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.05,1.4 0.1,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleY" android:duration="333" android:startOffset="167" android:valueFrom="0.5" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.05,1.4 0.1,1 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_0_G"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleY" android:duration="0" android:startOffset="167" android:valueFrom="0" android:valueTo="0.5" android:valueType="floatType"/></set></aapt:attr></target><target android:name="time_group"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="translateX" android:duration="683" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/></set></aapt:attr></target></animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/fingerprint_dialog_fp_to_error.xml b/packages/SystemUI/res/drawable/fingerprint_dialog_fp_to_error.xml
deleted file mode 100644
index c05a8d5..0000000
--- a/packages/SystemUI/res/drawable/fingerprint_dialog_fp_to_error.xml
+++ /dev/null
@@ -1 +0,0 @@
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"><aapt:attr name="android:drawable"><vector android:height="80dp" android:width="80dp" android:viewportHeight="80" android:viewportWidth="80"><group android:name="_R_G"><group android:name="_R_G_L_3_G" android:translateX="-0.25" android:translateY="-0.25"><path android:name="_R_G_L_3_G_D_0_P_0" android:fillColor="#474747" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M40.21 0.25 C18.13,0.25 0.25,18.17 0.25,40.25 C0.25,62.33 18.13,80.25 40.21,80.25 C62.33,80.25 80.25,62.33 80.25,40.25 C80.25,18.17 62.33,0.25 40.21,0.25c "/></group><group android:name="_R_G_L_2_G" android:translateX="-0.25" android:translateY="-0.25" android:pivotX="40.25" android:pivotY="40.25" android:scaleX="0.975" android:scaleY="0"><path android:name="_R_G_L_2_G_D_0_P_0" android:strokeColor="#f2b8b5" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="0" android:strokeAlpha="0" android:pathData=" M40.21 0.25 C18.13,0.25 0.25,18.17 0.25,40.25 C0.25,62.33 18.13,80.25 40.21,80.25 C62.33,80.25 80.25,62.33 80.25,40.25 C80.25,18.17 62.33,0.25 40.21,0.25c "/></group><group android:name="_R_G_L_1_G" android:translateX="9.950000000000003" android:translateY="10" android:pivotX="30" android:pivotY="30" android:scaleX="1.2" android:scaleY="1.2"><group android:name="_R_G_L_1_G_D_0_P_0_G_0_T_0" android:translateX="30" android:translateY="38.75" android:scaleX="0" android:scaleY="0"><path android:name="_R_G_L_1_G_D_0_P_0" android:fillColor="#f2b8b5" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-1.2 -1.25 C-1.2,-1.25 1.2,-1.25 1.2,-1.25 C1.2,-1.25 1.2,1.25 1.2,1.25 C1.2,1.25 -1.2,1.25 -1.2,1.25 C-1.2,1.25 -1.2,-1.25 -1.2,-1.25c "/></group><group android:name="_R_G_L_1_G_D_1_P_0_G_0_T_0" android:translateX="30" android:translateY="25" android:pivotX="0.002" android:pivotY="7.488" android:scaleX="1" android:scaleY="0"><path android:name="_R_G_L_1_G_D_1_P_0" android:fillColor="#f2b8b5" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-1.2 -7.5 C-1.2,-7.5 1.2,-7.5 1.2,-7.5 C1.2,-7.5 1.2,7.5 1.2,7.5 C1.2,7.5 -1.2,7.5 -1.2,7.5 C-1.2,7.5 -1.2,-7.5 -1.2,-7.5c "/></group></group><group android:name="_R_G_L_0_G" android:translateX="20.659" android:translateY="15.75"><path android:name="_R_G_L_0_G_D_0_P_0" android:strokeColor="#d3e3fd" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:trimPathStart="0" android:trimPathEnd="1" android:trimPathOffset="0" android:pathData=" M27.52 38.98 C26.49,39.95 25.29,40.73 23.98,41.29 C23.17,41.65 22.31,41.91 21.41,42.07 C20.74,42.19 20.05,42.25 19.34,42.25 C18.44,42.25 17.56,42.15 16.72,41.96 C15.93,41.77 15.16,41.51 14.43,41.18 C13.23,40.63 12.13,39.88 11.16,38.98 "/><path android:name="_R_G_L_0_G_D_1_P_0" android:strokeColor="#d3e3fd" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:trimPathStart="0" android:trimPathEnd="1" android:trimPathOffset="0" android:pathData=" M8.64 34.07 C7.89,31.97 7.89,29.85 7.89,29.85 C7.89,24.05 12.81,19.34 19.34,19.34 C25.87,19.34 30.8,24.05 30.8,29.85 C30.8,29.85 30.8,30.16 30.8,30.16 C30.8,32.32 29.04,34.07 26.89,34.07 C25.28,34.07 23.86,33.1 23.27,31.61 C23.27,31.61 21.96,28.34 21.96,28.34 C21.37,26.85 19.93,25.89 18.34,25.89 C16.18,25.89 14.43,27.64 14.43,29.8 C14.43,31.42 14.87,32.99 15.68,34.36 C16.22,35.26 16.93,36.08 17.77,36.75 C17.77,36.75 18.52,37.34 18.52,37.34 "/><path android:name="_R_G_L_0_G_D_2_P_0" android:strokeColor="#d3e3fd" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:trimPathStart="0" android:trimPathEnd="1" android:trimPathOffset="0" android:pathData=" M6.25 19.34 C7.48,17.3 9.46,15.58 11.9,14.42 C12.93,13.94 14.03,13.55 15.2,13.27 C16.51,12.96 17.9,12.8 19.34,12.8 C20.77,12.8 22.14,12.96 23.45,13.26 C24.9,13.6 26.26,14.12 27.48,14.78 C29.6,15.92 31.32,17.5 32.43,19.34 "/><path android:name="_R_G_L_0_G_D_3_P_0" android:strokeColor="#d3e3fd" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:trimPathStart="0" android:trimPathEnd="1" android:trimPathOffset="0" android:pathData=" M9.52 8.7 C10.98,7.91 12.58,7.28 14.28,6.86 C15.89,6.46 17.58,6.25 19.34,6.25 C21.06,6.25 22.72,6.45 24.3,6.83 C26.04,7.25 27.67,7.89 29.16,8.7 "/></group></group><group android:name="time_group"/></vector></aapt:attr><target android:name="_R_G_L_3_G_D_0_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="fillAlpha" android:duration="83" android:startOffset="0" android:valueFrom="1" android:valueTo="0" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_2_G_D_0_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="strokeWidth" android:duration="67" android:startOffset="0" android:valueFrom="0" android:valueTo="0" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="strokeWidth" android:duration="233" android:startOffset="67" android:valueFrom="0" android:valueTo="2.5" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_2_G_D_0_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="strokeAlpha" android:duration="67" android:startOffset="0" android:valueFrom="0" android:valueTo="0" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="strokeAlpha" android:duration="83" android:startOffset="67" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_2_G"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleY" android:duration="0" android:startOffset="67" android:valueFrom="0" android:valueTo="0.975" android:valueType="floatType"/></set></aapt:attr></target><target android:name="_R_G_L_1_G_D_0_P_0_G_0_T_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleX" android:duration="167" android:startOffset="0" android:valueFrom="0" android:valueTo="0" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.06 0.2,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleY" android:duration="167" android:startOffset="0" android:valueFrom="0" android:valueTo="0" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.06 0.2,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleX" android:duration="100" android:startOffset="167" android:valueFrom="0" android:valueTo="1.1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.06 0.2,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleY" android:duration="100" android:startOffset="167" android:valueFrom="0" android:valueTo="1.1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.06 0.2,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleX" android:duration="67" android:startOffset="267" android:valueFrom="1.1" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.147,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleY" android:duration="67" android:startOffset="267" android:valueFrom="1.1" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.147,1 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_1_G_D_1_P_0_G_0_T_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleX" android:duration="167" android:startOffset="0" android:valueFrom="1" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleY" android:duration="167" android:startOffset="0" android:valueFrom="0" android:valueTo="0" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.096 0.2,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleX" android:duration="100" android:startOffset="167" android:valueFrom="1" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleY" android:duration="100" android:startOffset="167" android:valueFrom="0" android:valueTo="1.1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.096 0.2,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleX" android:duration="67" android:startOffset="267" android:valueFrom="1" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.341,0 0.2,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleY" android:duration="67" android:startOffset="267" android:valueFrom="1.1" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_0_G_D_0_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="trimPathStart" android:duration="167" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_0_G_D_1_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="trimPathStart" android:duration="167" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_0_G_D_2_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="trimPathStart" android:duration="167" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_0_G_D_3_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="trimPathStart" android:duration="167" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="time_group"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="translateX" android:duration="350" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/></set></aapt:attr></target></animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/fingerprint_dialog_fp_to_unlock.xml b/packages/SystemUI/res/drawable/fingerprint_dialog_fp_to_unlock.xml
deleted file mode 100644
index 1694429..0000000
--- a/packages/SystemUI/res/drawable/fingerprint_dialog_fp_to_unlock.xml
+++ /dev/null
@@ -1 +0,0 @@
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"><aapt:attr name="android:drawable"><vector android:height="80dp" android:width="80dp" android:viewportHeight="80" android:viewportWidth="80"><group android:name="_R_G"><group android:name="_R_G_L_2_G" android:translateX="-0.25" android:translateY="-0.25"><path android:name="_R_G_L_2_G_D_0_P_0" android:fillColor="#474747" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M40.21 0.25 C18.13,0.25 0.25,18.17 0.25,40.25 C0.25,62.33 18.13,80.25 40.21,80.25 C62.33,80.25 80.25,62.33 80.25,40.25 C80.25,18.17 62.33,0.25 40.21,0.25c "/></group><group android:name="_R_G_L_1_G" android:translateX="20.75" android:translateY="15.75"><path android:name="_R_G_L_1_G_D_0_P_0" android:strokeColor="#d3e3fd" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M27.52 38.98 C26.49,39.95 25.29,40.73 23.98,41.29 C23.17,41.65 22.31,41.91 21.41,42.07 C20.74,42.19 20.05,42.25 19.34,42.25 C18.44,42.25 17.56,42.15 16.72,41.96 C15.93,41.77 15.16,41.51 14.43,41.18 C13.23,40.63 12.13,39.88 11.16,38.98 "/><path android:name="_R_G_L_1_G_D_1_P_0" android:strokeColor="#d3e3fd" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M8.64 34.07 C7.89,31.97 7.89,29.85 7.89,29.85 C7.89,24.05 12.81,19.34 19.34,19.34 C25.87,19.34 30.8,24.05 30.8,29.85 C30.8,29.85 30.8,30.16 30.8,30.16 C30.8,32.32 29.04,34.07 26.89,34.07 C25.28,34.07 23.86,33.1 23.27,31.61 C23.27,31.61 21.96,28.34 21.96,28.34 C21.37,26.85 19.93,25.89 18.34,25.89 C16.18,25.89 14.43,27.64 14.43,29.8 C14.43,31.42 14.87,32.99 15.68,34.36 C16.22,35.26 16.93,36.08 17.77,36.75 C17.77,36.75 18.52,37.34 18.52,37.34 "/><path android:name="_R_G_L_1_G_D_2_P_0" android:strokeColor="#d3e3fd" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M6.25 19.34 C7.48,17.3 9.46,15.58 11.9,14.42 C12.93,13.94 14.03,13.55 15.2,13.27 C16.51,12.96 17.9,12.8 19.34,12.8 C20.77,12.8 22.14,12.96 23.45,13.26 C24.9,13.6 26.26,14.12 27.48,14.78 C29.6,15.92 31.32,17.5 32.43,19.34 "/><path android:name="_R_G_L_1_G_D_3_P_0" android:strokeColor="#d3e3fd" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M9.52 8.7 C10.98,7.91 12.58,7.28 14.28,6.86 C15.89,6.46 17.58,6.25 19.34,6.25 C21.06,6.25 22.72,6.45 24.3,6.83 C26.04,7.25 27.67,7.89 29.16,8.7 "/></group><group android:name="_R_G_L_0_G" android:translateX="37.357" android:translateY="43.25" android:pivotX="2.75" android:pivotY="2.75" android:scaleX="1.41866" android:scaleY="1.41866"><path android:name="_R_G_L_0_G_D_0_P_0" android:fillColor="#d3e3fd" android:fillAlpha="0" android:fillType="nonZero" android:pathData=" M2.75 5.25 C4.13,5.25 5.25,4.13 5.25,2.75 C5.25,1.37 4.13,0.25 2.75,0.25 C1.37,0.25 0.25,1.37 0.25,2.75 C0.25,4.13 1.37,5.25 2.75,5.25c "/></group></group><group android:name="time_group"/></vector></aapt:attr><target android:name="_R_G_L_1_G_D_0_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="pathData" android:duration="107" android:startOffset="0" android:valueFrom="M27.52 38.98 C26.49,39.95 25.29,40.73 23.98,41.29 C23.17,41.65 22.31,41.91 21.41,42.07 C20.74,42.19 20.05,42.25 19.34,42.25 C18.44,42.25 17.56,42.15 16.72,41.96 C15.93,41.77 15.16,41.51 14.43,41.18 C13.23,40.63 12.13,39.88 11.16,38.98 " android:valueTo="M30.81 32.26 C30.56,32.49 30.27,38.76 29.96,38.9 C29.77,39.46 29.13,39.94 28.57,40.26 C28.15,40.51 26.93,40.65 26.4,40.65 C26.18,40.65 11.91,40.62 11.71,40.58 C10.68,40.53 9.06,39.79 8.89,38.88 C8.6,38.74 8.34,32.48 8.1,32.27 " android:valueType="pathType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.541,0 0.833,0.767 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="pathData" android:duration="143" android:startOffset="107" android:valueFrom="M30.81 32.26 C30.56,32.49 30.27,38.76 29.96,38.9 C29.77,39.46 29.13,39.94 28.57,40.26 C28.15,40.51 26.93,40.65 26.4,40.65 C26.18,40.65 11.91,40.62 11.71,40.58 C10.68,40.53 9.06,39.79 8.89,38.88 C8.6,38.74 8.34,32.48 8.1,32.27 " android:valueTo="M30.64 30.14 C30.64,30.14 30.64,38.14 30.64,38.14 C30.64,38.77 30.36,39.32 29.91,39.69 C29.57,39.97 29.12,40.14 28.64,40.14 C28.64,40.14 10.14,40.14 10.14,40.14 C9.04,40.14 8.14,39.25 8.14,38.14 C8.14,38.14 8.14,30.14 8.14,30.14 " android:valueType="pathType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.233 0.331,1 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_1_G_D_1_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="strokeAlpha" android:duration="140" android:startOffset="0" android:valueFrom="1" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="strokeAlpha" android:duration="50" android:startOffset="140" android:valueFrom="1" android:valueTo="0" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_1_G_D_1_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="pathData" android:duration="107" android:startOffset="0" android:valueFrom="M8.64 34.07 C7.89,31.97 7.89,29.85 7.89,29.85 C7.89,24.05 12.81,19.34 19.34,19.34 C25.87,19.34 30.8,24.05 30.8,29.85 C30.8,29.85 30.8,30.16 30.8,30.16 C30.8,32.32 29.04,34.07 26.89,34.07 C25.28,34.07 23.86,33.1 23.27,31.61 C23.27,31.61 21.96,28.34 21.96,28.34 C21.37,26.85 19.93,25.89 18.34,25.89 C16.18,25.89 14.43,27.64 14.43,29.8 C14.43,31.42 14.87,32.99 15.68,34.36 C16.22,35.26 16.93,36.08 17.77,36.75 C17.77,36.75 18.52,37.34 18.52,37.34 " android:valueTo="M18.93 32.18 C17.11,32.68 16.62,30.26 16.62,30.26 C16.62,28.78 17.81,27.59 19.39,27.59 C20.96,27.59 22.15,28.78 22.15,30.26 C22.15,30.26 22.15,30.34 22.15,30.34 C22.15,30.89 21.11,32.54 19.57,32.19 C19.19,32.1 20.48,31.09 20.34,30.71 C20.34,30.71 20.02,29.88 20.02,29.88 C19.88,29.5 19.53,29.25 19.15,29.25 C18.63,29.25 18,29.67 18,30.22 C18,30.57 18.06,31.08 18.32,31.51 C18.49,31.8 19.02,32.25 19.79,32.04 C20.41,31.7 20.38,31.36 20.38,31.36 " android:valueType="pathType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.541,0 0.833,0.767 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="pathData" android:duration="107" android:startOffset="107" android:valueFrom="M18.93 32.18 C17.11,32.68 16.62,30.26 16.62,30.26 C16.62,28.78 17.81,27.59 19.39,27.59 C20.96,27.59 22.15,28.78 22.15,30.26 C22.15,30.26 22.15,30.34 22.15,30.34 C22.15,30.89 21.11,32.54 19.57,32.19 C19.19,32.1 20.48,31.09 20.34,30.71 C20.34,30.71 20.02,29.88 20.02,29.88 C19.88,29.5 19.53,29.25 19.15,29.25 C18.63,29.25 18,29.67 18,30.22 C18,30.57 18.06,31.08 18.32,31.51 C18.49,31.8 19.02,32.25 19.79,32.04 C20.41,31.7 20.38,31.36 20.38,31.36 " android:valueTo="M19.42 31.53 C18.15,31.52 18.11,30.33 18.11,30.33 C18.11,29.59 18.66,28.98 19.4,28.98 C20.13,28.98 20.69,29.59 20.69,30.33 C20.69,30.33 20.69,30.37 20.69,30.37 C20.69,30.64 20.49,30.87 20.25,30.87 C20.07,30.87 19.91,30.74 19.84,30.55 C19.84,30.55 19.69,30.14 19.69,30.14 C19.63,29.94 19.46,29.82 19.28,29.82 C19.04,29.82 18.61,30.02 18.61,30.29 C18.61,30.43 18.6,30.75 18.76,31.03 C18.87,31.21 19.21,31.77 19.96,31.41 C20.69,31.01 20.69,30.34 20.69,30.34 " android:valueType="pathType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.233 0,1 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_1_G_D_2_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="pathData" android:duration="250" android:startOffset="0" android:valueFrom="M6.25 19.34 C7.48,17.3 9.46,15.58 11.9,14.42 C12.93,13.94 14.03,13.55 15.2,13.27 C16.51,12.96 17.9,12.8 19.34,12.8 C20.77,12.8 22.14,12.96 23.45,13.26 C24.9,13.6 26.26,14.12 27.48,14.78 C29.6,15.92 31.32,17.5 32.43,19.34 " android:valueTo="M8.14 30.22 C8.14,30.22 8.14,22.22 8.14,22.22 C8.14,21.71 8.33,21.25 8.64,20.9 C9,20.48 9.54,20.22 10.14,20.22 C10.14,20.22 28.64,20.22 28.64,20.22 C29.75,20.22 30.64,21.11 30.64,22.22 C30.64,22.22 30.64,30.14 30.64,30.14 " android:valueType="pathType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.541,0 0.189,1 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_1_G_D_3_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="pathData" android:duration="95" android:startOffset="0" android:valueFrom="M9.52 8.7 C10.98,7.91 12.58,7.28 14.28,6.86 C15.89,6.46 17.58,6.25 19.34,6.25 C21.06,6.25 22.72,6.45 24.3,6.83 C26.04,7.25 27.67,7.89 29.16,8.7 " android:valueTo="M11.47 14.84 C11.47,14.84 12.21,11.43 13.54,9.84 C14.84,8.28 16.68,7.22 19.35,7.22 C22.01,7.22 23.98,8.4 25.19,10.18 C26.39,11.96 27.25,14.84 27.25,14.84 " android:valueType="pathType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.541,0 0.833,0.767 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="pathData" android:duration="24" android:startOffset="95" android:valueFrom="M11.47 14.84 C11.47,14.84 12.21,11.43 13.54,9.84 C14.84,8.28 16.68,7.22 19.35,7.22 C22.01,7.22 23.98,8.4 25.19,10.18 C26.39,11.96 27.25,14.84 27.25,14.84 " android:valueTo="M12.11 16.85 C12.11,16.85 12.82,12.71 13.37,11.5 C14.17,9.24 16.38,7.53 19.35,7.53 C22.32,7.53 24.61,9.32 25.35,11.72 C25.61,12.64 26.62,16.85 26.62,16.85 " android:valueType="pathType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.233 0.833,0.767 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="pathData" android:duration="81" android:startOffset="119" android:valueFrom="M12.11 16.85 C12.11,16.85 12.82,12.71 13.37,11.5 C14.17,9.24 16.38,7.53 19.35,7.53 C22.32,7.53 24.61,9.32 25.35,11.72 C25.61,12.64 26.62,16.85 26.62,16.85 " android:valueTo="M13.12 20.04 C13.12,20.04 13.11,14.15 13.11,14.15 C13.11,10.77 15.91,8.04 19.36,8.04 C22.81,8.04 25.61,10.77 25.61,14.15 C25.61,14.15 25.62,20.04 25.62,20.04 " android:valueType="pathType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.233 0.261,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="pathData" android:duration="233" android:startOffset="200" android:valueFrom="M13.12 20.04 C13.12,20.04 13.11,14.15 13.11,14.15 C13.11,10.77 15.91,8.04 19.36,8.04 C22.81,8.04 25.61,10.77 25.61,14.15 C25.61,14.15 25.62,20.04 25.62,20.04 " android:valueTo="M37.91 20.05 C37.91,20.05 37.89,14.16 37.89,14.16 C37.89,10.79 35.15,8.05 31.86,8.03 C28.46,8.01 25.61,10.77 25.61,14.15 C25.61,14.15 25.62,20.04 25.62,20.04 " android:valueType="pathType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.123,0 0.23,1 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_0_G_D_0_P_0"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="fillAlpha" android:duration="120" android:startOffset="0" android:valueFrom="0" android:valueTo="0" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="fillAlpha" android:duration="20" android:startOffset="120" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="_R_G_L_0_G"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="scaleX" android:duration="120" android:startOffset="0" android:valueFrom="1.4186600000000003" android:valueTo="1.4186600000000003" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0.43,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleY" android:duration="120" android:startOffset="0" android:valueFrom="1.4186600000000003" android:valueTo="1.4186600000000003" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0.43,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleX" android:duration="130" android:startOffset="120" android:valueFrom="1.4186600000000003" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0.43,1 1.0,1.0"/></aapt:attr></objectAnimator><objectAnimator android:propertyName="scaleY" android:duration="130" android:startOffset="120" android:valueFrom="1.4186600000000003" android:valueTo="1" android:valueType="floatType"><aapt:attr name="android:interpolator"><pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0.43,1 1.0,1.0"/></aapt:attr></objectAnimator></set></aapt:attr></target><target android:name="time_group"><aapt:attr name="android:animation"><set android:ordering="together"><objectAnimator android:propertyName="translateX" android:duration="517" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/></set></aapt:attr></target></animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/auth_biometric_contents.xml b/packages/SystemUI/res/layout/auth_biometric_contents.xml
index e1b294f..d633803 100644
--- a/packages/SystemUI/res/layout/auth_biometric_contents.xml
+++ b/packages/SystemUI/res/layout/auth_biometric_contents.xml
@@ -49,11 +49,11 @@
 
     <FrameLayout
         android:id="@+id/biometric_icon_frame"
-        android:layout_width="match_parent"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_gravity="center_horizontal">
 
-        <ImageView
+        <com.airbnb.lottie.LottieAnimationView
             android:id="@+id/biometric_icon"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res/layout/auth_biometric_fingerprint_view.xml b/packages/SystemUI/res/layout/auth_biometric_fingerprint_view.xml
index ce53e27..01ea31f 100644
--- a/packages/SystemUI/res/layout/auth_biometric_fingerprint_view.xml
+++ b/packages/SystemUI/res/layout/auth_biometric_fingerprint_view.xml
@@ -17,7 +17,7 @@
 <com.android.systemui.biometrics.AuthBiometricFingerprintView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/contents"
-    android:layout_width="match_parent"
+    android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:orientation="vertical">
 
diff --git a/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml b/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml
index 70a7709..c972624 100644
--- a/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml
@@ -35,10 +35,20 @@
         app:layout_constraintBottom_toBottomOf="parent" />
 
     <LinearLayout
+        android:id="@+id/dream_overlay_extra_items"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:orientation="horizontal"
+        android:gravity="center_vertical"
+        android:layout_marginEnd="@dimen/dream_overlay_status_bar_extra_margin"
+        app:layout_constraintEnd_toStartOf="@+id/dream_overlay_system_status" />
+
+    <LinearLayout
         android:id="@+id/dream_overlay_system_status"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
         android:orientation="horizontal"
+        android:layout_marginStart="@dimen/dream_overlay_status_bar_extra_margin"
         app:layout_constraintEnd_toEndOf="parent">
 
         <com.android.systemui.statusbar.AlphaOptimizedImageView
diff --git a/packages/SystemUI/res/raw/fingerprint_dialogue_error_to_fingerprint_lottie.json b/packages/SystemUI/res/raw/fingerprint_dialogue_error_to_fingerprint_lottie.json
new file mode 100644
index 0000000..cc68a83
--- /dev/null
+++ b/packages/SystemUI/res/raw/fingerprint_dialogue_error_to_fingerprint_lottie.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":25,"w":80,"h":80,"nm":"error_to_fingerprint","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".colorAccentPrimary","cl":"colorAccentPrimary","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[40,40,0],"ix":2,"l":2},"a":{"a":0,"k":[19.341,24.25,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-1.701,0.42],[-1.757,0],[-1.577,-0.381],[-1.485,-0.816]],"o":[[1.455,-0.799],[1.608,-0.397],[1.719,0],[1.739,0.42],[0,0]],"v":[[-9.818,1.227],[-5.064,-0.618],[0,-1.227],[4.96,-0.643],[9.818,1.227]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.827450990677,0.890196084976,0.992156863213,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,7.477],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Top","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-2.446,1.161],[-1.168,0.275],[-1.439,0],[-1.301,-0.304],[-1.225,-0.66],[-1.11,-1.844]],"o":[[1.23,-2.044],[1.024,-0.486],[1.312,-0.31],[1.425,0],[1.454,0.34],[2.122,1.143],[0,0]],"v":[[-13.091,3.273],[-7.438,-1.646],[-4.14,-2.797],[0,-3.273],[4.104,-2.805],[8.141,-1.29],[13.091,3.273]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.827450980392,0.890196078431,0.992156862745,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,16.069],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Mid Top","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-6.53,0],[0,-5.793],[0,0],[2.159,0],[0.59,1.489],[0,0],[1.587,0],[0,-2.16],[-0.81,-1.363],[-0.844,-0.674],[0,0]],"o":[[-0.753,-2.095],[0,-5.793],[6.529,0],[0,0],[0,2.16],[-1.604,0],[0,0],[-0.589,-1.489],[-2.161,0],[0,1.62],[0.54,0.909],[0,0],[0,0]],"v":[[-10.702,5.728],[-11.454,1.506],[0.001,-9],[11.454,1.506],[11.454,1.817],[7.544,5.728],[3.926,3.273],[2.618,0],[-0.997,-2.454],[-4.91,1.457],[-3.657,6.014],[-1.57,8.412],[-0.818,9]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.827450980392,0.890196078431,0.992156862745,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,28.341],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Inside to dot ","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.307,-0.561],[0.894,-0.16],[0.706,0],[0.844,0.193],[0.728,0.334],[0.967,0.901]],"o":[[-1.038,0.967],[-0.817,0.351],[-0.673,0.12],[-0.9,0],[-0.794,-0.182],[-1.203,-0.551],[0,0]],"v":[[8.182,-1.636],[4.642,0.681],[2.07,1.453],[-0.001,1.636],[-2.621,1.341],[-4.909,0.563],[-8.182,-1.636]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.827450980392,0.890196078431,0.992156862745,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,40.614],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Bottom","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.299],"y":[1]},"o":{"x":[0.543],"y":[0]},"t":5,"s":[0]},{"t":20,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":5,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".red200","cl":"red200","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[39.95,40,0],"ix":2,"l":2},"a":{"a":0,"k":[30,30,0],"ix":1,"l":2},"s":{"a":0,"k":[120,120,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-1.2,-7.5],[1.2,-7.5],[1.2,7.5],[-1.2,7.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.949019607843,0.721568627451,0.709803921569,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[30.002,32.488],"ix":2},"a":{"a":0,"k":[0.002,7.488],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.659,0.6],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":0,"s":[100,100]},{"i":{"x":[0.6,0.92],"y":[1,1.096]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":4,"s":[100,110]},{"t":10,"s":[100,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Top!","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-1.2,-1.25],[1.2,-1.25],[1.2,1.25],[-1.2,1.25]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.949019607843,0.721568627451,0.709803921569,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[30,38.75],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.6,0.6],"y":[1,1]},"o":{"x":[0.853,0.853],"y":[0,0]},"t":0,"s":[100,100]},{"i":{"x":[0.92,0.92],"y":[1.06,1.06]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":4,"s":[110,110]},{"t":10,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Bottom!","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":25,"st":-30,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".red200","cl":"red200","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":5,"s":[100]},{"t":10,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[40,40,0],"ix":2,"l":2},"a":{"a":0,"k":[40.25,40.25,0],"ix":1,"l":2},"s":{"a":0,"k":[97.5,97.5,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[22.12,0],[0,-22.08],[-22.08,0],[0,22.08]],"o":[[-22.08,0],[0,22.08],[22.12,0],[0,-22.08]],"v":[[-0.04,-40],[-40,0],[-0.04,40],[40,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[40.25,40.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":5,"s":[100]},{"t":10,"s":[0]}],"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.949019607843,0.721568627451,0.709803921569,1],"ix":3},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":5,"s":[100]},{"t":10,"s":[0]}],"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[2.5]},{"t":10,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false}],"ip":0,"op":10,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".grey700","cl":"grey700","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[40,40,0],"ix":2,"l":2},"a":{"a":0,"k":[40.25,40.25,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[22.12,0],[0,-22.08],[-22.08,0],[0,22.08]],"o":[[-22.08,0],[0,22.08],[22.12,0],[0,-22.08]],"v":[[-0.04,-40],[-40,0],[-0.04,40],[40,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.278431385756,0.278431385756,0.278431385756,1],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":4,"s":[0]},{"t":14,"s":[100]}],"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[40.25,40.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/fingerprint_dialogue_error_to_unlock_lottie.json b/packages/SystemUI/res/raw/fingerprint_dialogue_error_to_unlock_lottie.json
new file mode 100644
index 0000000..aaf7e58
--- /dev/null
+++ b/packages/SystemUI/res/raw/fingerprint_dialogue_error_to_unlock_lottie.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":41,"w":80,"h":80,"nm":"error_to_unlock","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".colorAccentPrimary","cl":"colorAccentPrimary","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[40.091,40,0],"ix":2,"l":2},"a":{"a":0,"k":[19.341,24.25,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.1,0.1,0.1],"y":[1,1,1]},"o":{"x":[0.05,0.05,0.05],"y":[1.4,1.4,0]},"t":10,"s":[50,50,100]},{"t":30,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":14,"s":[{"i":[[0,0],[0,0],[-3.452,0],[0,-3.375],[0,0]],"o":[[0,0],[0,-3.375],[3.452,0],[0,0],[0,0]],"v":[[-6.217,12.558],[-6.234,6.669],[0.016,0.558],[6.266,6.669],[6.283,12.558]],"c":false}]},{"t":30,"s":[{"i":[[0,0],[0,0],[3.292,0.021],[0,-3.375],[0,0]],"o":[[0,0],[0,-3.375],[-3.393,-0.022],[0,0],[0,0]],"v":[[18.568,12.573],[18.552,6.684],[12.516,0.553],[6.266,6.669],[6.283,12.558]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.827450990677,0.890196084976,0.992156863213,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,7.477],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Top","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-0.307,0.352],[-0.601,0],[0,0],[0,-1.104],[0,0]],"o":[[0,0],[0,-0.503],[0.367,-0.42],[0,0],[1.104,0],[0,0],[0,0]],"v":[[-11.2,14.15],[-11.198,6.146],[-10.705,4.831],[-9.198,4.146],[9.302,4.146],[11.302,6.146],[11.3,14.07]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.827450980392,0.890196078431,0.992156862745,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,16.069],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Mid Top","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-0.736,0],[0,-0.741],[0,0],[0.243,0],[0.066,0.191],[0,0],[0.179,0],[0,-0.276],[-0.162,-0.273],[-0.755,0.357],[0,0]],"o":[[-1.273,-0.008],[0,-0.741],[0.736,0],[0,0],[0,0.276],[-0.181,0],[0,0],[-0.066,-0.191],[-0.243,0],[-0.002,0.139],[0.109,0.182],[0.727,-0.402],[0,0]],"v":[[0.082,3.187],[-1.235,1.986],[0.055,0.642],[1.346,1.986],[1.346,2.026],[0.905,2.527],[0.498,2.212],[0.35,1.794],[-0.057,1.479],[-0.733,1.951],[-0.58,2.686],[0.619,3.071],[1.351,2]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.827450980392,0.890196078431,0.992156862745,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,28.341],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Inside to dot ","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0.446,-0.367],[0.481,0],[0,0],[0,1.104],[0,0]],"o":[[0,0],[0,0.623],[-0.345,0.284],[0,0],[-1.104,0],[0,0],[0,0]],"v":[[11.302,-10.469],[11.302,-2.469],[10.57,-0.923],[9.302,-0.469],[-9.198,-0.469],[-11.198,-2.469],[-11.198,-10.469]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.827450980392,0.890196078431,0.992156862745,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,40.614],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Bottom","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":10,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".red200","cl":"red200","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[39.95,40,0],"ix":2,"l":2},"a":{"a":0,"k":[30,30,0],"ix":1,"l":2},"s":{"a":0,"k":[120,120,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-1.2,-7.5],[1.2,-7.5],[1.2,7.5],[-1.2,7.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.949019607843,0.721568627451,0.709803921569,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[30.002,32.488],"ix":2},"a":{"a":0,"k":[0.002,7.488],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.659,0.6],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":0,"s":[100,100]},{"i":{"x":[0.6,0.92],"y":[1,1.096]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":4,"s":[100,110]},{"t":10,"s":[100,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Top!","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-1.2,-1.25],[1.2,-1.25],[1.2,1.25],[-1.2,1.25]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.949019607843,0.721568627451,0.709803921569,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[30,38.75],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.6,0.6],"y":[1,1]},"o":{"x":[0.853,0.853],"y":[0,0]},"t":0,"s":[100,100]},{"i":{"x":[0.92,0.92],"y":[1.06,1.06]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":4,"s":[110,110]},{"t":10,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Bottom!","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":86,"st":-30,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".red200","cl":"red200","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":5,"s":[100]},{"t":10,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[40,40,0],"ix":2,"l":2},"a":{"a":0,"k":[40.25,40.25,0],"ix":1,"l":2},"s":{"a":0,"k":[97.5,97.5,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[22.12,0],[0,-22.08],[-22.08,0],[0,22.08]],"o":[[-22.08,0],[0,22.08],[22.12,0],[0,-22.08]],"v":[[-0.04,-40],[-40,0],[-0.04,40],[40,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[40.25,40.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":5,"s":[100]},{"t":10,"s":[0]}],"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.949019607843,0.721568627451,0.709803921569,1],"ix":3},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":5,"s":[100]},{"t":10,"s":[0]}],"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[2.5]},{"t":10,"s":[0]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false}],"ip":0,"op":10,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".grey700","cl":"grey700","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[40,40,0],"ix":2,"l":2},"a":{"a":0,"k":[40.25,40.25,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[22.12,0],[0,-22.08],[-22.08,0],[0,22.08]],"o":[[-22.08,0],[0,22.08],[22.12,0],[0,-22.08]],"v":[[-0.04,-40],[-40,0],[-0.04,40],[40,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.278431385756,0.278431385756,0.278431385756,1],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":4,"s":[0]},{"t":14,"s":[100]}],"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[40.25,40.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/fingerprint_dialogue_fingerprint_to_error_lottie.json b/packages/SystemUI/res/raw/fingerprint_dialogue_fingerprint_to_error_lottie.json
new file mode 100644
index 0000000..78bccba
--- /dev/null
+++ b/packages/SystemUI/res/raw/fingerprint_dialogue_fingerprint_to_error_lottie.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":80,"h":80,"nm":"fingerprint_to_error","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".colorAccentPrimary","cl":"colorAccentPrimary","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[40,40,0],"ix":2,"l":2},"a":{"a":0,"k":[19.341,24.25,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-1.701,0.42],[-1.757,0],[-1.577,-0.381],[-1.485,-0.816]],"o":[[1.455,-0.799],[1.608,-0.397],[1.719,0],[1.739,0.42],[0,0]],"v":[[-9.818,1.227],[-5.064,-0.618],[0,-1.227],[4.96,-0.643],[9.818,1.227]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.827450980392,0.890196078431,0.992156862745,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,7.477],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Top","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-2.446,1.161],[-1.168,0.275],[-1.439,0],[-1.301,-0.304],[-1.225,-0.66],[-1.11,-1.844]],"o":[[1.23,-2.044],[1.024,-0.486],[1.312,-0.31],[1.425,0],[1.454,0.34],[2.122,1.143],[0,0]],"v":[[-13.091,3.273],[-7.438,-1.646],[-4.14,-2.797],[0,-3.273],[4.104,-2.805],[8.141,-1.29],[13.091,3.273]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.827450980392,0.890196078431,0.992156862745,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,16.069],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Mid Top","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-6.53,0],[0,-5.793],[0,0],[2.159,0],[0.59,1.489],[0,0],[1.587,0],[0,-2.16],[-0.81,-1.363],[-0.844,-0.674],[0,0]],"o":[[-0.753,-2.095],[0,-5.793],[6.529,0],[0,0],[0,2.16],[-1.604,0],[0,0],[-0.589,-1.489],[-2.161,0],[0,1.62],[0.54,0.909],[0,0],[0,0]],"v":[[-10.702,5.728],[-11.454,1.506],[0.001,-9],[11.454,1.506],[11.454,1.817],[7.544,5.728],[3.926,3.273],[2.618,0],[-0.997,-2.454],[-4.91,1.457],[-3.657,6.014],[-1.57,8.412],[-0.818,9]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.827450980392,0.890196078431,0.992156862745,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,28.341],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Inside to dot ","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.307,-0.561],[0.894,-0.16],[0.706,0],[0.844,0.193],[0.728,0.334],[0.967,0.901]],"o":[[-1.038,0.967],[-0.817,0.351],[-0.673,0.12],[-0.9,0],[-0.794,-0.182],[-1.203,-0.551],[0,0]],"v":[[8.182,-1.636],[4.642,0.681],[2.07,1.453],[-0.001,1.636],[-2.621,1.341],[-4.909,0.563],[-8.182,-1.636]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.827450990677,0.890196084976,0.992156863213,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,40.614],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Bottom","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.2],"y":[0]},"t":0,"s":[0]},{"t":10,"s":[100]}],"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":5,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".red200","cl":"red200","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[39.95,40,0],"ix":2,"l":2},"a":{"a":0,"k":[30,30,0],"ix":1,"l":2},"s":{"a":0,"k":[120,120,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-1.2,-7.5],[1.2,-7.5],[1.2,7.5],[-1.2,7.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.949019610882,0.721568644047,0.709803938866,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[30.002,32.488],"ix":2},"a":{"a":0,"k":[0.002,7.488],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.4,0.08],"y":[0,0.096]},"t":10,"s":[100,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.341,0.4],"y":[0,0]},"t":16,"s":[100,110]},{"t":20,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Top!","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-1.2,-1.25],[1.2,-1.25],[1.2,1.25],[-1.2,1.25]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.949019610882,0.721568644047,0.709803938866,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[30,38.75],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.08,0.08],"y":[0.06,0.06]},"t":10,"s":[0,0]},{"i":{"x":[0.147,0.147],"y":[1,1]},"o":{"x":[0.4,0.4],"y":[0,0]},"t":16,"s":[110,110]},{"t":20,"s":[100,100]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Bottom!","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":21,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".red200","cl":"red200","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":4,"s":[0]},{"t":9,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[40,40,0],"ix":2,"l":2},"a":{"a":0,"k":[40.25,40.25,0],"ix":1,"l":2},"s":{"a":0,"k":[97.5,97.5,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[22.12,0],[0,-22.08],[-22.08,0],[0,22.08]],"o":[[-22.08,0],[0,22.08],[22.12,0],[0,-22.08]],"v":[[-0.04,-40],[-40,0],[-0.04,40],[40,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[40.25,40.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":4,"s":[0]},{"t":9,"s":[100]}],"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.949019607843,0.721568627451,0.709803921569,1],"ix":3},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":4,"s":[0]},{"t":9,"s":[100]}],"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":4,"s":[0]},{"t":18,"s":[2.5]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false}],"ip":4,"op":600,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".grey700","cl":"grey700","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[40,40,0],"ix":2,"l":2},"a":{"a":0,"k":[40.25,40.25,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[22.12,0],[0,-22.08],[-22.08,0],[0,22.08]],"o":[[-22.08,0],[0,22.08],[22.12,0],[0,-22.08]],"v":[[-0.04,-40],[-40,0],[-0.04,40],[40,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.278431385756,0.278431385756,0.278431385756,1],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[100]},{"t":5,"s":[0]}],"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[40.25,40.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/fingerprint_dialogue_fingerprint_to_unlock_lottie.json b/packages/SystemUI/res/raw/fingerprint_dialogue_fingerprint_to_unlock_lottie.json
new file mode 100644
index 0000000..313c6c5
--- /dev/null
+++ b/packages/SystemUI/res/raw/fingerprint_dialogue_fingerprint_to_unlock_lottie.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":31,"w":80,"h":80,"nm":"fingerprint_to_unlock","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":2,"ty":4,"nm":".colorAccentPrimary","cl":"colorAccentPrimary","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[40.107,46,0],"ix":2,"l":2},"a":{"a":0,"k":[2.75,2.75,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.43,0.43,0.2],"y":[1,1,1]},"o":{"x":[0.001,0.001,0.001],"y":[0,0,0]},"t":7.199,"s":[141.866,141.866,100]},{"t":15,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.381,0],[0,1.381],[1.381,0],[0,-1.381]],"o":[[1.381,0],[0,-1.381],[-1.381,0],[0,1.381]],"v":[[0,2.5],[2.5,0],[0,-2.5],[-2.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.827450980392,0.890196078431,0.992156862745,1],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":7.199,"s":[0]},{"t":8.400390625,"s":[100]}],"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[2.75,2.75],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".colorAccentPrimary","cl":"colorAccentPrimary","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[40.091,40,0],"ix":2,"l":2},"a":{"a":0,"k":[19.341,24.25,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.767},"o":{"x":0.541,"y":0},"t":0,"s":[{"i":[[0,0],[-1.701,0.42],[-1.757,0],[-1.577,-0.381],[-1.485,-0.816]],"o":[[1.455,-0.799],[1.608,-0.397],[1.719,0],[1.739,0.42],[0,0]],"v":[[-9.818,1.227],[-5.064,-0.618],[0,-1.227],[4.96,-0.643],[9.818,1.227]],"c":false}]},{"i":{"x":0.833,"y":0.767},"o":{"x":0.167,"y":0.233},"t":5.715,"s":[{"i":[[0,0],[-1.323,1.591],[-2.674,0],[-1.207,-1.781],[0,0]],"o":[[0,0],[1.298,-1.562],[2.657,0],[1.206,1.781],[0,0]],"v":[[-7.87,7.358],[-5.804,2.36],[0.009,-0.261],[5.845,2.706],[7.905,7.358]],"c":false}]},{"i":{"x":0.261,"y":1},"o":{"x":0.167,"y":0.233},"t":7.143,"s":[{"i":[[0,0],[-0.549,1.21],[-2.975,0],[-0.74,-2.398],[0,0]],"o":[[0,0],[0.796,-2.263],[2.964,0],[0.258,0.927],[0,0]],"v":[[-7.231,9.37],[-5.97,4.027],[0.012,0.056],[6.008,4.239],[7.277,9.37]],"c":false}]},{"i":{"x":0.23,"y":1},"o":{"x":0.123,"y":0},"t":12,"s":[{"i":[[0,0],[0,0],[-3.452,0],[0,-3.375],[0,0]],"o":[[0,0],[0,-3.375],[3.452,0],[0,0],[0,0]],"v":[[-6.217,12.558],[-6.234,6.669],[0.016,0.558],[6.266,6.669],[6.283,12.558]],"c":false}]},{"t":26,"s":[{"i":[[0,0],[0,0],[3.292,0.021],[0,-3.375],[0,0]],"o":[[0,0],[0,-3.375],[-3.393,-0.022],[0,0],[0,0]],"v":[[18.568,12.573],[18.552,6.684],[12.516,0.553],[6.266,6.669],[6.283,12.558]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.827450980392,0.890196078431,0.992156862745,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,7.477],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Top","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.189,"y":1},"o":{"x":0.541,"y":0},"t":0,"s":[{"i":[[0,0],[-2.446,1.161],[-1.168,0.275],[-1.439,0],[-1.301,-0.304],[-1.225,-0.66],[-1.11,-1.844]],"o":[[1.23,-2.044],[1.024,-0.486],[1.312,-0.31],[1.425,0],[1.454,0.34],[2.122,1.143],[0,0]],"v":[[-13.091,3.273],[-7.438,-1.646],[-4.14,-2.797],[0,-3.273],[4.104,-2.805],[8.141,-1.29],[13.091,3.273]],"c":false}]},{"t":15,"s":[{"i":[[0,0],[0,0],[-0.307,0.352],[-0.601,0],[0,0],[0,-1.104],[0,0]],"o":[[0,0],[0,-0.503],[0.367,-0.42],[0,0],[1.104,0],[0,0],[0,0]],"v":[[-11.2,14.15],[-11.198,6.146],[-10.705,4.831],[-9.198,4.146],[9.302,4.146],[11.302,6.146],[11.3,14.07]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.827450980392,0.890196078431,0.992156862745,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,16.069],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Mid Top","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.767},"o":{"x":0.541,"y":0},"t":0,"s":[{"i":[[0,0],[0,0],[-6.53,0],[0,-5.793],[0,0],[2.159,0],[0.59,1.489],[0,0],[1.587,0],[0,-2.16],[-0.81,-1.363],[-0.844,-0.674],[0,0]],"o":[[-0.753,-2.095],[0,-5.793],[6.529,0],[0,0],[0,2.16],[-1.604,0],[0,0],[-0.589,-1.489],[-2.161,0],[0,1.62],[0.54,0.909],[0,0],[0,0]],"v":[[-10.702,5.728],[-11.454,1.506],[0.001,-9],[11.454,1.506],[11.454,1.817],[7.544,5.728],[3.926,3.273],[2.618,0],[-0.997,-2.454],[-4.91,1.457],[-3.657,6.014],[-1.57,8.412],[-0.818,9]],"c":false}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0.233},"t":6.428,"s":[{"i":[[0,0],[0,0],[-1.576,0],[0,-1.474],[0,0],[1.541,0.347],[0.142,0.379],[0,0],[0.383,0],[0,-0.549],[-0.256,-0.431],[-0.768,0.207],[0,0]],"o":[[-1.823,0.497],[0,-1.474],[1.576,0],[0,0],[0,0.549],[-0.378,-0.085],[0,0],[-0.142,-0.379],[-0.521,0],[-0.002,0.353],[0.171,0.288],[0.622,-0.344],[0,0]],"v":[[-0.41,3.841],[-2.717,1.917],[0.047,-0.756],[2.811,1.917],[2.811,1.996],[0.225,3.848],[0.995,2.366],[0.679,1.534],[-0.193,0.909],[-1.338,1.879],[-1.026,3.169],[0.445,3.702],[1.036,3.015]],"c":false}]},{"t":12.857421875,"s":[{"i":[[0,0],[0,0],[-0.736,0],[0,-0.741],[0,0],[0.243,0],[0.066,0.191],[0,0],[0.179,0],[0,-0.276],[-0.162,-0.273],[-0.755,0.357],[0,0]],"o":[[-1.273,-0.008],[0,-0.741],[0.736,0],[0,0],[0,0.276],[-0.181,0],[0,0],[-0.066,-0.191],[-0.243,0],[-0.002,0.139],[0.109,0.182],[0.727,-0.402],[0,0]],"v":[[0.082,3.187],[-1.235,1.986],[0.055,0.642],[1.346,1.986],[1.346,2.026],[0.905,2.527],[0.498,2.212],[0.35,1.794],[-0.057,1.479],[-0.733,1.951],[-0.58,2.686],[0.619,3.071],[1.351,2]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.827450980392,0.890196078431,0.992156862745,1],"ix":3},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":8.4,"s":[100]},{"t":11.3984375,"s":[0]}],"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,28.341],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Inside to dot ","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.767},"o":{"x":0.541,"y":0},"t":0,"s":[{"i":[[0,0],[1.307,-0.561],[0.894,-0.16],[0.706,0],[0.844,0.193],[0.728,0.334],[0.967,0.901]],"o":[[-1.038,0.967],[-0.817,0.351],[-0.673,0.12],[-0.9,0],[-0.794,-0.182],[-1.203,-0.551],[0,0]],"v":[[8.182,-1.636],[4.642,0.681],[2.07,1.453],[-0.001,1.636],[-2.621,1.341],[-4.909,0.563],[-8.182,-1.636]],"c":false}]},{"i":{"x":0.331,"y":1},"o":{"x":0.167,"y":0.233},"t":6.428,"s":[{"i":[[0,0],[0.313,-0.134],[0.554,-0.317],[0.535,0],[0.203,0.046],[0.175,0.919],[0.232,0.216]],"o":[[-0.249,0.232],[-0.196,0.557],[-0.424,0.245],[-0.216,0],[-1.03,-0.044],[-0.288,-0.132],[0,0]],"v":[[11.468,-8.353],[10.62,-1.716],[9.232,-0.353],[7.057,0.034],[-7.634,-0.037],[-10.453,-1.739],[-11.238,-8.347]],"c":false}]},{"t":15,"s":[{"i":[[0,0],[0,0],[0.446,-0.367],[0.481,0],[0,0],[0,1.104],[0,0]],"o":[[0,0],[0,0.623],[-0.345,0.284],[0,0],[-1.104,0],[0,0],[0,0]],"v":[[11.302,-10.469],[11.302,-2.469],[10.57,-0.923],[9.302,-0.469],[-9.198,-0.469],[-11.198,-2.469],[-11.198,-10.469]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.827450980392,0.890196078431,0.992156862745,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,40.614],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Bottom","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".grey700","cl":"grey700","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[40,40,0],"ix":2,"l":2},"a":{"a":0,"k":[40.25,40.25,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[22.12,0],[0,-22.08],[-22.08,0],[0,22.08]],"o":[[-22.08,0],[0,22.08],[22.12,0],[0,-22.08]],"v":[[-0.04,-40],[-40,0],[-0.04,40],[40,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.278431385756,0.278431385756,0.278431385756,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[40.25,40.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}],"markers":[{"tm":30,"cm":"1","dr":0},{"tm":51,"cm":"350ms\r","dr":0},{"tm":69,"cm":"650ms\r","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index a58c901..45a3738 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Laai tans stadig • Vol oor <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Laaidok • Vol oor <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Wissel gebruiker"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle programme en data in hierdie sessie sal uitgevee word."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Welkom terug, gas!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Wiil jy jou sessie voortsit?"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 6324c1b..af6357b 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • በዝግታ ኃይልን በመሙላት ላይ • በ<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ውስጥ ይሞላል"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • የባትሪ ኃይል መሙያ መትከያ • በ<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ውስጥ ይሞላል"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ተጠቃሚ ቀይር"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"በዚህ ክፍለ-ጊዜ ውስጥ ያሉ ሁሉም መተግበሪያዎች እና ውሂብ ይሰረዛሉ።"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"እንኳን በደህና ተመለሱ እንግዳ!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"ክፍለ-ጊዜዎን መቀጠል ይፈልጋሉ?"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 92feccb..1cd0d89 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • جارٍ الشحن ببطء • ستمتلئ البطارية خلال <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • جارٍ الشحن على وحدة الإرساء • ستمتلئ البطارية خلال <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"تبديل المستخدم"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"سيتم حذف كل التطبيقات والبيانات في هذه الجلسة."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"مرحبًا بك مجددًا في جلسة الضيف"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"هل تريد متابعة جلستك؟"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 784a7d9..1185752 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • লাহে লাহে চাৰ্জ হৈ আছে • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>ত সম্পূৰ্ণ হ’ব"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • চাৰ্জিং ডক • সম্পূৰ্ণ হ’বলৈ <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> লাগিব"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ব্যৱহাৰকাৰী সলনি কৰক"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"এই ছেশ্বনৰ আটাইবোৰ এপ্ আৰু ডেটা মচা হ\'ব।"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"অতিথি, আপোনাক পুনৰ স্বাগতম!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"আপুনি আপোনাৰ ছেশ্বন অব্যাহত ৰাখিব বিচাৰেনে?"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index bbf3c89..6dfb616 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Asta şarj edilir • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> sonra dolacaq"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Şarj Doku • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> sonra dolacaq"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bu sessiyada bütün tətbiqlər və data silinəcək."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Xoş gəlmisiniz!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Sessiya davam etsin?"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 100c7e4..f26cb36 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Sporo se puni • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> do kraja punjenja"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Bazna stanica za punjenje • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> do kraja punjenja"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Zameni korisnika"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Sve aplikacije i podaci u ovoj sesiji će biti izbrisani."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Dobro došli nazad, goste!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite li da nastavite sesiju?"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index a7905ff..4257e3f 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ідзе павольная зарадка • Поўны зарад праз <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ідзе зарадка праз док-станцыю • Поўнасцю зарадзіцца праз <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Перайсці да іншага карыстальніка"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Усе праграмы і даныя гэтага сеанса будуць выдалены."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"З вяртаннем, госць!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Хочаце працягнуць сеанс?"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index b13b17db..e2f83f6 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Зарежда се бавно • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> до пълно зареждане"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Докинг станция за зареждане • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> до пълно зареждане"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Превключване между потребителите"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Всички приложения и данни в тази сесия ще бъдат изтрити."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Добре дошли отново в сесията като гост!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Искате ли да продължите сесията си?"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index bad5c2a..277eeb7 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ধীরে চার্জ হচ্ছে • পুরো চার্জ হতে <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> লাগবে"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • চার্জিং ডক • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>-এর মধ্যে সম্পূর্ণ হয়ে যাবে"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ব্যবহারকারী পাল্টে দিন"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"এই সেশনের সব অ্যাপ ও ডেটা মুছে ফেলা হবে।"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"অতিথি, আপনি ফিরে আসায় আপনাকে স্বাগত!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"আপনি কি আপনার সেশনটি চালিয়ে যেতে চান?"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index d00ebc5..0fe6121 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -339,6 +339,7 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Sporo punjenje • Potpuna napunjenost za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Priključna stanica za punjenje • Potpuna napunjenost za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Zamijeni korisnika"</string>
+    <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"padajući izbornik"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Sve aplikacije i podaci iz ove sesije će se izbrisati."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Zdravo! Lijepo je opet vidjeti goste."</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite li nastaviti sesiju?"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 553c6c7..15127b8 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carregant lentament • Es completarà d\'aquí a <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Base de càrrega • Es completarà d\'aquí a <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Canvia d\'usuari"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Totes les aplicacions i les dades d\'aquesta sessió se suprimiran."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Benvingut de nou, convidat."</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vols continuar amb la sessió?"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index c02c843..4da7e6f 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Pomalé nabíjení • Plně nabito za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Nabíjecí dok • Plně nabito za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Přepnout uživatele"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Veškeré aplikace a data v této relaci budou vymazána."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Vítejte zpět v relaci hosta!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Chcete v relaci pokračovat?"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 86e7d22..59732ef 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Oplader langsomt • Fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Oplader i dockingstation • Fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Skift bruger"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle apps og data i denne session slettes."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Velkommen tilbage, gæst!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vil du fortsætte din session?"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index c828536..bbac4f0 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Wird langsam geladen • Voll in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ladestation • Voll in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Nutzer wechseln"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle Apps und Daten in dieser Sitzung werden gelöscht."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Willkommen zurück im Gastmodus"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Möchtest du deine Sitzung fortsetzen?"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 4670fc7..ed44366 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Αργή φόρτιση • Πλήρης φόρτιση σε <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Βάση φόρτισης • Πλήρης φόρτιση σε <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Εναλλαγή χρήστη"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Όλες οι εφαρμογές και τα δεδομένα αυτής της περιόδου σύνδεσης θα διαγραφούν."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Kαλώς ορίσατε ξανά!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Θέλετε να συνεχίσετε την περίοδο σύνδεσής σας;"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 2139344..c8ccb36 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -339,6 +339,7 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Charging slowly • Full in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Charging dock • Full in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string>
+    <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"pulldown menu"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"All apps and data in this session will be deleted."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Welcome back, guest!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Do you want to continue your session?"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 84f337b..186679e 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -339,6 +339,7 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Charging slowly • Full in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Charging dock • Full in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string>
+    <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"pulldown menu"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"All apps and data in this session will be deleted."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Welcome back, guest!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Do you want to continue your session?"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 2139344..c8ccb36 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -339,6 +339,7 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Charging slowly • Full in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Charging dock • Full in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string>
+    <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"pulldown menu"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"All apps and data in this session will be deleted."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Welcome back, guest!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Do you want to continue your session?"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 2139344..c8ccb36 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -339,6 +339,7 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Charging slowly • Full in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Charging dock • Full in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string>
+    <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"pulldown menu"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"All apps and data in this session will be deleted."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Welcome back, guest!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Do you want to continue your session?"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index c8d0442..754a7f6 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -339,6 +339,7 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‎‎‎‏‏‎‎‎‎‏‎‏‏‎‎‏‎‎‎‎‎‏‏‏‎‎‏‎‏‏‎‎‏‎‏‎‏‎‎‏‎‏‏‎‎‎‎‏‎‎‏‎‎‏‎‎‏‎‎‏‎‎‏‏‎<xliff:g id="PERCENTAGE">%2$s</xliff:g>‎‏‎‎‏‏‏‎ • Charging slowly • Full in ‎‏‎‎‏‏‎<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‎‏‏‎‏‎‏‎‏‎‎‎‎‎‎‎‎‏‏‏‎‏‏‏‏‎‎‏‏‏‏‎‎‏‎‎‎‏‎‎‏‎‎‎‏‎‏‏‎‎‎‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="PERCENTAGE">%2$s</xliff:g>‎‏‎‎‏‏‏‎ • Charging Dock • Full in ‎‏‎‎‏‏‎<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‏‏‏‎‎‏‏‎‎‎‏‏‏‎‏‎‎‎‎‏‏‎‎‏‎‎‎‎‎‏‏‏‎‏‎‏‏‏‎‏‏‏‎‎‎‎‏‎‏‏‎‏‎‎‎Switch user‎‏‎‎‏‎"</string>
+    <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‏‎‏‏‎‏‎‎‏‏‎‎‎‎‎‎‎‏‏‏‏‎‎‏‎‏‎‎‏‏‎‎‎‎‏‏‏‏‏‏‏‎pulldown menu‎‏‎‎‏‎"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‎‎‎‏‎‏‏‏‎‏‎‏‎‏‎‏‎‎‎‎‎‏‎‎‏‎‏‏‎‎‏‏‎‏‎‎‏‏‏‎‏‏‏‏‎‏‎‏‏‏‎‏‎All apps and data in this session will be deleted.‎‏‎‎‏‎"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‏‎‎‏‎‏‎‏‎‏‏‎‏‎‎‎‎‏‎‎‏‎‏‏‏‎‎‏‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‎‎‎‎Welcome back, guest!‎‏‎‎‏‎"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‏‎‎‎‏‏‎‎‏‎‏‎‎‏‎‎‎‏‎‎‏‎‏‏‏‏‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‎‎‎‏‎‏‏‏‏‏‎‎‎‏‎Do you want to continue your session?‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 35f92f9..8a1f4ad 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Cargando lento • Se completará en <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Conectado y cargando • Carga completa en <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambiar usuario"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Se eliminarán las aplicaciones y los datos de esta sesión."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"¡Hola de nuevo, invitado!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"¿Quieres retomar la sesión?"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index b32859a..997cba7 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carga lenta • En <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> terminará de cargarse"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Base de carga • En <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> terminará de cargar"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambiar de usuario"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Se eliminarán todas las aplicaciones y datos de esta sesión."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"¡Hola de nuevo, invitado!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"¿Quieres continuar con tu sesión?"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index e2cc7e3..3210181 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Aeglane laadimine • Täis <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> pärast"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Laadimisdokk • Täis <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> pärast"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Kasutaja vahetamine"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Seansi kõik rakendused ja andmed kustutatakse."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Tere tulemast tagasi, külaline!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Kas soovite seansiga jätkata?"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 46751b3..3a8f9af 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -20,14 +20,14 @@
 <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="4811759950673118541">"Sistemaren interfazea"</string>
-    <string name="battery_low_title" msgid="5319680173344341779">"Bateria-aurrezlea aktibatu nahi duzu?"</string>
-    <string name="battery_low_description" msgid="3282977755476423966">"Bateriaren <xliff:g id="PERCENTAGE">%s</xliff:g> gelditzen zaizu. Bateria-aurrezleak gai iluna aktibatzen du, atzeko planoko jarduerak murrizten, eta jakinarazpenak atzeratzen."</string>
-    <string name="battery_low_intro" msgid="5148725009653088790">"Bateria-aurrezleak gai iluna aktibatzen du, atzeko planoko jarduerak murrizten, eta jakinarazpenak atzeratzen."</string>
+    <string name="battery_low_title" msgid="5319680173344341779">"Bateria-aurreztailea aktibatu nahi duzu?"</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Bateriaren <xliff:g id="PERCENTAGE">%s</xliff:g> gelditzen zaizu. Bateria-aurreztaileak gai iluna aktibatzen du, atzeko planoko jarduerak murrizten, eta jakinarazpenak atzeratzen."</string>
+    <string name="battery_low_intro" msgid="5148725009653088790">"Bateria-aurreztaileak gai iluna aktibatzen du, atzeko planoko jarduerak murrizten, eta jakinarazpenak atzeratzen."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> gelditzen da"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Ezin da USB bidez kargatu"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Erabili gailuaren kargagailua"</string>
-    <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Bateria-aurrezlea aktibatu nahi duzu?"</string>
-    <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Bateria-aurrezleari buruz"</string>
+    <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Bateria-aurreztailea aktibatu nahi duzu?"</string>
+    <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Bateria-aurreztaileari buruz"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Aktibatu"</string>
     <string name="battery_saver_start_action" msgid="8353766979886287140">"Aktibatu"</string>
     <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Ez, eskerrik asko"</string>
@@ -249,7 +249,7 @@
     <string name="quick_settings_connecting" msgid="2381969772953268809">"Konektatzen…"</string>
     <string name="quick_settings_hotspot_label" msgid="1199196300038363424">"Wifi-gunea"</string>
     <string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"Aktibatzen…"</string>
-    <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Datu-aurrezlea aktibatuta"</string>
+    <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Datu-aurreztailea aktibatuta"</string>
     <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# gailu}other{# gailu}}"</string>
     <string name="quick_settings_flashlight_label" msgid="4904634272006284185">"Linterna"</string>
     <string name="quick_settings_flashlight_camera_in_use" msgid="4820591564526512571">"Kamera abian da"</string>
@@ -267,7 +267,7 @@
     <string name="quick_settings_night_secondary_label_on_at" msgid="3584738542293528235">"Aktibatze-ordua: <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_secondary_label_until" msgid="1883981263191927372">"<xliff:g id="TIME">%s</xliff:g> arte"</string>
     <string name="quick_settings_ui_mode_night_label" msgid="1398928270610780470">"Gai iluna"</string>
-    <string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"Bateria-aurrezlea"</string>
+    <string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"Bateria-aurreztailea"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at_sunset" msgid="6017379738102015710">"Ilunabarrean aktibatuko da"</string>
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Egunsentira arte"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Aktibatze-ordua: <xliff:g id="TIME">%s</xliff:g>"</string>
@@ -339,6 +339,7 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Mantso kargatzen • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> guztiz kargatu arte"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Oinarrian kargatzen • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> guztiz kargatu arte"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Aldatu erabiltzailea"</string>
+    <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"zabaldu menua"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Saioko aplikazio eta datu guztiak ezabatuko dira."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Ongi etorri berriro, gonbidatu hori!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Saioarekin jarraitu nahi duzu?"</string>
@@ -536,7 +537,7 @@
     <string name="snoozed_for_time" msgid="7586689374860469469">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g>z atzeratu da"</string>
     <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# ordu}=2{# ordu}other{# ordu}}"</string>
     <string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{# minutu}other{# minutu}}"</string>
-    <string name="battery_detail_switch_title" msgid="6940976502957380405">"Bateria-aurrezlea"</string>
+    <string name="battery_detail_switch_title" msgid="6940976502957380405">"Bateria-aurreztailea"</string>
     <string name="keyboard_key_button_template" msgid="8005673627272051429">"<xliff:g id="NAME">%1$s</xliff:g> botoia"</string>
     <string name="keyboard_key_home" msgid="3734400625170020657">"Hasiera"</string>
     <string name="keyboard_key_back" msgid="4185420465469481999">"Atzera"</string>
@@ -586,8 +587,8 @@
     <string name="accessibility_long_click_tile" msgid="210472753156768705">"Ireki ezarpenak"</string>
     <string name="accessibility_status_bar_headphones" msgid="1304082414912647414">"Entzungailuak konektatu dira"</string>
     <string name="accessibility_status_bar_headset" msgid="2699275863720926104">"Mikrofonodun entzungailua konektatu da"</string>
-    <string name="data_saver" msgid="3484013368530820763">"Datu-aurrezlea"</string>
-    <string name="accessibility_data_saver_on" msgid="5394743820189757731">"Aktibatuta dago datu-aurrezlea"</string>
+    <string name="data_saver" msgid="3484013368530820763">"Datu-aurreztailea"</string>
+    <string name="accessibility_data_saver_on" msgid="5394743820189757731">"Aktibatuta dago datu-aurreztailea"</string>
     <string name="switch_bar_on" msgid="1770868129120096114">"Aktibatuta"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Desaktibatuta"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Ez dago erabilgarri"</string>
@@ -715,8 +716,8 @@
     <string name="slice_permission_checkbox" msgid="4242888137592298523">"Eman aplikazio guztien zatiak erakusteko baimena <xliff:g id="APP">%1$s</xliff:g> aplikazioari"</string>
     <string name="slice_permission_allow" msgid="6340449521277951123">"Eman baimena"</string>
     <string name="slice_permission_deny" msgid="6870256451658176895">"Ukatu"</string>
-    <string name="auto_saver_title" msgid="6873691178754086596">"Sakatu bateria-aurrezlea noiz aktibatu programatzeko"</string>
-    <string name="auto_saver_text" msgid="3214960308353838764">"Aktibatu aurrezlea bateria agortzeko arriskua dagoenean"</string>
+    <string name="auto_saver_title" msgid="6873691178754086596">"Sakatu bateria-aurreztailea noiz aktibatu programatzeko"</string>
+    <string name="auto_saver_text" msgid="3214960308353838764">"Aktibatu aurreztailea bateria agortzeko arriskua dagoenean"</string>
     <string name="no_auto_saver_action" msgid="7467924389609773835">"Ez, eskerrik asko"</string>
     <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
     <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"Erabiltzen ari da"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index e2cbb45..33a1b87 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • درحال شارژ کردن آهسته • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> تا شارژ کامل"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • پایه شارژ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> تا شارژ کامل"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"تغییر کاربر"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"همه برنامه‌ها و داده‌های این جلسه حذف خواهد شد."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"مهمان گرامی، بازگشتتان را خوش آمد می‌گوییم!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"آیا می‌خواهید جلسه‌تان را ادامه دهید؟"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index de8a1eb..9b9082d 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Latautuu hitaasti • Täynnä <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> päästä"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ladataan telineellä • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> kunnes täynnä"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Vaihda käyttäjää"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Kaikki sovellukset ja tämän istunnon tiedot poistetaan."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Tervetuloa takaisin!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Haluatko jatkaa istuntoa?"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 9e11b10..47e961b 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"En recharge lente : <xliff:g id="PERCENTAGE">%2$s</xliff:g> • Terminée <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Station de recharge • Recharge terminée dans <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Changer d\'utilisateur"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toutes les applications et les données de cette session seront supprimées."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Bienvenue à nouveau dans la session Invité"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Voulez-vous poursuivre la session?"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index f6bf4c0..46897b0 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -339,6 +339,8 @@
     <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="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Station de charge • Chargé dans <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Changer d\'utilisateur"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toutes les applications et les données de cette session seront supprimées."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Heureux de vous revoir, Invité"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Voulez-vous poursuivre la dernière session ?"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index ee94bc8..4c070ff 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Cargando lentamente • A carga completarase en <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Base de carga • Carga completa dentro de <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambiar usuario"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Eliminaranse todas as aplicacións e datos desta sesión."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Benvido de novo, convidado"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Queres continuar coa túa sesión?"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index b5a629a..ae642a7 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ધીમેથી ચાર્જ થઈ રહ્યું છે • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>માં ચાર્જ થઈ જશે"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ડૉકથી ચાર્જ થઈ રહ્યું છે • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>માં સંપૂર્ણ ચાર્જ થઈ જશે"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"વપરાશકર્તા સ્વિચ કરો"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"આ સત્રમાંની તમામ ઍપ અને ડેટા કાઢી નાખવામાં આવશે."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"ફરી સ્વાગત છે, અતિથિ!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"શું તમે તમારું સત્ર ચાલુ રાખવા માંગો છો?"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 0fc9d3d..08e3b80 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • धीरे चार्ज हो रहा है • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> में पूरा चार्ज हो जाएगा"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • डॉक पर चार्ज हो रहा है • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> में पूरा चार्ज हो जाएगा"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"उपयोगकर्ता बदलें"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"इस सेशन के सभी ऐप्लिकेशन और डेटा को हटा दिया जाएगा."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"मेहमान, आपका फिर से स्वागत है!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"क्‍या आपको अपना सेशन जारी रखना है?"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 56d40c7..c3f1b96 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -339,6 +339,7 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • sporo punjenje • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> do napunjenosti"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Priključna stanica za punjenje • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> do napunjenosti"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Promjena korisnika"</string>
+    <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"padajući izbornik"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Izbrisat će se sve aplikacije i podaci u ovoj sesiji."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Dobro došli natrag, gostu!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite li nastaviti sesiju?"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 131f789..4e40dc5 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Lassú töltés • A teljes töltöttségig: <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Töltődokk • A teljes töltöttségig: <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Felhasználóváltás"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"A munkamenetben található összes alkalmazás és adat törlődni fog."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Örülünk, hogy visszatért, vendég!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Folytatja a munkamenetet?"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index aa52ee5..4f080eb 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Դանդաղ լիցքավորում • Մնացել է <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Լիցքավորում դոկ-կայանի միջոցով • Մնացել է <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Անջատել օգտվողին"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Այս աշխատաշրջանի բոլոր հավելվածներն ու տվյալները կջնջվեն:"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Բարի վերադարձ, հյուր"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Շարունակե՞լ աշխատաշրջանը։"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 085f174..726c366 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Mengisi daya dengan lambat • Penuh dalam waktu <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Mengisi Daya dengan Dok • Penuh dalam waktu <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Beralih pengguna"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Semua aplikasi dan data dalam sesi ini akan dihapus."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Selamat datang kembali, tamu!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Lanjutkan sesi Anda?"</string>
@@ -467,7 +469,7 @@
     <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Ketuk untuk membuka"</string>
     <string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Memperbarui"</string>
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Buka kunci untuk menggunakan"</string>
-    <string name="wallet_error_generic" msgid="257704570182963611">"Terjadi masalah saat mendapatkan kartu Anda, coba lagi nanti"</string>
+    <string name="wallet_error_generic" msgid="257704570182963611">"Terjadi error saat mendapatkan kartu Anda, coba lagi nanti"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Setelan layar kunci"</string>
     <string name="qr_code_scanner_title" msgid="5290201053875420785">"Pindai kode QR"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Profil kerja"</string>
@@ -886,7 +888,7 @@
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> mengirim gambar"</string>
     <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> memposting pembaruan status: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
     <string name="person_available" msgid="2318599327472755472">"Online"</string>
-    <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Terjadi masalah saat membaca indikator baterai"</string>
+    <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Terjadi error saat membaca indikator baterai"</string>
     <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Ketuk untuk informasi selengkapnya"</string>
     <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Alarm tidak disetel"</string>
     <string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Sensor sidik jari"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 6a78cf0..7a90de3 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Hæg hleðsla • Full hleðsla eftir <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Hleður í dokku • Full hleðsla eftir <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Skipta um notanda"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Öllum forritum og gögnum í þessari lotu verður eytt."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Velkominn aftur, gestur!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Viltu halda áfram með lotuna?"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index b594104..2b2b32a 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ricarica lenta • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> alla ricarica completa"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • In carica nel dock • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> alla ricarica completa"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambio utente"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tutte le app e i dati di questa sessione verranno eliminati."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Ti ridiamo il benvenuto nella sessione Ospite."</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vuoi continuare la sessione?"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index cc9902f..4b39928 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • בטעינה איטית • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> עד לסיום"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • אביזר העגינה בטעינה • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> עד לסיום"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"החלפת משתמש"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"כל האפליקציות והנתונים בסשן הזה יימחקו."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"שמחים לראותך שוב!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"האם ברצונך להמשיך בפעילות באתר?"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 0fd8d58..a7fdf40 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 低速充電中 • 完了まで <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ホルダーで充電中 • 完了まで <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ユーザーを切り替える"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"このセッションでのアプリとデータはすべて削除されます。"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"おかえりなさい、ゲストさん"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"セッションを続行しますか?"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 7756071..7c4df7b 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ნელა იტენება • სრულ დატენვამდე <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • დამტენი სამაგრი • დატენამდე დარჩა <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"მომხმარებლის გადართვა"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ამ სესიის ყველა აპი და მონაცემი წაიშლება."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"სტუმარო, გვიხარია, რომ დაბრუნდით!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"გსურთ, თქვენი სესიის გაგრძელება?"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 6e55cf2..06cb83c 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Баяу зарядталуда • Толуына <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> қалды."</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Қондыру станциясында зарядталуда • Толуына <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> қалды."</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Пайдаланушыны ауыстыру"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Осы сеанстағы барлық қолданбалар мен деректер жойылады."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Қош келдіңіз, қонақ!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Сеансты жалғастыру керек пе?"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 509d552..338d05d 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • កំពុង​សាកថ្ម​យឺត • ពេញក្នុងរយៈពេល <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ឧបករណ៍ភ្ជាប់សាកថ្ម • ពេញក្នុងរយៈពេល <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ទៀត"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ប្ដូរ​អ្នក​ប្រើ"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"កម្មវិធី និងទិន្នន័យ​ទាំងអស់​ក្នុង​វគ្គ​នេះ​នឹង​ត្រូវ​លុប។"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"សូម​ស្វាគមន៍​ការ​ត្រឡប់​មកវិញ, ភ្ញៀវ!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"តើ​អ្នក​ចង់​បន្ត​វគ្គ​របស់​អ្នក​ទេ?"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 3b660f7..fd3b703 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ನಿಧಾನವಾಗಿ ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ಸಮಯದಲ್ಲಿ ಪೂರ್ಣಗೊಳ್ಳುತ್ತದೆ"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ಡಾಕ್ ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ದಲ್ಲಿ ಚಾರ್ಜ್ ಪೂರ್ಣಗೊಳ್ಳುತ್ತದೆ"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ಬಳಕೆದಾರರನ್ನು ಬದಲಿಸಿ"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ಈ ಸೆಷನ್‌ನಲ್ಲಿನ ಎಲ್ಲ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"ಮತ್ತೆ ಸುಸ್ವಾಗತ, ಅತಿಥಿ!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"ನಿಮ್ಮ ಸೆಷನ್‌ ಮುಂದುವರಿಸಲು ಇಚ್ಚಿಸುವಿರಾ?"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 301cc06..4cedd5f 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 저속 충전 중 • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> 후 충전 완료"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 충전 거치대 • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> 후 충전 완료"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"사용자 전환"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"이 세션에 있는 모든 앱과 데이터가 삭제됩니다."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"게스트 세션 진행"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"세션을 계속 진행하시겠습니까?"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index b94e396..7266a7b 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Жай кубатталууда • Толгонго чейин <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> калды"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Кубаттоо догу • Толгонго чейин <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> калды"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Колдонуучуну которуу"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Бул сеанстагы бардык колдонмолор жана аларга байланыштуу нерселер өчүрүлөт."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Кайтып келишиңиз менен!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Сеансыңызды улантасызбы?"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index a8d4ffa..6685ae7 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ກຳລັງສາກໄຟແບບຊ້າ • ຈະເຕັມໃນອີກ <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ກຳລັງສາກໄຟຜ່ານດັອກ • ຈະເຕັມໃນອີກ <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ສະຫຼັບຜູ້ໃຊ້"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ແອັບຯ​ແລະ​ຂໍ້​ມູນ​ທັງ​ໝົດ​ໃນ​ເຊດ​ຊັນ​ນີ້​ຈະ​ຖືກ​ລຶບ​ອອກ."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"ຍິນ​ດີ​ຕ້ອນ​ຮັບ​ກັບ​ມາ, ຜູ້ຢ້ຽມຢາມ!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"ທ່ານ​ຕ້ອງ​ການ​ສືບ​ຕໍ່​ເຊດ​ຊັນ​ຂອງ​ທ່ານບໍ່?"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index dd2162d..751e485 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Lėtai įkraunama • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> iki visiško įkrovimo"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Įkraunama doke • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> iki visiško įkrovimo"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Perjungti naudotoją"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bus ištrintos visos šios sesijos programos ir duomenys."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Sveiki sugrįžę, svety!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Ar norite tęsti sesiją?"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 8b2759c..8a19ef1 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Lēnā uzlāde • Laiks līdz pilnai uzlādei: <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Notiek uzlāde dokā • Līdz pilnai uzlādei atlicis: <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Mainīt lietotāju"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tiks dzēstas visas šīs sesijas lietotnes un dati."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Laipni lūdzam atpakaļ, viesi!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vai vēlaties turpināt savu sesiju?"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 56c98a8..6f3076f 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Се полни бавно • Полна по <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Се полни на док • Полн за <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Промени го корисникот"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Сите апликации и податоци во сесијата ќе се избришат."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Добре дојде пак, гостине!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Дали сакате да продолжите со сесијата?"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 6d5109b..623fcbd 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • പതുക്കെ ചാർജ് ചെയ്യുന്നു • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>-ൽ പൂർത്തിയാകും"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ചാർജിംഗ് ഡോക്ക് • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>-ൽ പൂർത്തിയാകും"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ഉപയോക്താവ് മാറുക"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ഈ സെഷനിലെ എല്ലാ ആപ്പുകളും ഡാറ്റയും ഇല്ലാതാക്കും."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"അതിഥി, വീണ്ടും സ്വാഗതം!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"നിങ്ങളുടെ സെഷൻ തുടരണോ?"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 126326a..c340037 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Удаан цэнэглэж байна • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>-н дараа дүүрнэ"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Цэнэглэх холбогч • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>-н дараа дүүрнэ"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Хэрэглэгчийг сэлгэх"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Энэ харилцан үйлдлийн бүх апп болон дата устах болно."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Эргэн тавтай морилно уу!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Та үргэлжлүүлэхийг хүсэж байна уу?"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 2ff02b3..d2f35452 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • हळू चार्ज होत आहे • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> मध्ये पूर्ण होईल"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • चार्जिंग डॉक • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> मध्ये पूर्ण होईल"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"वापरकर्ता स्विच करा"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"या सत्रातील सर्व अ‍ॅप्स आणि डेटा हटवला जाईल."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"अतिथी, तुमचे पुन्‍हा स्‍वागत आहे!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"तुम्ही तुमचे सत्र सुरू ठेवू इच्छिता?"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index b9ee5c0..d569385 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Mengecas dengan perlahan • Penuh dalam masa <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Mengecas dengan Dok • Penuh dalam masa <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Tukar pengguna"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Semua apl dan data dalam sesi ini akan dipadam."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Selamat kembali, tetamu!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Adakah anda ingin meneruskan sesi anda?"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index ff436b8..24dc589 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • နှေးကွေးစွာ အားသွင်းနေသည် • အားပြည့်ရန် <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> လိုသည်"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • အားသွင်းအထိုင် • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> တွင် ပြည့်မည်"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"အသုံးပြုသူကို ပြောင်းလဲရန်"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ဒီချိတ်ဆက်မှု ထဲက အက်ပ်များ အားလုံး နှင့် ဒေတာကို ဖျက်ပစ်မည်။"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"ဧည့်သည်ကို ပြန်လည် ကြိုဆိုပါသည်။"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"သင်၏ စက်ရှင်ကို ဆက်လုပ်လိုပါသလား။"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 2517b8e..090d64b 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Lader sakte • Fulladet om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ladedokk • Fulladet om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Bytt bruker"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle apper og data i denne økten blir slettet."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Velkommen tilbake, gjest!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vil du fortsette økten?"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index a4946b8..415137c 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • बिस्तारै चार्ज हुँदै छ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> मा पूरै चार्ज हुन्छ"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • डक चार्ज हुँदै छ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> मा पूरै चार्ज हुन्छ"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"प्रयोगकर्ता फेर्नुहोस्"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"यो सत्रमा भएका सबै एपहरू र डेटा मेटाइने छ।"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"तपाईंलाई फेरि स्वागत छ, अतिथि"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"तपाईं आफ्नो सत्र जारी गर्न चाहनुहुन्छ?"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 3223012..d631990 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Langzaam opladen • Vol over <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Oplaaddock • Vol over <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Gebruiker wijzigen"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle apps en gegevens in deze sessie worden verwijderd."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Welkom terug, gast!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Wil je doorgaan met je sessie?"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index c8f238f..81c4580 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ଧୀରେ ଚାର୍ଜ ହେଉଛି • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>ରେ ସମ୍ପୂର୍ଣ୍ଣ ହେବ"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ଡକରୁ ଚାର୍ଜ ହେଉଛି • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>ରେ ସମ୍ପୂର୍ଣ୍ଣ ହେବ"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ୟୁଜର୍‍ ବଦଳାନ୍ତୁ"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ଏହି ସେସନର ସମସ୍ତ ଆପ୍‌ ଓ ଡାଟା ଡିଲିଟ୍‌ ହୋଇଯିବ।"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"ପୁଣି ସ୍ୱାଗତ, ଅତିଥି!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"ଆପଣ ନିଜର ସେସନ୍ ଜାରି ରଖିବାକୁ ଚାହାଁନ୍ତି କି?"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 9e9e0f1..a4b9262 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ਹੌਲੀ ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ਵਿੱਚ ਪੂਰਾ ਚਾਰਜ ਹੋਵੇਗਾ"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ਡੌਕ ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ਵਿੱਚ ਪੂਰਾ ਚਾਰਜ ਹੋਵੇਗਾ"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ਵਰਤੋਂਕਾਰ ਸਵਿੱਚ ਕਰੋ"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ਇਸ ਸੈਸ਼ਨ ਵਿਚਲੀਆਂ ਸਾਰੀਆਂ ਐਪਾਂ ਅਤੇ ਡਾਟਾ ਨੂੰ ਮਿਟਾ ਦਿੱਤਾ ਜਾਏਗਾ।"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"ਮਹਿਮਾਨ, ਫਿਰ ਤੁਹਾਡਾ ਸੁਆਗਤ ਹੈ!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"ਕੀ ਤੁਸੀਂ ਆਪਣਾ ਸੈਸ਼ਨ ਜਾਰੀ ਰੱਖਣਾ ਚਾਹੁੰਦੇ ਹੋ?"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index d538c3e..2265018 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Wolne ładowanie • Pełne naładowanie za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ładowanie na stacji dokującej • Pełne naładowanie za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Przełącz użytkownika"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Wszystkie aplikacje i dane w tej sesji zostaną usunięte."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Witaj ponownie, Gościu!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Chcesz kontynuować sesję?"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 4435e2b..395b1f7 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carga lenta • Conclusão em <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carregando na base • Carga completa em <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Trocar usuário"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todos os apps e dados nesta sessão serão excluídos."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Você voltou, visitante!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Quer continuar a sessão?"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 34a84ab..a8ace85 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • A carregar lentamente • Carga completa em <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • A carregar na estação de ancoragem • Carga completa em <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Mudar utilizador"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todas as apps e dados desta sessão serão eliminados."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Bem-vindo de volta, convidado!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Pretende continuar a sessão?"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 4435e2b..395b1f7 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carga lenta • Conclusão em <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carregando na base • Carga completa em <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Trocar usuário"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todos os apps e dados nesta sessão serão excluídos."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Você voltou, visitante!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Quer continuar a sessão?"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index f9ba7c7..451ff5b 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Se încarcă lent • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> până la încărcarea completă"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Suport de încărcare • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> până la încărcarea completă"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Comutați între utilizatori"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toate aplicațiile și datele din această sesiune vor fi șterse."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Bine ați revenit în sesiunea pentru invitați!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vreți să continuați sesiunea?"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 89d7680..ecaf8d4 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Медленная зарядка • Осталось <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Зарядка от док-станции • Ещё <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Сменить пользователя."</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Все приложения и данные этого профиля будут удалены."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Рады видеть вас снова!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Продолжить сеанс?"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 54df18c..9bc1000 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • සෙමින් ආරෝපණය වෙමින් • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>කින් සම්පූර්ණ වේ"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ආරෝපණ ඩොකය • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>කින් සම්පූර්ණ වේ"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"පරිශීලක මාරුව"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"මෙම සැසියේ සියළුම යෙදුම් සහ දත්ත මකාවී."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"නැවත සාදරයෙන් පිළිගනිමු, අමුත්තා!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"ඔබගේ සැසිය දිගටම කරගෙන යෑමට ඔබට අවශ්‍යද?"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index d1a3d39..7fdfcc8 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Nabíja sa pomaly • Do úplného nabitia zostáva <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Nabíjací dok • Do úplného nabitia zostáva <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Prepnutie používateľa"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Všetky aplikácie a údaje v tejto relácii budú odstránené."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Hosť, vitajte späť!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Chcete v relácii pokračovať?"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 1cf1380..8752f8e 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Počasno polnjenje • Napolnjeno čez <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Polnjenje na nosilcu • Polno čez <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Preklop med uporabniki"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Vse aplikacije in podatki v tej seji bodo izbrisani."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Znova pozdravljeni, gost!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite nadaljevati sejo?"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 71ba302..b1d07a4 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Po karikohet ngadalë • Plot për <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Po karikohet në stacion • Plot për <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Ndërro përdorues"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Të gjitha aplikacionet dhe të dhënat në këtë sesion do të fshihen."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Mirë se erdhe, i ftuar!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Dëshiron ta vazhdosh sesionin tënd?"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index a72f817..8b2e5a4 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Споро се пуни • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> до краја пуњења"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Базна станица за пуњење • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> до краја пуњења"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Замени корисника"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Све апликације и подаци у овој сесији ће бити избрисани."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Добро дошли назад, госте!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Желите ли да наставите сесију?"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 96114e0..7994324 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Laddas långsamt • Fulladdat om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Dockningsstation • Fulladdat om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Byt användare"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alla appar och data i denna session kommer att raderas."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Välkommen tillbaka som gäst!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vill du fortsätta sessionen?"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 88ab84c..0e6694d3 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Inachaji polepole • Itajaa baada ya <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Kituo cha Kuchaji • Itajaa baada ya <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Badili mtumiaji"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Data na programu zote katika kipindi hiki zitafutwa."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Karibu tena mgeni!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Je, unataka kuendelea na kipindi chako?"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 25dde54..085832f 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • மெதுவாக சார்ஜாகிறது • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> இல் முழுதும் சார்ஜாகும்"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • டாக் மூலம் சார்ஜாகிறது • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> இல் முழுமையாகச் சார்ஜாகிவிடும்"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"பயனரை மாற்று"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"இந்த அமர்வின் எல்லா ஆப்ஸும் தரவும் நீக்கப்படும்."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"நல்வரவு!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"உங்கள் அமர்வைத் தொடர விருப்பமா?"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 820abdd..96c09cb 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • నెమ్మదిగా ఛార్జ్ అవుతోంది • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>లో పూర్తి ఛార్జ్"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ఛార్జింగ్ డాక్ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>లో పూర్తిగా ఛార్జ్ అవుతుంది"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"వినియోగదారుని మార్చు"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ఈ సెషన్‌లోని అన్ని యాప్‌లు మరియు డేటా తొలగించబడతాయి."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"గెస్ట్‌కు తిరిగి స్వాగతం!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"మీరు మీ సెషన్‌ని కొనసాగించాలనుకుంటున్నారా?"</string>
@@ -736,17 +738,17 @@
     <string name="privacy_type_media_projection" msgid="8136723828804251547">"స్క్రీన్ రికార్డింగ్"</string>
     <string name="music_controls_no_title" msgid="4166497066552290938">"శీర్షిక లేదు"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"స్టాండ్‌బై"</string>
-    <string name="magnification_window_title" msgid="4863914360847258333">"మాగ్నిఫికేషన్ విండో"</string>
-    <string name="magnification_controls_title" msgid="8421106606708891519">"మాగ్నిఫికేషన్ నియంత్రణల విండో"</string>
+    <string name="magnification_window_title" msgid="4863914360847258333">"మ్యాగ్నిఫికేషన్ విండో"</string>
+    <string name="magnification_controls_title" msgid="8421106606708891519">"మ్యాగ్నిఫికేషన్ నియంత్రణల విండో"</string>
     <string name="accessibility_control_zoom_in" msgid="1189272315480097417">"దగ్గరగా జూమ్ చేయండి"</string>
     <string name="accessibility_control_zoom_out" msgid="69578832020304084">"దూరంగా జూమ్ చేయండి"</string>
     <string name="accessibility_control_move_up" msgid="6622825494014720136">"పైకి పంపండి"</string>
     <string name="accessibility_control_move_down" msgid="5390922476900974512">"కిందకి పంపండి"</string>
     <string name="accessibility_control_move_left" msgid="8156206978511401995">"ఎడమవైపుగా జరపండి"</string>
     <string name="accessibility_control_move_right" msgid="8926821093629582888">"కుడివైపుగా జరపండి"</string>
-    <string name="magnification_mode_switch_description" msgid="2698364322069934733">"మాగ్నిఫికేషన్ స్విచ్"</string>
+    <string name="magnification_mode_switch_description" msgid="2698364322069934733">"మ్యాగ్నిఫికేషన్ స్విచ్"</string>
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ఫుల్ స్క్రీన్‌ను మ్యాగ్నిఫై చేయండి"</string>
-    <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"స్క్రీన్‌లో భాగాన్ని మాగ్నిఫై చేయండి"</string>
+    <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"స్క్రీన్‌లో భాగాన్ని మ్యాగ్నిఫై చేయండి"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"స్విచ్ చేయి"</string>
     <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"యాక్సెసిబిలిటీ ఫీచర్‌లను తెరవడానికి ట్యాప్ చేయండి. సెట్టింగ్‌లలో ఈ బటన్‌ను అనుకూలంగా మార్చండి లేదా రీప్లేస్ చేయండి.\n\n"<annotation id="link">"వీక్షణ సెట్టింగ్‌లు"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"తాత్కాలికంగా దానిని దాచడానికి బటన్‌ను చివరకు తరలించండి"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 9060b13..c00c09a 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • กำลังชาร์จอย่างช้าๆ • จะเต็มในอีก <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • กำลังชาร์จบนแท่นชาร์จ • จะเต็มในอีก <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"สลับผู้ใช้"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ระบบจะลบแอปและข้อมูลทั้งหมดในเซสชันนี้"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"ยินดีต้อนรับผู้ใช้ชั่วคราวกลับมาอีกครั้ง"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"คุณต้องการอยู่ในเซสชันต่อไปไหม"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 6da2358..9d1bc41 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -339,6 +339,7 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Mabagal na nagcha-charge • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> na lang para mapuno"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Charging Dock • Mapupuno sa loob ng <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Magpalit ng user"</string>
+    <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"pulldown menu"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Ide-delete ang lahat ng app at data sa session na ito."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Welcome ulit, bisita!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Gusto mo bang ipagpatuloy ang iyong session?"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index a1fcb69..a18c425 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Yavaş şarj oluyor • Dolmasına <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> kaldı"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Yuvada Şarj Oluyor • Dolmasına <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> kaldı"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Kullanıcı değiştirme"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bu oturumdaki tüm uygulamalar ve veriler silinecek."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Misafir kullanıcı, tekrar hoşgeldiniz"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Oturumunuza devam etmek istiyor musunuz?"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 970a14dd..c8e667b 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Повільне заряджання • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> до повного заряду"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Док-станція для заряджання • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> до повного заряду"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Змінити користувача"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Усі додатки й дані з цього сеансу буде видалено."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"З поверненням!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Продовжити сеанс?"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 2e7c3df..1a2c123 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • آہستہ چارج ہو رہا ہے • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> میں مکمل"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ڈاک چارج ہو رہا ہے • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> میں مکمل"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"صارف سوئچ کریں"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"اس سیشن میں موجود سبھی ایپس اور ڈیٹا کو حذف کر دیا جائے گا۔"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"مہمان، پھر سے خوش آمدید!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"کیا آپ اپنا سیشن جاری رکھنا چاہتے ہیں؟"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 8c1aff4..c84394a 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Sekin quvvat olmoqda • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> qoldi"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Dok-stansiya • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> qoldi"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Foydalanuvchini almashtirish"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Ushbu seansdagi barcha ilovalar va ma’lumotlar o‘chirib tashlanadi."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Xush kelibsiz, mehmon!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Seansni davom ettirmoqchimisiz?"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 6f1e8f2..ce82c96 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Đang sạc chậm • Sẽ đầy sau <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Đế sạc • Sạc đầy sau <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Chuyển đổi người dùng"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tất cả ứng dụng và dữ liệu trong phiên này sẽ bị xóa."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Chào mừng bạn trở lại!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Bạn có muốn tiếp tục phiên của mình không?"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index e36359c..bedd76b 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 正在慢速充电 • 将于 <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>后充满"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 正在基座上充电 • 将于 <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>后充满"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"切换用户"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"此会话中的所有应用和数据都将被删除。"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"访客,欢迎回来!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"要继续您的会话吗?"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 893bc27..7f4e659 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -129,8 +129,8 @@
     <string name="biometric_dialog_try_again" msgid="8575345628117768844">"請再試一次"</string>
     <string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"輕按即可取消驗證"</string>
     <string name="biometric_dialog_face_icon_description_idle" msgid="4351777022315116816">"請再試一次"</string>
-    <string name="biometric_dialog_face_icon_description_authenticating" msgid="3401633342366146535">"正在尋找您的臉孔"</string>
-    <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"臉孔已經驗證"</string>
+    <string name="biometric_dialog_face_icon_description_authenticating" msgid="3401633342366146535">"正在尋找您的面孔"</string>
+    <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"面孔已經驗證"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"已確認"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"輕按 [確定] 以完成"</string>
     <string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"已使用面孔解鎖。按解鎖圖示即可繼續。"</string>
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 慢速充電中 • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>後充滿電"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 正在插座上充電 • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>後充滿電"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"切換使用者"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"這個工作階段中的所有應用程式和資料都會被刪除。"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"訪客您好,歡迎回來!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"您要繼續您的工作階段嗎?"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 16aa647..ad90947 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 慢速充電中 • 將於 <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>後充飽"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 正在座架上充電 • 將於 <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>後充飽"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"切換使用者"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"這個工作階段中的所有應用程式和資料都會遭到刪除。"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"訪客你好,歡迎回來!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"你要繼續這個工作階段嗎?"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 8f9f579..bfa86f5 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -339,6 +339,8 @@
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ishaja kancane • Izogcwala ngo-<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ukushaja Idokhi • Izogcwala ngo-<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Shintsha umsebenzisi"</string>
+    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
+    <skip />
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Zonke izinhlelo zokusebenza nedatha kulesi sikhathi zizosuswa."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Siyakwamukela futhi, sivakashi!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Ingabe ufuna ukuqhubeka ngesikhathi sakho?"</string>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 3fb00a3..f344721 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -937,7 +937,8 @@
 
     <!-- Biometric Dialog values -->
     <dimen name="biometric_dialog_face_icon_size">64dp</dimen>
-    <dimen name="biometric_dialog_fingerprint_icon_size">80dp</dimen>
+    <dimen name="biometric_dialog_fingerprint_icon_width">80dp</dimen>
+    <dimen name="biometric_dialog_fingerprint_icon_height">80dp</dimen>
     <dimen name="biometric_dialog_button_negative_max_width">160dp</dimen>
     <dimen name="biometric_dialog_button_positive_max_width">136dp</dimen>
     <dimen name="biometric_dialog_corner_size">4dp</dimen>
@@ -1455,6 +1456,7 @@
     <dimen name="dream_overlay_camera_mic_off_indicator_size">8dp</dimen>
     <dimen name="dream_overlay_notification_indicator_size">6dp</dimen>
     <dimen name="dream_overlay_grey_chip_width">56dp</dimen>
+    <dimen name="dream_overlay_status_bar_extra_margin">16dp</dimen>
 
     <!-- Dream overlay complications related dimensions -->
     <dimen name="dream_overlay_complication_clock_time_text_size">100sp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 9c2542c..7f3caec 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -799,7 +799,7 @@
     <!-- Message shown when lock screen is tapped or face authentication fails. [CHAR LIMIT=60] -->
     <string name="keyguard_unlock">Swipe up to open</string>
 
-    <!-- Message shown when lock screen is unlocked (ie: by trust agent) and the user taps the empty space on the lock screen and UDFPS is supported. Provides extra instructions for how the user can enter their device [CHAR LIMIT=60] -->
+    <!-- Message shown when lock screen is unlocked (ie: by trust agent or face auth). Provides extra instructions for how the user can enter their device [CHAR LIMIT=60] -->
     <string name="keyguard_unlock_press">Press the unlock icon to open</string>
 
     <!-- Message shown when non-bypass face authentication succeeds. Provides extra instructions for how the user can enter their device [CHAR LIMIT=60] -->
@@ -813,6 +813,10 @@
     <!-- Message shown when non-bypass face authentication succeeds and UDFPS is supported. Provides extra instructions for how the user can enter their device [CHAR LIMIT=60] -->
     <string name="keyguard_face_successful_unlock_press_alt_3">Face recognized. Press the unlock icon to open.</string>
 
+    <!-- Message shown when non-bypass face authentication succeeds. [CHAR LIMIT=60] -->
+    <string name="keyguard_face_successful_unlock">Unlocked by face</string>
+    <!-- Message shown when non-bypass face authentication succeeds. [CHAR LIMIT=60] -->
+    <string name="keyguard_face_successful_unlock_alt1">Face recognized</string>
 
     <!-- Messages shown when users press outside of udfps region during -->
     <string-array name="udfps_accessibility_touch_hints">
@@ -887,7 +891,8 @@
     <!-- Accessibility label for the button that opens the user switcher. -->
     <string name="accessibility_multi_user_switch_switcher">Switch user</string>
 
-    <!-- Accessibility label for the button that opens the user switcher and announces the current user. -->
+    <!-- Accessibility role description for the element that opens the user switcher list. -->
+    <string name="accessibility_multi_user_list_switcher">pulldown menu</string>
 
     <!-- Accessibility label for the user icon on the lock screen. -->
 
diff --git a/packages/SystemUI/res/xml/qqs_header.xml b/packages/SystemUI/res/xml/qqs_header.xml
index ee0c4fb6..a82684d03 100644
--- a/packages/SystemUI/res/xml/qqs_header.xml
+++ b/packages/SystemUI/res/xml/qqs_header.xml
@@ -43,7 +43,7 @@
         android:id="@+id/date">
         <Layout
             android:layout_width="0dp"
-            android:layout_height="0dp"
+            android:layout_height="@dimen/qs_header_non_clickable_element_height"
             app:layout_constrainedWidth="true"
             app:layout_constraintStart_toEndOf="@id/clock"
             app:layout_constraintEnd_toStartOf="@id/barrier"
@@ -61,7 +61,7 @@
             app:layout_constraintHeight_min="@dimen/qs_header_non_clickable_element_height"
             app:layout_constraintStart_toEndOf="@id/date"
             app:layout_constraintEnd_toStartOf="@id/batteryRemainingIcon"
-            app:layout_constraintTop_toTopOf="@id/date"
+            app:layout_constraintTop_toTopOf="parent"
             app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintHorizontal_bias="1"
             />
@@ -76,7 +76,7 @@
             app:layout_constraintHeight_min="@dimen/qs_header_non_clickable_element_height"
             app:layout_constraintStart_toEndOf="@id/statusIcons"
             app:layout_constraintEnd_toEndOf="@id/end_guide"
-            app:layout_constraintTop_toTopOf="@id/date"
+            app:layout_constraintTop_toTopOf="parent"
             app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintHorizontal_bias="1"
             />
@@ -100,8 +100,8 @@
             android:layout_height="0dp"
             app:layout_constraintStart_toEndOf="@id/date"
             app:layout_constraintEnd_toEndOf="@id/end_guide"
-            app:layout_constraintTop_toTopOf="@id/date"
-            app:layout_constraintBottom_toBottomOf="@id/date"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintHorizontal_bias="1"
         />
     </Constraint>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java
index 203b236..7e42e1b 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java
@@ -170,7 +170,7 @@
     /** @return {@link SurfaceControl.Transaction} instance with vsync-id */
     public static SurfaceControl.Transaction newSurfaceControlTransaction() {
         final SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
-        tx.setFrameTimelineVsync(Choreographer.getSfInstance().getVsyncId());
+        tx.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId());
         return tx;
     }
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
index 0149751..4613e8b 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
@@ -100,4 +100,14 @@
      * Sent when the desired dark intensity of the nav buttons has changed
      */
     void onNavButtonsDarkIntensityChanged(float darkIntensity) = 22;
+
+     /**
+      * Sent when screen started turning on.
+      */
+     void onScreenTurningOn() = 23;
+
+     /**
+      * Sent when screen started turning off.
+      */
+     void onScreenTurningOff() = 24;
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java
index 9265f07..33e8e35 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java
@@ -122,12 +122,13 @@
                     IRemoteTransitionFinishedCallback finishCallback) {
                 final ArrayMap<SurfaceControl, SurfaceControl> leashMap = new ArrayMap<>();
                 final RemoteAnimationTargetCompat[] appsCompat =
-                        RemoteAnimationTargetCompat.wrap(info, false /* wallpapers */, t, leashMap);
+                        RemoteAnimationTargetCompat.wrapApps(info, t, leashMap);
                 final RemoteAnimationTargetCompat[] wallpapersCompat =
-                        RemoteAnimationTargetCompat.wrap(info, true /* wallpapers */, t, leashMap);
-                // TODO(bc-unlock): Build wrapped object for non-apps target.
+                        RemoteAnimationTargetCompat.wrapNonApps(
+                                info, true /* wallpapers */, t, leashMap);
                 final RemoteAnimationTargetCompat[] nonAppsCompat =
-                        new RemoteAnimationTargetCompat[0];
+                        RemoteAnimationTargetCompat.wrapNonApps(
+                                info, false /* wallpapers */, t, leashMap);
 
                 // TODO(b/177438007): Move this set-up logic into launcher's animation impl.
                 boolean isReturnToHome = false;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
index ef9e095..7c3b5fc 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
@@ -16,7 +16,9 @@
 
 package com.android.systemui.shared.system;
 
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
 import static android.view.WindowManager.TRANSIT_CLOSE;
 import static android.view.WindowManager.TRANSIT_OPEN;
 import static android.view.WindowManager.TRANSIT_TO_BACK;
@@ -24,6 +26,8 @@
 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.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR;
+
 import android.annotation.NonNull;
 import android.annotation.SuppressLint;
 import android.app.ActivityManager;
@@ -76,7 +80,7 @@
 
     private final SurfaceControl mStartLeash;
 
-    // Fields used only to unrap into RemoteAnimationTarget
+    // Fields used only to unwrap into RemoteAnimationTarget
     private final Rect startBounds;
 
     public final boolean willShowImeOnTarget;
@@ -203,8 +207,19 @@
 
     public RemoteAnimationTargetCompat(TransitionInfo.Change change, int order,
             TransitionInfo info, SurfaceControl.Transaction t) {
-        taskId = change.getTaskInfo() != null ? change.getTaskInfo().taskId : -1;
         mode = newModeToLegacyMode(change.getMode());
+        taskInfo = change.getTaskInfo();
+        if (taskInfo != null) {
+            taskId = taskInfo.taskId;
+            isNotInRecents = !taskInfo.isRunning;
+            activityType = taskInfo.getActivityType();
+            windowConfiguration = taskInfo.configuration.windowConfiguration;
+        } else {
+            taskId = INVALID_TASK_ID;
+            isNotInRecents = true;
+            activityType = ACTIVITY_TYPE_UNDEFINED;
+            windowConfiguration = new WindowConfiguration();
+        }
 
         // TODO: once we can properly sync transactions across process, then get rid of this leash.
         leash = createLeash(info, change, order, t);
@@ -221,22 +236,12 @@
         prefixOrderIndex = order;
         // TODO(shell-transitions): I guess we need to send content insets? evaluate how its used.
         contentInsets = new Rect(0, 0, 0, 0);
-        if (change.getTaskInfo() != null) {
-            isNotInRecents = !change.getTaskInfo().isRunning;
-            activityType = change.getTaskInfo().getActivityType();
-        } else {
-            isNotInRecents = true;
-            activityType = ACTIVITY_TYPE_UNDEFINED;
-        }
-        taskInfo = change.getTaskInfo();
         allowEnterPip = change.getAllowEnterPip();
         mStartLeash = null;
         rotationChange = change.getEndRotation() - change.getStartRotation();
-        windowType = INVALID_WINDOW_TYPE;
+        windowType = (change.getFlags() & FLAG_IS_DIVIDER_BAR) != 0
+                ? TYPE_DOCK_DIVIDER : INVALID_WINDOW_TYPE;
 
-        windowConfiguration = change.getTaskInfo() != null
-            ? change.getTaskInfo().configuration.windowConfiguration
-            : new WindowConfiguration();
         startBounds = change.getStartAbsBounds();
         willShowImeOnTarget = (change.getFlags() & TransitionInfo.FLAG_WILL_IME_SHOWN) != 0;
     }
@@ -251,37 +256,62 @@
     }
 
     /**
-     * Represents a TransitionInfo object as an array of old-style targets
+     * Represents a TransitionInfo object as an array of old-style app targets
+     *
+     * @param leashMap Temporary map of change leash -> launcher leash. Is an output, so should be
+     *                 populated by this function. If null, it is ignored.
+     */
+    public static RemoteAnimationTargetCompat[] wrapApps(TransitionInfo info,
+            SurfaceControl.Transaction t, ArrayMap<SurfaceControl, SurfaceControl> leashMap) {
+        final ArrayList<RemoteAnimationTargetCompat> out = new ArrayList<>();
+        final SparseArray<TransitionInfo.Change> childTaskTargets = new SparseArray<>();
+        for (int i = 0; i < info.getChanges().size(); i++) {
+            final TransitionInfo.Change change = info.getChanges().get(i);
+            if (change.getTaskInfo() == null) continue;
+
+            final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
+            // Children always come before parent since changes are in top-to-bottom z-order.
+            if (taskInfo != null) {
+                if (childTaskTargets.contains(taskInfo.taskId)) {
+                    // has children, so not a leaf. Skip.
+                    continue;
+                }
+                if (taskInfo.hasParentTask()) {
+                    childTaskTargets.put(taskInfo.parentTaskId, change);
+                }
+            }
+
+            final RemoteAnimationTargetCompat targetCompat =
+                    new RemoteAnimationTargetCompat(change, info.getChanges().size() - i, info, t);
+            if (leashMap != null) {
+                leashMap.put(change.getLeash(), targetCompat.leash);
+            }
+            out.add(targetCompat);
+        }
+
+        return out.toArray(new RemoteAnimationTargetCompat[out.size()]);
+    }
+
+    /**
+     * Represents a TransitionInfo object as an array of old-style non-app targets
      *
      * @param wallpapers If true, this will return wallpaper targets; otherwise it returns
      *                   non-wallpaper targets.
      * @param leashMap Temporary map of change leash -> launcher leash. Is an output, so should be
      *                 populated by this function. If null, it is ignored.
      */
-    public static RemoteAnimationTargetCompat[] wrap(TransitionInfo info, boolean wallpapers,
+    public static RemoteAnimationTargetCompat[] wrapNonApps(TransitionInfo info, boolean wallpapers,
             SurfaceControl.Transaction t, ArrayMap<SurfaceControl, SurfaceControl> leashMap) {
         final ArrayList<RemoteAnimationTargetCompat> out = new ArrayList<>();
-        final SparseArray<TransitionInfo.Change> childTaskTargets = new SparseArray<>();
+
         for (int i = 0; i < info.getChanges().size(); i++) {
             final TransitionInfo.Change change = info.getChanges().get(i);
+            if (change.getTaskInfo() != null) continue;
+
             final boolean changeIsWallpaper =
                     (change.getFlags() & TransitionInfo.FLAG_IS_WALLPAPER) != 0;
             if (wallpapers != changeIsWallpaper) continue;
 
-            if (!wallpapers) {
-                final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
-                // Children always come before parent since changes are in top-to-bottom z-order.
-                if (taskInfo != null) {
-                    if (childTaskTargets.contains(taskInfo.taskId)) {
-                        // has children, so not a leaf. Skip.
-                        continue;
-                    }
-                    if (taskInfo.hasParentTask()) {
-                        childTaskTargets.put(taskInfo.parentTaskId, change);
-                    }
-                }
-            }
-
             final RemoteAnimationTargetCompat targetCompat =
                     new RemoteAnimationTargetCompat(change, info.getChanges().size() - i, info, t);
             if (leashMap != null) {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
index 7c1ef8c..f679225 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
@@ -128,9 +128,10 @@
                     IRemoteTransitionFinishedCallback finishedCallback) {
                 final ArrayMap<SurfaceControl, SurfaceControl> leashMap = new ArrayMap<>();
                 final RemoteAnimationTargetCompat[] apps =
-                        RemoteAnimationTargetCompat.wrap(info, false /* wallpapers */, t, leashMap);
+                        RemoteAnimationTargetCompat.wrapApps(info, t, leashMap);
                 final RemoteAnimationTargetCompat[] wallpapers =
-                        RemoteAnimationTargetCompat.wrap(info, true /* wallpapers */, t, leashMap);
+                        RemoteAnimationTargetCompat.wrapNonApps(
+                                info, true /* wallpapers */, t, leashMap);
                 // TODO(b/177438007): Move this set-up logic into launcher's animation impl.
                 mToken = transition;
                 // This transition is for opening recents, so recents is on-top. We want to draw
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index f697e25..3517d22 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -1129,11 +1129,13 @@
                 Log.e(TAG, "Current user in user switcher is null.");
                 return;
             }
+            final String currentUserName = mUserSwitcherController.getCurrentUserName();
             Drawable userIcon = findUserIcon(currentUser.info.id);
             ((ImageView) mView.findViewById(R.id.user_icon)).setImageDrawable(userIcon);
-            mUserSwitcher.setText(mUserSwitcherController.getCurrentUserName());
+            mUserSwitcher.setText(currentUserName);
 
-            ViewGroup anchor = mView.findViewById(R.id.user_switcher_anchor);
+            KeyguardUserSwitcherAnchor anchor = mView.findViewById(R.id.user_switcher_anchor);
+
             BaseUserAdapter adapter = new BaseUserAdapter(mUserSwitcherController) {
                 @Override
                 public View getView(int position, View convertView, ViewGroup parent) {
@@ -1213,7 +1215,6 @@
 
             anchor.setOnClickListener((v) -> {
                 if (mFalsingManager.isFalseTap(LOW_PENALTY)) return;
-
                 mPopup = new KeyguardUserSwitcherPopupMenu(v.getContext(), mFalsingManager);
                 mPopup.setAnchorView(anchor);
                 mPopup.setAdapter(adapter);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
index 89d6fb5..acbea1b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
@@ -29,7 +29,7 @@
 
 /**
  * Translates items away/towards the hinge when the device is opened/closed. This is controlled by
- * the set of ids, which also dictact which direction to move and when, via a filter function.
+ * the set of ids, which also dictate which direction to move and when, via a filter function.
  */
 @SysUIUnfoldScope
 class KeyguardUnfoldTransition
@@ -55,7 +55,9 @@
                     ViewIdToTranslate(R.id.lockscreen_clock_view, LEFT, filterNever),
                     ViewIdToTranslate(
                         R.id.notification_stack_scroller, RIGHT, filterSplitShadeOnly),
-                    ViewIdToTranslate(R.id.wallet_button, RIGHT, filterNever)),
+                    ViewIdToTranslate(R.id.wallet_button, RIGHT, filterNever),
+                    ViewIdToTranslate(R.id.start_button, LEFT, filterNever),
+                    ViewIdToTranslate(R.id.end_button, RIGHT, filterNever)),
             progressProvider = unfoldProgressProvider)
     }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 98946ac..6bac7dc 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -87,7 +87,6 @@
 import android.telephony.TelephonyCallback;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
-import android.util.Log;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 
@@ -730,7 +729,7 @@
     private void handleFingerprintAuthFailed() {
         Assert.isMainThread();
         if (mHandler.hasCallbacks(mFpCancelNotReceived)) {
-            Log.d(TAG, "handleFingerprintAuthFailed()"
+            mLogger.d("handleFingerprintAuthFailed()"
                     + " triggered while waiting for cancellation, removing watchdog");
             mHandler.removeCallbacks(mFpCancelNotReceived);
         }
@@ -765,7 +764,7 @@
     private void handleFingerprintAuthenticated(int authUserId, boolean isStrongBiometric) {
         Trace.beginSection("KeyGuardUpdateMonitor#handlerFingerPrintAuthenticated");
         if (mHandler.hasCallbacks(mFpCancelNotReceived)) {
-            Log.d(TAG, "handleFingerprintAuthenticated()"
+            mLogger.d("handleFingerprintAuthenticated()"
                     + " triggered while waiting for cancellation, removing watchdog");
             mHandler.removeCallbacks(mFpCancelNotReceived);
         }
@@ -840,7 +839,7 @@
 
         if (msgId == FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE
                 || msgId == FingerprintManager.BIOMETRIC_ERROR_POWER_PRESSED) {
-            Log.d(TAG, "Fingerprint retrying auth due to(" + msgId + ") -> " + errString);
+            mLogger.logRetryAfterFpError(msgId, errString);
             mHandler.postDelayed(mRetryFingerprintAuthentication, HAL_ERROR_RETRY_TIMEOUT);
         }
 
@@ -3418,7 +3417,7 @@
                 mHandler.sendMessage(mHandler.obtainMessage(MSG_ASSISTANT_STACK_CHANGED,
                         info.visible));
             } catch (RemoteException e) {
-                Log.e(TAG, "unable to check task stack", e);
+                mLogger.logException(e, "unable to check task stack ");
             }
         }
     };
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 99e0ce2..7a42803 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -271,7 +271,7 @@
      * like fingerprint authentication errors.
      *
      * @param message Message that indicates an error.
-     * @see KeyguardIndicationController.BaseKeyguardCallback#HIDE_DELAY_MS
+     * @see KeyguardIndicationController#DEFAULT_HIDE_DELAY_MS
      * @see KeyguardIndicationController#showTransientIndication(CharSequence)
      */
     public void onTrustAgentErrorMessage(CharSequence message) { }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUserSwitcherAnchor.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardUserSwitcherAnchor.kt
new file mode 100644
index 0000000..5f3ba72
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUserSwitcherAnchor.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.accessibility.AccessibilityNodeInfo
+import android.widget.LinearLayout
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
+import com.android.systemui.R
+
+/**
+ * Custom View for the multi-user switcher pull-down menu anchor
+ */
+class KeyguardUserSwitcherAnchor @JvmOverloads constructor(
+        context: Context,
+        attrs: AttributeSet? = null
+) : LinearLayout(context, attrs) {
+
+    override fun createAccessibilityNodeInfo(): AccessibilityNodeInfo {
+        val info = super.createAccessibilityNodeInfo()
+        AccessibilityNodeInfoCompat.wrap(info).roleDescription =
+                context.getString(R.string.accessibility_multi_user_list_switcher)
+        return info
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
index 035b7f0..d718a24 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
@@ -198,6 +198,15 @@
                 { "Retrying face after HW unavailable, attempt $int1" })
     }
 
+    fun logRetryAfterFpError(msgId: Int, errString: String?) {
+        logBuffer.log(TAG, DEBUG, {
+            int1 = msgId
+            str1 = "$errString"
+        }, {
+            "Fingerprint retrying auth due to($int1) -> $str1"
+        })
+    }
+
     fun logRetryAfterFpHwUnavailable(retryCount: Int) {
         logBuffer.log(TAG, WARNING,
                 { int1 = retryCount },
@@ -270,12 +279,12 @@
                 { str1 = newTimeFormat },
                 { "handleTimeFormatUpdate timeFormat=$str1" })
     }
-
     fun logUdfpsPointerDown(sensorId: Int) {
         logBuffer.log(TAG, DEBUG,
                 { int1 = sensorId },
                 { "onUdfpsPointerDown, sensorId: $int1" })
     }
+
     fun logUdfpsPointerUp(sensorId: Int) {
         logBuffer.log(TAG, DEBUG,
                 { int1 = sensorId },
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 5c84ff3..614a87f 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -87,7 +87,6 @@
 import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment;
-import com.android.systemui.statusbar.notification.NotificationFilter;
 import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
 import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
@@ -102,7 +101,6 @@
 import com.android.systemui.statusbar.phone.LightBarController;
 import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
 import com.android.systemui.statusbar.phone.ManagedProfileController;
-import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper;
 import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
 import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -313,7 +311,6 @@
     @Inject Lazy<AccessibilityFloatingMenuController> mAccessibilityFloatingMenuController;
     @Inject Lazy<StatusBarStateController> mStatusBarStateController;
     @Inject Lazy<NotificationLockscreenUserManager> mNotificationLockscreenUserManager;
-    @Inject Lazy<NotificationGroupAlertTransferHelper> mNotificationGroupAlertTransferHelper;
     @Inject Lazy<NotificationGroupManagerLegacy> mNotificationGroupManager;
     @Inject Lazy<VisualStabilityManager> mVisualStabilityManager;
     @Inject Lazy<NotificationGutsManager> mNotificationGutsManager;
@@ -322,7 +319,6 @@
     @Inject Lazy<SmartReplyConstants> mSmartReplyConstants;
     @Inject Lazy<NotificationListener> mNotificationListener;
     @Inject Lazy<NotificationLogger> mNotificationLogger;
-    @Inject Lazy<NotificationFilter> mNotificationFilter;
     @Inject Lazy<KeyguardDismissUtil> mKeyguardDismissUtil;
     @Inject Lazy<SmartReplyController> mSmartReplyController;
     @Inject Lazy<RemoteInputQuickSettingsDisabler> mRemoteInputQuickSettingsDisabler;
@@ -529,8 +525,6 @@
                 mNotificationLockscreenUserManager::get);
         mProviders.put(VisualStabilityManager.class, mVisualStabilityManager::get);
         mProviders.put(NotificationGroupManagerLegacy.class, mNotificationGroupManager::get);
-        mProviders.put(NotificationGroupAlertTransferHelper.class,
-                mNotificationGroupAlertTransferHelper::get);
         mProviders.put(NotificationMediaManager.class, mNotificationMediaManager::get);
         mProviders.put(NotificationGutsManager.class, mNotificationGutsManager::get);
         mProviders.put(NotificationRemoteInputManager.class,
@@ -538,7 +532,6 @@
         mProviders.put(SmartReplyConstants.class, mSmartReplyConstants::get);
         mProviders.put(NotificationListener.class, mNotificationListener::get);
         mProviders.put(NotificationLogger.class, mNotificationLogger::get);
-        mProviders.put(NotificationFilter.class, mNotificationFilter::get);
         mProviders.put(KeyguardDismissUtil.class, mKeyguardDismissUtil::get);
         mProviders.put(SmartReplyController.class, mSmartReplyController::get);
         mProviders.put(RemoteInputQuickSettingsDisabler.class,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceIconController.kt
index 55611f7..e60d4e1 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceIconController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceIconController.kt
@@ -18,7 +18,7 @@
 import android.content.Context
 import android.graphics.drawable.Drawable
 import android.util.Log
-import android.widget.ImageView
+import com.airbnb.lottie.LottieAnimationView
 import com.android.systemui.R
 import com.android.systemui.biometrics.AuthBiometricView.BiometricState
 import com.android.systemui.biometrics.AuthBiometricView.STATE_AUTHENTICATED
@@ -33,8 +33,8 @@
 
 /** Face only icon animator for BiometricPrompt. */
 class AuthBiometricFaceIconController(
-    context: Context,
-    iconView: ImageView
+        context: Context,
+        iconView: LottieAnimationView
 ) : AuthIconController(context, iconView) {
 
     // false = dark to light, true = light to dark
@@ -76,44 +76,44 @@
         if (newState == STATE_AUTHENTICATING_ANIMATING_IN) {
             showStaticDrawable(R.drawable.face_dialog_pulse_dark_to_light)
             iconView.contentDescription = context.getString(
-                R.string.biometric_dialog_face_icon_description_authenticating
+                    R.string.biometric_dialog_face_icon_description_authenticating
             )
         } else if (newState == STATE_AUTHENTICATING) {
             startPulsing()
             iconView.contentDescription = context.getString(
-                R.string.biometric_dialog_face_icon_description_authenticating
+                    R.string.biometric_dialog_face_icon_description_authenticating
             )
         } else if (oldState == STATE_PENDING_CONFIRMATION && newState == STATE_AUTHENTICATED) {
             animateIconOnce(R.drawable.face_dialog_dark_to_checkmark)
             iconView.contentDescription = context.getString(
-                R.string.biometric_dialog_face_icon_description_confirmed
+                    R.string.biometric_dialog_face_icon_description_confirmed
             )
         } else if (lastStateIsErrorIcon && newState == STATE_IDLE) {
             animateIconOnce(R.drawable.face_dialog_error_to_idle)
             iconView.contentDescription = context.getString(
-                R.string.biometric_dialog_face_icon_description_idle
+                    R.string.biometric_dialog_face_icon_description_idle
             )
         } else if (lastStateIsErrorIcon && newState == STATE_AUTHENTICATED) {
             animateIconOnce(R.drawable.face_dialog_dark_to_checkmark)
             iconView.contentDescription = context.getString(
-                R.string.biometric_dialog_face_icon_description_authenticated
+                    R.string.biometric_dialog_face_icon_description_authenticated
             )
         } else if (newState == STATE_ERROR && oldState != STATE_ERROR) {
             animateIconOnce(R.drawable.face_dialog_dark_to_error)
         } else if (oldState == STATE_AUTHENTICATING && newState == STATE_AUTHENTICATED) {
             animateIconOnce(R.drawable.face_dialog_dark_to_checkmark)
             iconView.contentDescription = context.getString(
-                R.string.biometric_dialog_face_icon_description_authenticated
+                    R.string.biometric_dialog_face_icon_description_authenticated
             )
         } else if (newState == STATE_PENDING_CONFIRMATION) {
             animateIconOnce(R.drawable.face_dialog_wink_from_dark)
             iconView.contentDescription = context.getString(
-                R.string.biometric_dialog_face_icon_description_authenticated
+                    R.string.biometric_dialog_face_icon_description_authenticated
             )
         } else if (newState == STATE_IDLE) {
             showStaticDrawable(R.drawable.face_dialog_idle_static)
             iconView.contentDescription = context.getString(
-                R.string.biometric_dialog_face_icon_description_idle
+                    R.string.biometric_dialog_face_icon_description_idle
             )
         } else {
             Log.w(TAG, "Unhandled state: $newState")
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt
index 3e4e573..40d1eff 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt
@@ -16,42 +16,43 @@
 
 package com.android.systemui.biometrics
 
+import android.annotation.RawRes
 import android.content.Context
-import android.graphics.drawable.Drawable
-import android.widget.ImageView
+import com.airbnb.lottie.LottieAnimationView
 import com.android.systemui.R
 import com.android.systemui.biometrics.AuthBiometricView.BiometricState
-import com.android.systemui.biometrics.AuthBiometricView.STATE_PENDING_CONFIRMATION
 import com.android.systemui.biometrics.AuthBiometricView.STATE_AUTHENTICATED
 import com.android.systemui.biometrics.AuthBiometricView.STATE_ERROR
 import com.android.systemui.biometrics.AuthBiometricView.STATE_HELP
+import com.android.systemui.biometrics.AuthBiometricView.STATE_PENDING_CONFIRMATION
 
 /** Face/Fingerprint combined icon animator for BiometricPrompt. */
 class AuthBiometricFingerprintAndFaceIconController(
-    context: Context,
-    iconView: ImageView
+        context: Context,
+        iconView: LottieAnimationView
 ) : AuthBiometricFingerprintIconController(context, iconView) {
 
     override val actsAsConfirmButton: Boolean = true
 
     override fun shouldAnimateForTransition(
-        @BiometricState oldState: Int,
-        @BiometricState newState: Int
+            @BiometricState oldState: Int,
+            @BiometricState newState: Int
     ): Boolean = when (newState) {
         STATE_PENDING_CONFIRMATION -> true
         STATE_AUTHENTICATED -> false
         else -> super.shouldAnimateForTransition(oldState, newState)
     }
 
+    @RawRes
     override fun getAnimationForTransition(
-        @BiometricState oldState: Int,
-        @BiometricState newState: Int
-    ): Drawable? = when (newState) {
+            @BiometricState oldState: Int,
+            @BiometricState newState: Int
+    ): Int? = when (newState) {
         STATE_PENDING_CONFIRMATION -> {
             if (oldState == STATE_ERROR || oldState == STATE_HELP) {
-                context.getDrawable(R.drawable.fingerprint_dialog_error_to_unlock)
+                R.raw.fingerprint_dialogue_error_to_unlock_lottie
             } else {
-                context.getDrawable(R.drawable.fingerprint_dialog_fp_to_unlock)
+                R.raw.fingerprint_dialogue_fingerprint_to_unlock_lottie
             }
         }
         STATE_AUTHENTICATED -> null
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
index 606a73a..589ec0e 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
@@ -16,10 +16,9 @@
 
 package com.android.systemui.biometrics
 
+import android.annotation.RawRes
 import android.content.Context
-import android.graphics.drawable.AnimatedVectorDrawable
-import android.graphics.drawable.Drawable
-import android.widget.ImageView
+import com.airbnb.lottie.LottieAnimationView
 import com.android.systemui.R
 import com.android.systemui.biometrics.AuthBiometricView.BiometricState
 import com.android.systemui.biometrics.AuthBiometricView.STATE_AUTHENTICATED
@@ -32,42 +31,42 @@
 
 /** Fingerprint only icon animator for BiometricPrompt.  */
 open class AuthBiometricFingerprintIconController(
-    context: Context,
-    iconView: ImageView
+        context: Context,
+        iconView: LottieAnimationView
 ) : AuthIconController(context, iconView) {
 
-    var iconLayoutParamsSize = 0
+    var iconLayoutParamSize: Pair<Int, Int> = Pair(1, 1)
         set(value) {
             if (field == value) {
                 return
             }
-            iconView.layoutParams.width = value
-            iconView.layoutParams.height = value
+            iconView.layoutParams.width = value.first
+            iconView.layoutParams.height = value.second
             field = value
         }
 
     init {
-        iconLayoutParamsSize = context.resources.getDimensionPixelSize(
-            R.dimen.biometric_dialog_fingerprint_icon_size
-        )
+        iconLayoutParamSize = Pair(context.resources.getDimensionPixelSize(
+                R.dimen.biometric_dialog_fingerprint_icon_width),
+                context.resources.getDimensionPixelSize(
+                        R.dimen.biometric_dialog_fingerprint_icon_height))
     }
 
     override fun updateIcon(@BiometricState lastState: Int, @BiometricState newState: Int) {
         val icon = getAnimationForTransition(lastState, newState) ?: return
 
-        iconView.setImageDrawable(icon)
+        if (!(lastState == STATE_AUTHENTICATING_ANIMATING_IN && newState == STATE_AUTHENTICATING)) {
+            iconView.setAnimation(icon)
+        }
 
         val iconContentDescription = getIconContentDescription(newState)
         if (iconContentDescription != null) {
             iconView.contentDescription = iconContentDescription
         }
 
-        (icon as? AnimatedVectorDrawable)?.apply {
-            reset()
-            if (shouldAnimateForTransition(lastState, newState)) {
-                forceAnimationOnUI()
-                start()
-            }
+        iconView.frame = 0
+        if (shouldAnimateForTransition(lastState, newState)) {
+            iconView.playAnimation()
         }
     }
 
@@ -86,8 +85,8 @@
     }
 
     protected open fun shouldAnimateForTransition(
-        @BiometricState oldState: Int,
-        @BiometricState newState: Int
+            @BiometricState oldState: Int,
+            @BiometricState newState: Int
     ) = when (newState) {
         STATE_HELP,
         STATE_ERROR -> true
@@ -97,24 +96,27 @@
         else -> false
     }
 
+    @RawRes
     protected open fun getAnimationForTransition(
-        @BiometricState oldState: Int,
-        @BiometricState newState: Int
-    ): Drawable? {
+            @BiometricState oldState: Int,
+            @BiometricState newState: Int
+    ): Int? {
         val id = when (newState) {
             STATE_HELP,
-            STATE_ERROR -> R.drawable.fingerprint_dialog_fp_to_error
+            STATE_ERROR -> {
+                R.raw.fingerprint_dialogue_fingerprint_to_error_lottie
+            }
             STATE_AUTHENTICATING_ANIMATING_IN,
             STATE_AUTHENTICATING -> {
                 if (oldState == STATE_ERROR || oldState == STATE_HELP) {
-                    R.drawable.fingerprint_dialog_error_to_fp
+                    R.raw.fingerprint_dialogue_error_to_fingerprint_lottie
                 } else {
-                    R.drawable.fingerprint_dialog_fp_to_error
+                    R.raw.fingerprint_dialogue_fingerprint_to_error_lottie
                 }
             }
-            STATE_AUTHENTICATED -> R.drawable.fingerprint_dialog_fp_to_error
+            STATE_AUTHENTICATED -> R.raw.fingerprint_dialogue_fingerprint_to_error_lottie
             else -> return null
         }
-        return if (id != null) context.getDrawable(id) else null
+        return if (id != null) return id else null
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt
index 24046f0..31baa0f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt
@@ -90,8 +90,9 @@
 
     fun updateOverrideIconLayoutParamsSize() {
         udfpsAdapter?.let {
-            (mIconController as? AuthBiometricFingerprintIconController)?.iconLayoutParamsSize =
-                    it.getSensorDiameter(scaleFactorProvider?.provide() ?: 1.0f)
+            val sensorDiameter = it.getSensorDiameter(scaleFactorProvider?.provide() ?: 1.0f)
+            (mIconController as? AuthBiometricFingerprintIconController)?.iconLayoutParamSize =
+                    Pair(sensorDiameter, sensorDiameter)
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricIconController.kt
index ce5e600..15f487b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricIconController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricIconController.kt
@@ -22,15 +22,15 @@
 import android.graphics.drawable.AnimatedVectorDrawable
 import android.graphics.drawable.Drawable
 import android.util.Log
-import android.widget.ImageView
+import com.airbnb.lottie.LottieAnimationView
 import com.android.systemui.biometrics.AuthBiometricView.BiometricState
 
 private const val TAG = "AuthIconController"
 
 /** Controller for animating the BiometricPrompt icon/affordance. */
 abstract class AuthIconController(
-    protected val context: Context,
-    protected val iconView: ImageView
+        protected val context: Context,
+        protected val iconView: LottieAnimationView
 ) : Animatable2.AnimationCallback() {
 
     /** If this controller should ignore events and pause. */
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
index d7ae9ef..e866b9c 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
@@ -41,14 +41,14 @@
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityManager;
 import android.widget.Button;
-import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.systemui.R;
-import com.android.systemui.util.LargeScreenUtils;
+
+import com.airbnb.lottie.LottieAnimationView;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -133,7 +133,7 @@
     private TextView mSubtitleView;
     private TextView mDescriptionView;
     private View mIconHolderView;
-    protected ImageView mIconView;
+    protected LottieAnimationView mIconView;
     protected TextView mIndicatorView;
 
     @VisibleForTesting @NonNull AuthIconController mIconController;
@@ -824,25 +824,12 @@
         return new AuthDialog.LayoutParams(width, totalHeight);
     }
 
-    private boolean isLargeDisplay() {
-        return LargeScreenUtils.shouldUseSplitNotificationShade(getResources());
-    }
-
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         final int width = MeasureSpec.getSize(widthMeasureSpec);
         final int height = MeasureSpec.getSize(heightMeasureSpec);
 
-        final boolean isLargeDisplay = isLargeDisplay();
-
-        final int newWidth;
-        if (isLargeDisplay) {
-            // TODO(b/201811580): Unless we can come up with a one-size-fits-all equation, we may
-            //  want to consider moving this to an overlay.
-            newWidth = 2 * Math.min(width, height) / 3;
-        } else {
-            newWidth = Math.min(width, height);
-        }
+        final int newWidth = Math.min(width, height);
 
         // Use "newWidth" instead, so the landscape dialog width is the same as the portrait
         // width.
diff --git a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java
index 835025b..e82d0ea 100644
--- a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java
+++ b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.charging;
 
-import static com.android.systemui.charging.WirelessChargingLayout.UNKNOWN_BATTERY_LEVEL;
-
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
@@ -32,13 +30,14 @@
 
 import com.android.internal.logging.UiEvent;
 import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.ripple.RippleShader.RippleShape;
 
 /**
  * A WirelessChargingAnimation is a view containing view + animation for wireless charging.
  * @hide
  */
 public class WirelessChargingAnimation {
-
+    public static final int UNKNOWN_BATTERY_LEVEL = -1;
     public static final long DURATION = 1500;
     private static final String TAG = "WirelessChargingView";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -58,11 +57,12 @@
      * before calling {@link #show} - can be done through {@link #makeWirelessChargingAnimation}.
      * @hide
      */
-    public WirelessChargingAnimation(@NonNull Context context, @Nullable Looper looper,
+    private WirelessChargingAnimation(@NonNull Context context, @Nullable Looper looper,
             int transmittingBatteryLevel, int batteryLevel, Callback callback, boolean isDozing,
-            UiEventLogger uiEventLogger) {
+            RippleShape rippleShape, UiEventLogger uiEventLogger) {
         mCurrentWirelessChargingView = new WirelessChargingView(context, looper,
-                transmittingBatteryLevel, batteryLevel, callback, isDozing, uiEventLogger);
+                transmittingBatteryLevel, batteryLevel, callback, isDozing,
+                rippleShape, uiEventLogger);
     }
 
     /**
@@ -72,9 +72,10 @@
      */
     public static WirelessChargingAnimation makeWirelessChargingAnimation(@NonNull Context context,
             @Nullable Looper looper, int transmittingBatteryLevel, int batteryLevel,
-            Callback callback, boolean isDozing, UiEventLogger uiEventLogger) {
+            Callback callback, boolean isDozing, RippleShape rippleShape,
+            UiEventLogger uiEventLogger) {
         return new WirelessChargingAnimation(context, looper, transmittingBatteryLevel,
-                batteryLevel, callback, isDozing, uiEventLogger);
+                batteryLevel, callback, isDozing, rippleShape, uiEventLogger);
     }
 
     /**
@@ -82,9 +83,10 @@
      * battery level without charging number shown.
      */
     public static WirelessChargingAnimation makeChargingAnimationWithNoBatteryLevel(
-            @NonNull Context context, UiEventLogger uiEventLogger) {
+            @NonNull Context context, RippleShape rippleShape, UiEventLogger uiEventLogger) {
         return makeWirelessChargingAnimation(context, null,
-                UNKNOWN_BATTERY_LEVEL, UNKNOWN_BATTERY_LEVEL, null, false, uiEventLogger);
+                UNKNOWN_BATTERY_LEVEL, UNKNOWN_BATTERY_LEVEL, null, false,
+                rippleShape, uiEventLogger);
     }
 
     /**
@@ -121,10 +123,10 @@
 
         public WirelessChargingView(Context context, @Nullable Looper looper,
                 int transmittingBatteryLevel, int batteryLevel, Callback callback,
-                boolean isDozing, UiEventLogger uiEventLogger) {
+                boolean isDozing, RippleShape rippleShape, UiEventLogger uiEventLogger) {
             mCallback = callback;
             mNextView = new WirelessChargingLayout(context, transmittingBatteryLevel, batteryLevel,
-                    isDozing);
+                    isDozing, rippleShape);
             mGravity = Gravity.CENTER_HORIZONTAL | Gravity.CENTER;
             mUiEventLogger = uiEventLogger;
 
diff --git a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
index 65400c2..47ea27f 100644
--- a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
@@ -33,7 +33,7 @@
 import com.android.settingslib.Utils;
 import com.android.systemui.R;
 import com.android.systemui.animation.Interpolators;
-import com.android.systemui.ripple.RippleShader;
+import com.android.systemui.ripple.RippleShader.RippleShape;
 import com.android.systemui.ripple.RippleView;
 
 import java.text.NumberFormat;
@@ -41,37 +41,36 @@
 /**
  * @hide
  */
-public class WirelessChargingLayout extends FrameLayout {
-    public static final int UNKNOWN_BATTERY_LEVEL = -1;
+final class WirelessChargingLayout extends FrameLayout {
     private static final long RIPPLE_ANIMATION_DURATION = 1500;
     private static final int SCRIM_COLOR = 0x4C000000;
     private static final int SCRIM_FADE_DURATION = 300;
     private RippleView mRippleView;
 
-    public WirelessChargingLayout(Context context) {
+    WirelessChargingLayout(Context context, int transmittingBatteryLevel, int batteryLevel,
+            boolean isDozing, RippleShape rippleShape) {
         super(context);
-        init(context, null, false);
+        init(context, null, transmittingBatteryLevel, batteryLevel, isDozing, rippleShape);
     }
 
-    public WirelessChargingLayout(Context context, int transmittingBatteryLevel, int batteryLevel,
-            boolean isDozing) {
+    private WirelessChargingLayout(Context context) {
         super(context);
-        init(context, null, transmittingBatteryLevel, batteryLevel, isDozing);
+        init(context, null, /* isDozing= */ false, RippleShape.CIRCLE);
     }
 
-    public WirelessChargingLayout(Context context, AttributeSet attrs) {
+    private WirelessChargingLayout(Context context, AttributeSet attrs) {
         super(context, attrs);
-        init(context, attrs, false);
+        init(context, attrs, /* isDozing= */false, RippleShape.CIRCLE);
     }
 
-    private void init(Context c, AttributeSet attrs, boolean isDozing) {
-        init(c, attrs, -1, -1, false);
+    private void init(Context c, AttributeSet attrs, boolean isDozing, RippleShape rippleShape) {
+        init(c, attrs, -1, -1, isDozing, rippleShape);
     }
 
     private void init(Context context, AttributeSet attrs, int transmittingBatteryLevel,
-            int batteryLevel, boolean isDozing) {
+            int batteryLevel, boolean isDozing, RippleShape rippleShape) {
         final boolean showTransmittingBatteryLevel =
-                (transmittingBatteryLevel != UNKNOWN_BATTERY_LEVEL);
+                (transmittingBatteryLevel != WirelessChargingAnimation.UNKNOWN_BATTERY_LEVEL);
 
         // set style based on background
         int style = R.style.ChargingAnim_WallpaperBackground;
@@ -84,7 +83,7 @@
         // amount of battery:
         final TextView percentage = findViewById(R.id.wireless_charging_percentage);
 
-        if (batteryLevel != UNKNOWN_BATTERY_LEVEL) {
+        if (batteryLevel != WirelessChargingAnimation.UNKNOWN_BATTERY_LEVEL) {
             percentage.setText(NumberFormat.getPercentInstance().format(batteryLevel / 100f));
             percentage.setAlpha(0);
         }
@@ -138,8 +137,7 @@
         animatorSetScrim.start();
 
         mRippleView = findViewById(R.id.wireless_charging_ripple);
-        // TODO: Make rounded box shape if the device is tablet.
-        mRippleView.setupShader(RippleShader.RippleShape.CIRCLE);
+        mRippleView.setupShader(rippleShape);
         OnAttachStateChangeListener listener = new OnAttachStateChangeListener() {
             @Override
             public void onViewAttachedToWindow(View view) {
@@ -233,8 +231,12 @@
             int width = getMeasuredWidth();
             int height = getMeasuredHeight();
             mRippleView.setCenter(width * 0.5f, height * 0.5f);
-            float maxSize = Math.max(width, height);
-            mRippleView.setMaxSize(maxSize, maxSize);
+            if (mRippleView.getRippleShape() == RippleShape.ROUNDED_BOX) {
+                mRippleView.setMaxSize(width * 1.5f, height * 1.5f);
+            } else {
+                float maxSize = Math.max(width, height);
+                mRippleView.setMaxSize(maxSize, maxSize);
+            }
             mRippleView.setColor(Utils.getColorAttr(mRippleView.getContext(),
                     android.R.attr.colorAccent).getDefaultColor());
         }
diff --git a/packages/SystemUI/src/com/android/systemui/common/coroutine/ChannelExt.kt b/packages/SystemUI/src/com/android/systemui/common/coroutine/ChannelExt.kt
index 6f3beac..a0b19dc 100644
--- a/packages/SystemUI/src/com/android/systemui/common/coroutine/ChannelExt.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/coroutine/ChannelExt.kt
@@ -35,7 +35,7 @@
      *             " - downstream canceled or failed.",
      *          it,
      *    )
-     *}
+     * }
      * ```
      */
     fun <T> SendChannel<T>.trySendWithFailureLogging(
diff --git a/packages/SystemUI/src/com/android/systemui/common/domain/model/Position.kt b/packages/SystemUI/src/com/android/systemui/common/domain/model/Position.kt
deleted file mode 100644
index f697c0a..0000000
--- a/packages/SystemUI/src/com/android/systemui/common/domain/model/Position.kt
+++ /dev/null
@@ -1,34 +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.common.domain.model
-
-import com.android.systemui.common.data.model.Position as DataLayerPosition
-
-/** Models a two-dimensional position */
-data class Position(
-    val x: Int,
-    val y: Int,
-) {
-    companion object {
-        fun DataLayerPosition.toDomainLayer(): Position {
-            return Position(
-                x = x,
-                y = y,
-            )
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/common/data/model/Position.kt b/packages/SystemUI/src/com/android/systemui/common/shared/model/Position.kt
similarity index 93%
rename from packages/SystemUI/src/com/android/systemui/common/data/model/Position.kt
rename to packages/SystemUI/src/com/android/systemui/common/shared/model/Position.kt
index 7c9df10..52f6167 100644
--- a/packages/SystemUI/src/com/android/systemui/common/data/model/Position.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/shared/model/Position.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.common.data.model
+package com.android.systemui.common.shared.model
 
 /** Models a two-dimensional position */
 data class Position(
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
index 78a45f9..b6923a8 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
@@ -75,25 +75,12 @@
      * Initializes all the WMShell components before starting any of the SystemUI components.
      */
     default void init() {
-        // TODO(238217847): To be removed once the dependencies are inverted and ShellController can
-        // inject these classes directly, otherwise, it's currently needed to ensure that these
-        // classes are created and set on the controller before onInit() is called
-        getShellInit();
-        getShellCommandHandler();
         getShell().onInit();
     }
 
     @WMSingleton
     ShellInterface getShell();
 
-    // TODO(238217847): To be removed once ShellController can inject ShellInit directly
-    @WMSingleton
-    ShellInit getShellInit();
-
-    // TODO(238217847): To be removed once ShellController can inject ShellCommandHandler directly
-    @WMSingleton
-    ShellCommandHandler getShellCommandHandler();
-
     @WMSingleton
     Optional<OneHanded> getOneHanded();
 
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarItemsProvider.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarItemsProvider.java
new file mode 100644
index 0000000..193d6f5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarItemsProvider.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.dreams;
+
+import android.view.View;
+
+import androidx.annotation.NonNull;
+
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.statusbar.policy.CallbackController;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+import javax.inject.Inject;
+
+/**
+ * {@link DreamOverlayStatusBarItemsProvider} provides extra dream overlay status bar items. A
+ * callback can be registered that will be informed of items being added or removed from the
+ * provider.
+ */
+@SysUISingleton
+public class DreamOverlayStatusBarItemsProvider implements
+        CallbackController<DreamOverlayStatusBarItemsProvider.Callback> {
+    /**
+     * Represents one item in the dream overlay status bar.
+     */
+    public interface StatusBarItem {
+        /**
+         * Return the {@link View} associated with this item.
+         */
+        View getView();
+    }
+
+    /**
+     * A callback to be registered with the provider to be informed of when the list of status bar
+     * items has changed.
+     */
+    public interface Callback {
+        /**
+         * Inform the callback that status bar items have changed.
+         */
+        void onStatusBarItemsChanged(List<StatusBarItem> newItems);
+    }
+
+    private final Executor mExecutor;
+    private final List<StatusBarItem> mItems = new ArrayList<>();
+    private final List<Callback> mCallbacks = new ArrayList<>();
+
+    @Inject
+    public DreamOverlayStatusBarItemsProvider(@Main Executor executor) {
+        mExecutor = executor;
+    }
+
+    @Override
+    public void addCallback(@NonNull Callback callback) {
+        mExecutor.execute(() -> {
+            Objects.requireNonNull(callback, "Callback must not be null.");
+            if (mCallbacks.contains(callback)) {
+                return;
+            }
+
+            mCallbacks.add(callback);
+            if (!mItems.isEmpty()) {
+                callback.onStatusBarItemsChanged(mItems);
+            }
+        });
+    }
+
+    @Override
+    public void removeCallback(@NonNull Callback callback) {
+        mExecutor.execute(() -> {
+            Objects.requireNonNull(callback, "Callback must not be null.");
+            mCallbacks.remove(callback);
+        });
+    }
+
+    /**
+     * Adds an item to the dream overlay status bar.
+     */
+    public void addStatusBarItem(StatusBarItem item) {
+        mExecutor.execute(() -> {
+            if (!mItems.contains(item)) {
+                mItems.add(item);
+                mCallbacks.forEach(callback -> callback.onStatusBarItemsChanged(mItems));
+            }
+        });
+    }
+
+    /**
+     * Removes an item from the dream overlay status bar.
+     */
+    public void removeStatusBarItem(StatusBarItem item) {
+        mExecutor.execute(() -> {
+            if (mItems.remove(item)) {
+                mCallbacks.forEach(callback -> callback.onStatusBarItemsChanged(mItems));
+            }
+        });
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java
index a25257d..7e4a108 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.util.AttributeSet;
 import android.view.View;
+import android.view.ViewGroup;
 
 import androidx.constraintlayout.widget.ConstraintLayout;
 
@@ -29,6 +30,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 
@@ -58,6 +60,7 @@
     public static final int STATUS_ICON_PRIORITY_MODE_ON = 6;
 
     private final Map<Integer, View> mStatusIcons = new HashMap<>();
+    private ViewGroup mSystemStatusViewGroup;
 
     public DreamOverlayStatusBarView(Context context) {
         this(context, null);
@@ -94,6 +97,8 @@
                 fetchStatusIconForResId(R.id.dream_overlay_notification_indicator));
         mStatusIcons.put(STATUS_ICON_PRIORITY_MODE_ON,
                 fetchStatusIconForResId(R.id.dream_overlay_priority_mode));
+
+        mSystemStatusViewGroup = findViewById(R.id.dream_overlay_extra_items);
     }
 
     void showIcon(@StatusIconType int iconType, boolean show, @Nullable String contentDescription) {
@@ -107,6 +112,11 @@
         icon.setVisibility(show ? View.VISIBLE : View.GONE);
     }
 
+    void setExtraStatusBarItemViews(List<View> views) {
+        mSystemStatusViewGroup.removeAllViews();
+        views.forEach(view -> mSystemStatusViewGroup.addView(view));
+    }
+
     private View fetchStatusIconForResId(int resId) {
         final View statusIcon = findViewById(resId);
         return Objects.requireNonNull(statusIcon);
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
index 55c1806..65cfae1 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
@@ -38,6 +38,7 @@
 
 import com.android.systemui.R;
 import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.dreams.DreamOverlayStatusBarItemsProvider.StatusBarItem;
 import com.android.systemui.dreams.dagger.DreamOverlayComponent;
 import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;
 import com.android.systemui.statusbar.policy.NextAlarmController;
@@ -47,10 +48,13 @@
 import com.android.systemui.util.ViewController;
 import com.android.systemui.util.time.DateFormatUtil;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Optional;
 import java.util.concurrent.Executor;
+import java.util.stream.Collectors;
 
 import javax.inject.Inject;
 
@@ -69,7 +73,10 @@
     private final Optional<DreamOverlayNotificationCountProvider>
             mDreamOverlayNotificationCountProvider;
     private final ZenModeController mZenModeController;
+    private final DreamOverlayStatusBarItemsProvider mStatusBarItemsProvider;
     private final Executor mMainExecutor;
+    private final List<DreamOverlayStatusBarItemsProvider.StatusBarItem> mExtraStatusBarItems =
+            new ArrayList<>();
 
     private boolean mIsAttached;
 
@@ -116,6 +123,9 @@
                             ? buildNotificationsContentDescription(notificationCount)
                             : null);
 
+    private final DreamOverlayStatusBarItemsProvider.Callback mStatusBarItemsProviderCallback =
+            this::onStatusBarItemsChanged;
+
     @Inject
     public DreamOverlayStatusBarViewController(
             DreamOverlayStatusBarView view,
@@ -129,7 +139,8 @@
             IndividualSensorPrivacyController sensorPrivacyController,
             Optional<DreamOverlayNotificationCountProvider> dreamOverlayNotificationCountProvider,
             ZenModeController zenModeController,
-            StatusBarWindowStateController statusBarWindowStateController) {
+            StatusBarWindowStateController statusBarWindowStateController,
+            DreamOverlayStatusBarItemsProvider statusBarItemsProvider) {
         super(view);
         mResources = resources;
         mMainExecutor = mainExecutor;
@@ -140,6 +151,7 @@
         mDateFormatUtil = dateFormatUtil;
         mSensorPrivacyController = sensorPrivacyController;
         mDreamOverlayNotificationCountProvider = dreamOverlayNotificationCountProvider;
+        mStatusBarItemsProvider = statusBarItemsProvider;
         mZenModeController = zenModeController;
 
         // Register to receive show/hide updates for the system status bar. Our custom status bar
@@ -166,6 +178,8 @@
         mDreamOverlayNotificationCountProvider.ifPresent(
                 provider -> provider.addCallback(mNotificationCountCallback));
 
+        mStatusBarItemsProvider.addCallback(mStatusBarItemsProviderCallback);
+
         mTouchInsetSession.addViewToTracking(mView);
     }
 
@@ -177,6 +191,7 @@
         mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
         mDreamOverlayNotificationCountProvider.ifPresent(
                 provider -> provider.removeCallback(mNotificationCountCallback));
+        mStatusBarItemsProvider.removeCallback(mStatusBarItemsProviderCallback);
         mTouchInsetSession.clear();
 
         mIsAttached = false;
@@ -271,4 +286,16 @@
             }
         });
     }
+
+    private void onStatusBarItemsChanged(List<StatusBarItem> newItems) {
+        mMainExecutor.execute(() -> {
+            mExtraStatusBarItems.clear();
+            mExtraStatusBarItems.addAll(newItems);
+            mView.setExtraStatusBarItemViews(
+                    newItems
+                            .stream()
+                            .map(StatusBarItem::getView)
+                            .collect(Collectors.toList()));
+        });
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index d9e75c4..a65aed2 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -185,6 +185,7 @@
             new ReleasedFlag(1000);
     public static final ReleasedFlag DOCK_SETUP_ENABLED = new ReleasedFlag(1001);
 
+    public static final UnreleasedFlag ROUNDED_BOX_RIPPLE = new UnreleasedFlag(1002, false);
 
     // 1100 - windowing
     @Keep
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java
index 5aedbdc..f84a5e3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java
@@ -27,6 +27,7 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.KeyguardIndicationController;
 import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
 import com.android.systemui.util.ViewController;
 import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -56,8 +57,11 @@
 public class KeyguardIndicationRotateTextViewController extends
         ViewController<KeyguardIndicationTextView> implements Dumpable {
     public static String TAG = "KgIndicationRotatingCtrl";
-    private static final long DEFAULT_INDICATION_SHOW_LENGTH = 3500; // milliseconds
-    public static final long IMPORTANT_MSG_MIN_DURATION = 2000L + 600L; // 2000ms + [Y in duration]
+    private static final long DEFAULT_INDICATION_SHOW_LENGTH =
+            KeyguardIndicationController.DEFAULT_HIDE_DELAY_MS
+                    - KeyguardIndicationTextView.Y_IN_DURATION;
+    public static final long IMPORTANT_MSG_MIN_DURATION =
+            2000L + KeyguardIndicationTextView.Y_IN_DURATION;
 
     private final StatusBarStateController mStatusBarStateController;
     private final float mMaxAlpha;
@@ -375,6 +379,7 @@
     public static final int INDICATION_TYPE_USER_LOCKED = 8;
     public static final int INDICATION_TYPE_REVERSE_CHARGING = 10;
     public static final int INDICATION_TYPE_BIOMETRIC_MESSAGE = 11;
+    public static final int INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP = 12;
 
     @IntDef({
             INDICATION_TYPE_NONE,
@@ -388,7 +393,8 @@
             INDICATION_TYPE_RESTING,
             INDICATION_TYPE_USER_LOCKED,
             INDICATION_TYPE_REVERSE_CHARGING,
-            INDICATION_TYPE_BIOMETRIC_MESSAGE
+            INDICATION_TYPE_BIOMETRIC_MESSAGE,
+            INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface IndicationType{}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/LifecycleScreenStatusProvider.kt b/packages/SystemUI/src/com/android/systemui/keyguard/LifecycleScreenStatusProvider.kt
index 044a57c..0a55294 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/LifecycleScreenStatusProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/LifecycleScreenStatusProvider.kt
@@ -41,4 +41,12 @@
     override fun onScreenTurnedOn() {
         listeners.forEach(ScreenListener::onScreenTurnedOn)
     }
+
+    override fun onScreenTurningOff() {
+        listeners.forEach(ScreenListener::onScreenTurningOff)
+    }
+
+    override fun onScreenTurningOn(ignored: Runnable) {
+        listeners.forEach(ScreenListener::onScreenTurningOn)
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index 4ff008f..56f1ac4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -43,7 +43,7 @@
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.keyguard.data.repository.KeyguardRepositoryModule;
-import com.android.systemui.keyguard.domain.usecase.KeyguardUseCaseModule;
+import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceModule;
 import com.android.systemui.navigationbar.NavigationModeController;
 import com.android.systemui.statusbar.NotificationShadeDepthController;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -70,8 +70,8 @@
         KeyguardUserSwitcherComponent.class},
         includes = {
             FalsingModule.class,
+            KeyguardQuickAffordanceModule.class,
             KeyguardRepositoryModule.class,
-            KeyguardUseCaseModule.class,
         })
 public class KeyguardModule {
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepository.kt
deleted file mode 100644
index 43c4fa0..0000000
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepository.kt
+++ /dev/null
@@ -1,65 +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.keyguard.data.repository
-
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.keyguard.data.config.KeyguardQuickAffordanceConfigs
-import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.State
-import com.android.systemui.keyguard.shared.model.KeyguardQuickAffordanceModel
-import com.android.systemui.keyguard.shared.model.KeyguardQuickAffordancePosition
-import javax.inject.Inject
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.combine
-
-/** Defines interface for classes that encapsulate quick affordance state for the keyguard. */
-interface KeyguardQuickAffordanceRepository {
-    fun affordance(position: KeyguardQuickAffordancePosition): Flow<KeyguardQuickAffordanceModel>
-}
-
-/** Real implementation of [KeyguardQuickAffordanceRepository] */
-@SysUISingleton
-class KeyguardQuickAffordanceRepositoryImpl
-@Inject
-constructor(
-    private val configs: KeyguardQuickAffordanceConfigs,
-) : KeyguardQuickAffordanceRepository {
-
-    /** Returns an observable for the quick affordance model in the given position. */
-    override fun affordance(
-        position: KeyguardQuickAffordancePosition
-    ): Flow<KeyguardQuickAffordanceModel> {
-        val configs = configs.getAll(position)
-        return combine(configs.map { config -> config.state }) { states ->
-            val index = states.indexOfFirst { state -> state is State.Visible }
-            val visibleState =
-                if (index != -1) {
-                    states[index] as State.Visible
-                } else {
-                    null
-                }
-            if (visibleState != null) {
-                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/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
index 62cf1a6..e52d9ee 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
@@ -18,7 +18,7 @@
 
 import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
-import com.android.systemui.common.data.model.Position
+import com.android.systemui.common.shared.model.Position
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.statusbar.policy.KeyguardStateController
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
index 1a5670c..d15d7f2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
@@ -16,22 +16,10 @@
 
 package com.android.systemui.keyguard.data.repository
 
-import com.android.systemui.keyguard.data.config.KeyguardQuickAffordanceConfigs
-import com.android.systemui.keyguard.data.config.KeyguardQuickAffordanceConfigsImpl
 import dagger.Binds
 import dagger.Module
 
 @Module
 interface KeyguardRepositoryModule {
     @Binds fun keyguardRepository(impl: KeyguardRepositoryImpl): KeyguardRepository
-
-    @Binds
-    fun keyguardQuickAffordanceRepository(
-        impl: KeyguardQuickAffordanceRepositoryImpl
-    ): KeyguardQuickAffordanceRepository
-
-    @Binds
-    fun keyguardQuickAffordanceConfigs(
-        impl: KeyguardQuickAffordanceConfigsImpl
-    ): KeyguardQuickAffordanceConfigs
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBottomAreaInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBottomAreaInteractor.kt
new file mode 100644
index 0000000..ede50b0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBottomAreaInteractor.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.keyguard.domain.interactor
+
+import com.android.systemui.common.shared.model.Position
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.data.repository.KeyguardRepository
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+
+/** Encapsulates business-logic specifically related to the keyguard bottom area. */
+@SysUISingleton
+class KeyguardBottomAreaInteractor
+@Inject
+constructor(
+    private val repository: KeyguardRepository,
+) {
+    /** Whether to animate the next doze mode transition. */
+    val animateDozingTransitions: Flow<Boolean> = repository.animateBottomAreaDozingTransitions
+    /** The amount of alpha for the UI components of the bottom area. */
+    val alpha: Flow<Float> = repository.bottomAreaAlpha
+    /** The position of the keyguard clock. */
+    val clockPosition: Flow<Position> = repository.clockPosition
+
+    fun setClockPosition(x: Int, y: Int) {
+        repository.setClockPosition(x, y)
+    }
+
+    fun setAlpha(alpha: Float) {
+        repository.setBottomAreaAlpha(alpha)
+    }
+
+    fun setAnimateDozingTransitions(animate: Boolean) {
+        repository.setAnimateDozingTransitions(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
new file mode 100644
index 0000000..dccc941
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.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.keyguard.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.data.repository.KeyguardRepository
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+
+/**
+ * Encapsulates business-logic related to the keyguard but not to a more specific part within it.
+ */
+@SysUISingleton
+class KeyguardInteractor
+@Inject
+constructor(
+    repository: KeyguardRepository,
+) {
+    /**
+     * The amount of doze the system is in, where `1.0` is fully dozing and `0.0` is not dozing at
+     * all.
+     */
+    val dozeAmount: Flow<Float> = repository.dozeAmount
+    /** Whether the system is in doze mode. */
+    val isDozing: Flow<Boolean> = repository.isDozing
+    /** Whether the keyguard is showing ot not. */
+    val isKeyguardShowing: Flow<Boolean> = 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
new file mode 100644
index 0000000..9a69e26
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
@@ -0,0 +1,136 @@
+/*
+ *  Copyright (C) 2022 The Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyguard.domain.interactor
+
+import android.content.Intent
+import com.android.internal.widget.LockPatternUtils
+import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordanceModel
+import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordancePosition
+import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceConfig
+import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceRegistry
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import javax.inject.Inject
+import kotlin.reflect.KClass
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+
+@SysUISingleton
+class KeyguardQuickAffordanceInteractor
+@Inject
+constructor(
+    private val keyguardInteractor: KeyguardInteractor,
+    private val registry: KeyguardQuickAffordanceRegistry<out KeyguardQuickAffordanceConfig>,
+    private val lockPatternUtils: LockPatternUtils,
+    private val keyguardStateController: KeyguardStateController,
+    private val userTracker: UserTracker,
+    private val activityStarter: ActivityStarter,
+) {
+    /** Returns an observable for the quick affordance at the given position. */
+    fun quickAffordance(
+        position: KeyguardQuickAffordancePosition
+    ): Flow<KeyguardQuickAffordanceModel> {
+        return combine(
+            quickAffordanceInternal(position),
+            keyguardInteractor.isDozing,
+            keyguardInteractor.isKeyguardShowing,
+        ) { affordance, isDozing, isKeyguardShowing ->
+            if (!isDozing && isKeyguardShowing) {
+                affordance
+            } else {
+                KeyguardQuickAffordanceModel.Hidden
+            }
+        }
+    }
+
+    /**
+     * Notifies that a quick affordance has been clicked by the user.
+     *
+     * @param configKey The configuration key corresponding to the [KeyguardQuickAffordanceModel] of
+     * the affordance that was clicked
+     * @param animationController An optional controller for the activity-launch animation
+     */
+    fun onQuickAffordanceClicked(
+        configKey: KClass<out KeyguardQuickAffordanceConfig>,
+        animationController: ActivityLaunchAnimator.Controller?,
+    ) {
+        @Suppress("UNCHECKED_CAST") val config = registry.get(configKey as KClass<Nothing>)
+        when (val result = config.onQuickAffordanceClicked(animationController)) {
+            is KeyguardQuickAffordanceConfig.OnClickedResult.StartActivity ->
+                launchQuickAffordance(
+                    intent = result.intent,
+                    canShowWhileLocked = result.canShowWhileLocked,
+                    animationController = animationController
+                )
+            is KeyguardQuickAffordanceConfig.OnClickedResult.Handled -> Unit
+        }
+    }
+
+    private fun quickAffordanceInternal(
+        position: KeyguardQuickAffordancePosition
+    ): Flow<KeyguardQuickAffordanceModel> {
+        val configs = registry.getAll(position)
+        return combine(configs.map { config -> config.state }) { states ->
+            val index = states.indexOfFirst { it is KeyguardQuickAffordanceConfig.State.Visible }
+            if (index != -1) {
+                val visibleState = states[index] as KeyguardQuickAffordanceConfig.State.Visible
+                KeyguardQuickAffordanceModel.Visible(
+                    configKey = configs[index]::class,
+                    icon = visibleState.icon,
+                    contentDescriptionResourceId = visibleState.contentDescriptionResourceId,
+                )
+            } else {
+                KeyguardQuickAffordanceModel.Hidden
+            }
+        }
+    }
+
+    private fun launchQuickAffordance(
+        intent: Intent,
+        canShowWhileLocked: Boolean,
+        animationController: ActivityLaunchAnimator.Controller?,
+    ) {
+        @LockPatternUtils.StrongAuthTracker.StrongAuthFlags
+        val strongAuthFlags =
+            lockPatternUtils.getStrongAuthForUser(userTracker.userHandle.identifier)
+        val needsToUnlockFirst =
+            when {
+                strongAuthFlags ==
+                    LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT -> true
+                !canShowWhileLocked && !keyguardStateController.isUnlocked -> true
+                else -> false
+            }
+        if (needsToUnlockFirst) {
+            activityStarter.postStartActivityDismissingKeyguard(
+                intent,
+                0 /* delay */,
+                animationController
+            )
+        } else {
+            activityStarter.startActivity(
+                intent,
+                true /* dismissShade */,
+                animationController,
+                true /* showOverLockscreenWhenLocked */,
+            )
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardQuickAffordanceModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/model/KeyguardQuickAffordanceModel.kt
similarity index 91%
rename from packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardQuickAffordanceModel.kt
rename to packages/SystemUI/src/com/android/systemui/keyguard/domain/model/KeyguardQuickAffordanceModel.kt
index 09785df..eff1469 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardQuickAffordanceModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/model/KeyguardQuickAffordanceModel.kt
@@ -15,11 +15,11 @@
  *
  */
 
-package com.android.systemui.keyguard.shared.model
+package com.android.systemui.keyguard.domain.model
 
 import androidx.annotation.StringRes
 import com.android.systemui.containeddrawable.ContainedDrawable
-import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig
+import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceConfig
 import kotlin.reflect.KClass
 
 /**
@@ -27,7 +27,6 @@
  * lock-screen).
  */
 sealed class KeyguardQuickAffordanceModel {
-
     /** No affordance should show up. */
     object Hidden : KeyguardQuickAffordanceModel()
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardQuickAffordancePosition.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/model/KeyguardQuickAffordancePosition.kt
similarity index 93%
rename from packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardQuickAffordancePosition.kt
rename to packages/SystemUI/src/com/android/systemui/keyguard/domain/model/KeyguardQuickAffordancePosition.kt
index b71e15d..581dafa3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardQuickAffordancePosition.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/model/KeyguardQuickAffordancePosition.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.keyguard.shared.model
+package com.android.systemui.keyguard.domain.model
 
 /** Enumerates all possible positions for quick affordances that can appear on the lock-screen. */
 enum class KeyguardQuickAffordancePosition {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
similarity index 91%
rename from packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
rename to packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
index 3202ecb..8f32ff9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
@@ -15,7 +15,7 @@
  *
  */
 
-package com.android.systemui.keyguard.data.quickaffordance
+package com.android.systemui.keyguard.domain.quickaffordance
 
 import android.content.Context
 import android.content.Intent
@@ -36,6 +36,7 @@
 import javax.inject.Inject
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flatMapLatest
 import kotlinx.coroutines.flow.flowOf
 
 /** Home controls quick affordance data source. */
@@ -50,7 +51,13 @@
     private val appContext = context.applicationContext
 
     override val state: Flow<KeyguardQuickAffordanceConfig.State> =
-        stateInternal(component.getControlsListingController().getOrNull())
+        component.canShowWhileLockedSetting.flatMapLatest { canShowWhileLocked ->
+            if (canShowWhileLocked) {
+                stateInternal(component.getControlsListingController().getOrNull())
+            } else {
+                flowOf(KeyguardQuickAffordanceConfig.State.Hidden)
+            }
+        }
 
     override fun onQuickAffordanceClicked(
         animationController: ActivityLaunchAnimator.Controller?,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/KeyguardQuickAffordanceConfig.kt
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfig.kt
rename to packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/KeyguardQuickAffordanceConfig.kt
index 67a776e..8fb952c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/KeyguardQuickAffordanceConfig.kt
@@ -15,7 +15,7 @@
  *
  */
 
-package com.android.systemui.keyguard.data.quickaffordance
+package com.android.systemui.keyguard.domain.quickaffordance
 
 import android.content.Intent
 import androidx.annotation.StringRes
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/KeyguardQuickAffordanceModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/KeyguardQuickAffordanceModule.kt
new file mode 100644
index 0000000..94024d4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/KeyguardQuickAffordanceModule.kt
@@ -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 com.android.systemui.keyguard.domain.quickaffordance
+
+import dagger.Binds
+import dagger.Module
+
+@Module
+interface KeyguardQuickAffordanceModule {
+    @Binds
+    fun keyguardQuickAffordanceRegistry(
+        impl: KeyguardQuickAffordanceRegistryImpl
+    ): KeyguardQuickAffordanceRegistry<out KeyguardQuickAffordanceConfig>
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceConfigs.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/KeyguardQuickAffordanceRegistry.kt
similarity index 68%
rename from packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceConfigs.kt
rename to packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/KeyguardQuickAffordanceRegistry.kt
index 7164215..ad40ee7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceConfigs.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/KeyguardQuickAffordanceRegistry.kt
@@ -15,29 +15,25 @@
  *
  */
 
-package com.android.systemui.keyguard.data.config
+package com.android.systemui.keyguard.domain.quickaffordance
 
-import com.android.systemui.keyguard.data.quickaffordance.HomeControlsKeyguardQuickAffordanceConfig
-import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig
-import com.android.systemui.keyguard.data.quickaffordance.QrCodeScannerKeyguardQuickAffordanceConfig
-import com.android.systemui.keyguard.data.quickaffordance.QuickAccessWalletKeyguardQuickAffordanceConfig
-import com.android.systemui.keyguard.shared.model.KeyguardQuickAffordancePosition
+import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordancePosition
 import javax.inject.Inject
 import kotlin.reflect.KClass
 
-/** Injectable provider of the positioning of the known quick affordance configs. */
-interface KeyguardQuickAffordanceConfigs {
-    fun getAll(position: KeyguardQuickAffordancePosition): List<KeyguardQuickAffordanceConfig>
-    fun get(configClass: KClass<out KeyguardQuickAffordanceConfig>): KeyguardQuickAffordanceConfig
+/** Central registry of all known quick affordance configs. */
+interface KeyguardQuickAffordanceRegistry<T : KeyguardQuickAffordanceConfig> {
+    fun getAll(position: KeyguardQuickAffordancePosition): List<T>
+    fun get(configClass: KClass<out T>): T
 }
 
-class KeyguardQuickAffordanceConfigsImpl
+class KeyguardQuickAffordanceRegistryImpl
 @Inject
 constructor(
     homeControls: HomeControlsKeyguardQuickAffordanceConfig,
     quickAccessWallet: QuickAccessWalletKeyguardQuickAffordanceConfig,
     qrCodeScanner: QrCodeScannerKeyguardQuickAffordanceConfig,
-) : KeyguardQuickAffordanceConfigs {
+) : KeyguardQuickAffordanceRegistry<KeyguardQuickAffordanceConfig> {
     private val configsByPosition =
         mapOf(
             KeyguardQuickAffordancePosition.BOTTOM_START to
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt
rename to packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt
index ea6497e..c8e5e4a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt
@@ -15,7 +15,7 @@
  *
  */
 
-package com.android.systemui.keyguard.data.quickaffordance
+package com.android.systemui.keyguard.domain.quickaffordance
 
 import com.android.systemui.R
 import com.android.systemui.animation.ActivityLaunchAnimator
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
rename to packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
index cc5a997..885af33 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
@@ -15,7 +15,7 @@
  *
  */
 
-package com.android.systemui.keyguard.data.quickaffordance
+package com.android.systemui.keyguard.domain.quickaffordance
 
 import android.graphics.drawable.Drawable
 import android.service.quickaccesswallet.GetWalletCardsError
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/KeyguardUseCaseModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/KeyguardUseCaseModule.kt
deleted file mode 100644
index c44c2c9..0000000
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/KeyguardUseCaseModule.kt
+++ /dev/null
@@ -1,29 +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.keyguard.domain.usecase
-
-import dagger.Binds
-import dagger.Module
-
-@Module
-interface KeyguardUseCaseModule {
-
-    @Binds
-    fun launchQuickAffordance(
-        impl: LaunchKeyguardQuickAffordanceUseCaseImpl
-    ): LaunchKeyguardQuickAffordanceUseCase
-}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/LaunchKeyguardQuickAffordanceUseCase.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/LaunchKeyguardQuickAffordanceUseCase.kt
deleted file mode 100644
index 3d60399..0000000
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/LaunchKeyguardQuickAffordanceUseCase.kt
+++ /dev/null
@@ -1,76 +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.keyguard.domain.usecase
-
-import android.content.Intent
-import com.android.internal.widget.LockPatternUtils
-import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.StrongAuthFlags
-import com.android.systemui.animation.ActivityLaunchAnimator
-import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.settings.UserTracker
-import com.android.systemui.statusbar.policy.KeyguardStateController
-import javax.inject.Inject
-
-/** Defines interface for classes that can launch a quick affordance. */
-interface LaunchKeyguardQuickAffordanceUseCase {
-    operator fun invoke(
-        intent: Intent,
-        canShowWhileLocked: Boolean,
-        animationController: ActivityLaunchAnimator.Controller?,
-    )
-}
-
-/** Real implementation of [LaunchKeyguardQuickAffordanceUseCase] */
-class LaunchKeyguardQuickAffordanceUseCaseImpl
-@Inject
-constructor(
-    private val lockPatternUtils: LockPatternUtils,
-    private val keyguardStateController: KeyguardStateController,
-    private val userTracker: UserTracker,
-    private val activityStarter: ActivityStarter,
-) : LaunchKeyguardQuickAffordanceUseCase {
-    override operator fun invoke(
-        intent: Intent,
-        canShowWhileLocked: Boolean,
-        animationController: ActivityLaunchAnimator.Controller?,
-    ) {
-        @StrongAuthFlags
-        val strongAuthFlags =
-            lockPatternUtils.getStrongAuthForUser(userTracker.userHandle.identifier)
-        val needsToUnlockFirst =
-            when {
-                strongAuthFlags ==
-                    LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT -> true
-                !canShowWhileLocked && !keyguardStateController.isUnlocked -> true
-                else -> false
-            }
-        if (needsToUnlockFirst) {
-            activityStarter.postStartActivityDismissingKeyguard(
-                intent,
-                0 /* delay */,
-                animationController
-            )
-        } else {
-            activityStarter.startActivity(
-                intent,
-                true /* dismissShade */,
-                animationController,
-                true /* showOverLockscreenWhenLocked */,
-            )
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/ObserveAnimateBottomAreaTransitionsUseCase.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/ObserveAnimateBottomAreaTransitionsUseCase.kt
deleted file mode 100644
index ca37727..0000000
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/ObserveAnimateBottomAreaTransitionsUseCase.kt
+++ /dev/null
@@ -1,32 +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.keyguard.domain.usecase
-
-import com.android.systemui.keyguard.data.repository.KeyguardRepository
-import javax.inject.Inject
-import kotlinx.coroutines.flow.Flow
-
-/** Use-case for observing whether doze state transitions should animate the bottom area */
-class ObserveAnimateBottomAreaTransitionsUseCase
-@Inject
-constructor(
-    private val repository: KeyguardRepository,
-) {
-    operator fun invoke(): Flow<Boolean> {
-        return repository.animateBottomAreaDozingTransitions
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/ObserveBottomAreaAlphaUseCase.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/ObserveBottomAreaAlphaUseCase.kt
deleted file mode 100644
index 151b704..0000000
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/ObserveBottomAreaAlphaUseCase.kt
+++ /dev/null
@@ -1,32 +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.keyguard.domain.usecase
-
-import com.android.systemui.keyguard.data.repository.KeyguardRepository
-import javax.inject.Inject
-import kotlinx.coroutines.flow.Flow
-
-/** Use-case for observing the alpha of the bottom area */
-class ObserveBottomAreaAlphaUseCase
-@Inject
-constructor(
-    private val repository: KeyguardRepository,
-) {
-    operator fun invoke(): Flow<Float> {
-        return repository.bottomAreaAlpha
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/ObserveClockPositionUseCase.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/ObserveClockPositionUseCase.kt
deleted file mode 100644
index 02c5737..0000000
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/ObserveClockPositionUseCase.kt
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.keyguard.domain.usecase
-
-import com.android.systemui.common.domain.model.Position
-import com.android.systemui.common.domain.model.Position.Companion.toDomainLayer
-import com.android.systemui.keyguard.data.repository.KeyguardRepository
-import javax.inject.Inject
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.map
-
-/** Use-case for observing the position of the clock. */
-class ObserveClockPositionUseCase
-@Inject
-constructor(
-    private val repository: KeyguardRepository,
-) {
-    operator fun invoke(): Flow<Position> {
-        return repository.clockPosition.map { it.toDomainLayer() }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/ObserveDozeAmountUseCase.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/ObserveDozeAmountUseCase.kt
deleted file mode 100644
index 56d6182..0000000
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/ObserveDozeAmountUseCase.kt
+++ /dev/null
@@ -1,32 +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.keyguard.domain.usecase
-
-import com.android.systemui.keyguard.data.repository.KeyguardRepository
-import javax.inject.Inject
-import kotlinx.coroutines.flow.Flow
-
-/** Use-case for observing the amount of doze the system is in. */
-class ObserveDozeAmountUseCase
-@Inject
-constructor(
-    private val repository: KeyguardRepository,
-) {
-    operator fun invoke(): Flow<Float> {
-        return repository.dozeAmount
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/ObserveIsDozingUseCase.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/ObserveIsDozingUseCase.kt
deleted file mode 100644
index 1d241d9..0000000
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/ObserveIsDozingUseCase.kt
+++ /dev/null
@@ -1,32 +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.keyguard.domain.usecase
-
-import com.android.systemui.keyguard.data.repository.KeyguardRepository
-import javax.inject.Inject
-import kotlinx.coroutines.flow.Flow
-
-/** Use-case for observing whether we are dozing. */
-class ObserveIsDozingUseCase
-@Inject
-constructor(
-    private val repository: KeyguardRepository,
-) {
-    operator fun invoke(): Flow<Boolean> {
-        return repository.isDozing
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/ObserveIsKeyguardShowingUseCase.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/ObserveIsKeyguardShowingUseCase.kt
deleted file mode 100644
index 11af123..0000000
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/ObserveIsKeyguardShowingUseCase.kt
+++ /dev/null
@@ -1,39 +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.keyguard.domain.usecase
-
-import com.android.systemui.keyguard.data.repository.KeyguardRepository
-import javax.inject.Inject
-import kotlinx.coroutines.flow.Flow
-
-/**
- * Use-case for observing whether the keyguard is currently being shown.
- *
- * 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").
- */
-class ObserveIsKeyguardShowingUseCase
-@Inject
-constructor(
-    private val repository: KeyguardRepository,
-) {
-    operator fun invoke(): Flow<Boolean> {
-        return repository.isKeyguardShowing
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/ObserveKeyguardQuickAffordanceUseCase.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/ObserveKeyguardQuickAffordanceUseCase.kt
deleted file mode 100644
index eef8ec3..0000000
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/ObserveKeyguardQuickAffordanceUseCase.kt
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.keyguard.domain.usecase
-
-import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
-import com.android.systemui.keyguard.shared.model.KeyguardQuickAffordanceModel
-import com.android.systemui.keyguard.shared.model.KeyguardQuickAffordancePosition
-import javax.inject.Inject
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.combine
-
-/** Use-case for observing the model of a quick affordance in the keyguard. */
-class ObserveKeyguardQuickAffordanceUseCase
-@Inject
-constructor(
-    private val repository: KeyguardQuickAffordanceRepository,
-    private val isDozingUseCase: ObserveIsDozingUseCase,
-    private val isKeyguardShowingUseCase: ObserveIsKeyguardShowingUseCase,
-) {
-    operator fun invoke(
-        position: KeyguardQuickAffordancePosition
-    ): Flow<KeyguardQuickAffordanceModel> {
-        return combine(
-            repository.affordance(position),
-            isDozingUseCase(),
-            isKeyguardShowingUseCase(),
-        ) { affordance, isDozing, isKeyguardShowing ->
-            if (!isDozing && isKeyguardShowing) {
-                affordance
-            } else {
-                KeyguardQuickAffordanceModel.Hidden
-            }
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/OnKeyguardQuickAffordanceClickedUseCase.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/OnKeyguardQuickAffordanceClickedUseCase.kt
deleted file mode 100644
index f8db90f..0000000
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/OnKeyguardQuickAffordanceClickedUseCase.kt
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.keyguard.domain.usecase
-
-import com.android.systemui.animation.ActivityLaunchAnimator
-import com.android.systemui.keyguard.data.config.KeyguardQuickAffordanceConfigs
-import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig
-import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.OnClickedResult
-import javax.inject.Inject
-import kotlin.reflect.KClass
-
-/** Use-case for handling a click on a keyguard quick affordance (e.g. bottom button). */
-class OnKeyguardQuickAffordanceClickedUseCase
-@Inject
-constructor(
-    private val configs: KeyguardQuickAffordanceConfigs,
-    private val launchAffordanceUseCase: LaunchKeyguardQuickAffordanceUseCase,
-) {
-    operator fun invoke(
-        configKey: KClass<*>,
-        animationController: ActivityLaunchAnimator.Controller?,
-    ) {
-        @Suppress("UNCHECKED_CAST")
-        val config = configs.get(configKey as KClass<out KeyguardQuickAffordanceConfig>)
-        when (val result = config.onQuickAffordanceClicked(animationController)) {
-            is OnClickedResult.StartActivity ->
-                launchAffordanceUseCase(
-                    intent = result.intent,
-                    canShowWhileLocked = result.canShowWhileLocked,
-                    animationController = animationController
-                )
-            is OnClickedResult.Handled -> Unit
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/SetClockPositionUseCase.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/SetClockPositionUseCase.kt
deleted file mode 100644
index 8f746e5..0000000
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/SetClockPositionUseCase.kt
+++ /dev/null
@@ -1,31 +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.keyguard.domain.usecase
-
-import com.android.systemui.keyguard.data.repository.KeyguardRepository
-import javax.inject.Inject
-
-/** Use-case for setting the updated clock position. */
-class SetClockPositionUseCase
-@Inject
-constructor(
-    private val keyguardRepository: KeyguardRepository,
-) {
-    operator fun invoke(x: Int, y: Int) {
-        keyguardRepository.setClockPosition(x, y)
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/SetKeyguardBottomAreaAlphaUseCase.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/SetKeyguardBottomAreaAlphaUseCase.kt
deleted file mode 100644
index 90be1ec..0000000
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/SetKeyguardBottomAreaAlphaUseCase.kt
+++ /dev/null
@@ -1,31 +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.keyguard.domain.usecase
-
-import com.android.systemui.keyguard.data.repository.KeyguardRepository
-import javax.inject.Inject
-
-/** Use-case for setting the alpha that the keyguard bottom area should use */
-class SetKeyguardBottomAreaAlphaUseCase
-@Inject
-constructor(
-    private val repository: KeyguardRepository,
-) {
-    operator fun invoke(alpha: Float) {
-        repository.setBottomAreaAlpha(alpha)
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/SetKeyguardBottomAreaAnimateDozingTransitionsUseCase.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/SetKeyguardBottomAreaAnimateDozingTransitionsUseCase.kt
deleted file mode 100644
index 007780a..0000000
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/usecase/SetKeyguardBottomAreaAnimateDozingTransitionsUseCase.kt
+++ /dev/null
@@ -1,33 +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.keyguard.domain.usecase
-
-import com.android.systemui.keyguard.data.repository.KeyguardRepository
-import javax.inject.Inject
-
-/**
- * Use-case for setting whether the keyguard bottom area should animate the next doze transitions
- */
-class SetKeyguardBottomAreaAnimateDozingTransitionsUseCase
-@Inject
-constructor(
-    private val repository: KeyguardRepository,
-) {
-    operator fun invoke(animate: Boolean) {
-        repository.setAnimateDozingTransitions(animate)
-    }
-}
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 04d30bf..19c6249 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
@@ -95,35 +95,23 @@
         view.repeatWhenAttached {
             repeatOnLifecycle(Lifecycle.State.STARTED) {
                 launch {
-                    combine(viewModel.startButton, viewModel.animateButtonReveal) {
-                            buttonModel,
-                            animateReveal ->
-                            Pair(buttonModel, animateReveal)
-                        }
-                        .collect { (buttonModel, animateReveal) ->
-                            updateButton(
-                                view = startButton,
-                                viewModel = buttonModel,
-                                animateReveal = animateReveal,
-                                falsingManager = falsingManager,
-                            )
-                        }
+                    viewModel.startButton.collect { buttonModel ->
+                        updateButton(
+                            view = startButton,
+                            viewModel = buttonModel,
+                            falsingManager = falsingManager,
+                        )
+                    }
                 }
 
                 launch {
-                    combine(viewModel.endButton, viewModel.animateButtonReveal) {
-                            buttonModel,
-                            animateReveal ->
-                            Pair(buttonModel, animateReveal)
-                        }
-                        .collect { (buttonModel, animateReveal) ->
-                            updateButton(
-                                view = endButton,
-                                viewModel = buttonModel,
-                                animateReveal = animateReveal,
-                                falsingManager = falsingManager,
-                            )
-                        }
+                    viewModel.endButton.collect { buttonModel ->
+                        updateButton(
+                            view = endButton,
+                            viewModel = buttonModel,
+                            falsingManager = falsingManager,
+                        )
+                    }
                 }
 
                 launch {
@@ -226,7 +214,6 @@
     private fun updateButton(
         view: ImageView,
         viewModel: KeyguardQuickAffordanceViewModel,
-        animateReveal: Boolean,
         falsingManager: FalsingManager,
     ) {
         if (!viewModel.isVisible) {
@@ -236,7 +223,7 @@
 
         if (!view.isVisible) {
             view.isVisible = true
-            if (animateReveal) {
+            if (viewModel.animateReveal) {
                 view.alpha = 0f
                 view.translationY = view.height / 2f
                 view
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 4b69a81..01d5e5c 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
@@ -17,15 +17,11 @@
 package com.android.systemui.keyguard.ui.viewmodel
 
 import com.android.systemui.doze.util.BurnInHelperWrapper
-import com.android.systemui.keyguard.domain.usecase.ObserveAnimateBottomAreaTransitionsUseCase
-import com.android.systemui.keyguard.domain.usecase.ObserveBottomAreaAlphaUseCase
-import com.android.systemui.keyguard.domain.usecase.ObserveClockPositionUseCase
-import com.android.systemui.keyguard.domain.usecase.ObserveDozeAmountUseCase
-import com.android.systemui.keyguard.domain.usecase.ObserveIsDozingUseCase
-import com.android.systemui.keyguard.domain.usecase.ObserveKeyguardQuickAffordanceUseCase
-import com.android.systemui.keyguard.domain.usecase.OnKeyguardQuickAffordanceClickedUseCase
-import com.android.systemui.keyguard.shared.model.KeyguardQuickAffordanceModel
-import com.android.systemui.keyguard.shared.model.KeyguardQuickAffordancePosition
+import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor
+import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordanceModel
+import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordancePosition
 import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.combine
@@ -36,13 +32,9 @@
 class KeyguardBottomAreaViewModel
 @Inject
 constructor(
-    private val observeQuickAffordanceUseCase: ObserveKeyguardQuickAffordanceUseCase,
-    private val onQuickAffordanceClickedUseCase: OnKeyguardQuickAffordanceClickedUseCase,
-    observeBottomAreaAlphaUseCase: ObserveBottomAreaAlphaUseCase,
-    observeIsDozingUseCase: ObserveIsDozingUseCase,
-    observeAnimateBottomAreaTransitionsUseCase: ObserveAnimateBottomAreaTransitionsUseCase,
-    private val observeDozeAmountUseCase: ObserveDozeAmountUseCase,
-    observeClockPositionUseCase: ObserveClockPositionUseCase,
+    private val keyguardInteractor: KeyguardInteractor,
+    private val quickAffordanceInteractor: KeyguardQuickAffordanceInteractor,
+    private val bottomAreaInteractor: KeyguardBottomAreaInteractor,
     private val burnInHelperWrapper: BurnInHelperWrapper,
 ) {
     /** An observable for the view-model of the "start button" quick affordance. */
@@ -51,17 +43,11 @@
     /** An observable for the view-model of the "end button" quick affordance. */
     val endButton: Flow<KeyguardQuickAffordanceViewModel> =
         button(KeyguardQuickAffordancePosition.BOTTOM_END)
-    /**
-     * An observable for whether the next time a quick action button becomes visible, it should
-     * animate.
-     */
-    val animateButtonReveal: Flow<Boolean> =
-        observeAnimateBottomAreaTransitionsUseCase().distinctUntilChanged()
     /** An observable for whether the overlay container should be visible. */
     val isOverlayContainerVisible: Flow<Boolean> =
-        observeIsDozingUseCase().map { !it }.distinctUntilChanged()
+        keyguardInteractor.isDozing.map { !it }.distinctUntilChanged()
     /** An observable for the alpha level for the entire bottom area. */
-    val alpha: Flow<Float> = observeBottomAreaAlphaUseCase().distinctUntilChanged()
+    val alpha: Flow<Float> = bottomAreaInteractor.alpha.distinctUntilChanged()
     /** An observable for whether the indication area should be padded. */
     val isIndicationAreaPadded: Flow<Boolean> =
         combine(startButton, endButton) { startButtonModel, endButtonModel ->
@@ -70,11 +56,11 @@
             .distinctUntilChanged()
     /** An observable for the x-offset by which the indication area should be translated. */
     val indicationAreaTranslationX: Flow<Float> =
-        observeClockPositionUseCase().map { it.x.toFloat() }.distinctUntilChanged()
+        bottomAreaInteractor.clockPosition.map { it.x.toFloat() }.distinctUntilChanged()
 
     /** Returns an observable for the y-offset by which the indication area should be translated. */
     fun indicationAreaTranslationY(defaultBurnInOffset: Int): Flow<Float> {
-        return observeDozeAmountUseCase()
+        return keyguardInteractor.dozeAmount
             .map { dozeAmount ->
                 dozeAmount *
                     (burnInHelperWrapper.burnInOffset(
@@ -88,21 +74,28 @@
     private fun button(
         position: KeyguardQuickAffordancePosition
     ): Flow<KeyguardQuickAffordanceViewModel> {
-        return observeQuickAffordanceUseCase(position)
-            .map { model -> model.toViewModel() }
+        return combine(
+                quickAffordanceInteractor.quickAffordance(position),
+                bottomAreaInteractor.animateDozingTransitions.distinctUntilChanged(),
+            ) { model, animateReveal ->
+                model.toViewModel(animateReveal)
+            }
             .distinctUntilChanged()
     }
 
-    private fun KeyguardQuickAffordanceModel.toViewModel(): KeyguardQuickAffordanceViewModel {
+    private fun KeyguardQuickAffordanceModel.toViewModel(
+        animateReveal: Boolean,
+    ): KeyguardQuickAffordanceViewModel {
         return when (this) {
             is KeyguardQuickAffordanceModel.Visible ->
                 KeyguardQuickAffordanceViewModel(
                     configKey = configKey,
                     isVisible = true,
+                    animateReveal = animateReveal,
                     icon = icon,
                     contentDescriptionResourceId = contentDescriptionResourceId,
                     onClicked = { parameters ->
-                        onQuickAffordanceClickedUseCase(
+                        quickAffordanceInteractor.onQuickAffordanceClicked(
                             configKey = parameters.configKey,
                             animationController = parameters.animationController,
                         )
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 2417998..985ab62 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
@@ -19,18 +19,21 @@
 import androidx.annotation.StringRes
 import com.android.systemui.animation.ActivityLaunchAnimator
 import com.android.systemui.containeddrawable.ContainedDrawable
+import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceConfig
 import kotlin.reflect.KClass
 
 /** Models the UI state of a keyguard quick affordance button. */
 data class KeyguardQuickAffordanceViewModel(
-    val configKey: KClass<*>? = null,
+    val configKey: KClass<out KeyguardQuickAffordanceConfig>? = null,
     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 onClicked: (OnClickedParameters) -> Unit = {},
 ) {
     data class OnClickedParameters(
-        val configKey: KClass<*>,
+        val configKey: KClass<out KeyguardQuickAffordanceConfig>,
         val animationController: ActivityLaunchAnimator.Controller?,
     )
 }
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt
index 81efdf5..e0c8d66 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt
@@ -266,11 +266,11 @@
     }
 
     /**
-     * Are there any media notifications active, including the recommendation?
+     * Are there any active media entries, including the recommendation?
      */
-    fun hasActiveMediaOrRecommendation() =
-            userEntries.any { it.value.active } ||
-                    (smartspaceMediaData.isActive && smartspaceMediaData.isValid())
+    fun hasActiveMediaOrRecommendation() = userEntries.any { it.value.active } ||
+            (smartspaceMediaData.isActive &&
+                (smartspaceMediaData.isValid() || reactivatedKey != null))
 
     /**
      * Are there any media entries we should display?
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 8757904..00b0ff9 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
@@ -68,7 +68,7 @@
                     .addFeature("feature")
             val useAppIcon = !(args.size >= 3 && args[2] == "useAppIcon=false")
             if (useAppIcon) {
-                routeInfo.setPackageName(TEST_PACKAGE_NAME)
+                routeInfo.setClientPackageName(TEST_PACKAGE_NAME)
             }
 
             statusBarManager.updateMediaTapToTransferSenderDisplay(
@@ -134,7 +134,7 @@
                 .addFeature("feature")
             val useAppIcon = !(args.size >= 2 && args[1] == "useAppIcon=false")
             if (useAppIcon) {
-                routeInfo.setPackageName(TEST_PACKAGE_NAME)
+                routeInfo.setClientPackageName(TEST_PACKAGE_NAME)
             }
 
             statusBarManager.updateMediaTapToTransferReceiverDisplay(
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
index 5f478ce..9ab83b8 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
@@ -56,7 +56,7 @@
         internal val logger: MediaTttLogger,
         internal val windowManager: WindowManager,
         private val viewUtil: ViewUtil,
-        @Main private val mainExecutor: DelayableExecutor,
+        @Main internal val mainExecutor: DelayableExecutor,
         private val accessibilityManager: AccessibilityManager,
         private val configurationController: ConfigurationController,
         private val powerManager: PowerManager,
@@ -205,13 +205,15 @@
      *
      * @param appPackageName the package name of the app playing the media. Will be used to fetch
      *   the app icon and app name if overrides aren't provided.
+     *
+     * @return the content description of the icon.
      */
     internal fun setIcon(
         currentChipView: ViewGroup,
         appPackageName: String?,
         appIconDrawableOverride: Drawable? = null,
         appNameOverride: CharSequence? = null,
-    ) {
+    ): CharSequence {
         val appIconView = currentChipView.requireViewById<CachingIconView>(R.id.app_icon)
         val iconInfo = getIconInfo(appPackageName)
 
@@ -224,6 +226,7 @@
 
         appIconView.contentDescription = appNameOverride ?: iconInfo.iconName
         appIconView.setImageDrawable(appIconDrawableOverride ?: iconInfo.icon)
+        return appIconView.contentDescription.toString()
     }
 
     /**
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 0f1ae00..196ea22 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
@@ -143,7 +143,7 @@
         super.updateChipView(newChipInfo, currentChipView)
         setIcon(
                 currentChipView,
-                newChipInfo.routeInfo.packageName,
+                newChipInfo.routeInfo.clientPackageName,
                 newChipInfo.appIconDrawableOverride,
                 newChipInfo.appNameOverride
         )
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 3ea11b8..92d9ea8 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
@@ -122,13 +122,12 @@
         val chipState = newChipInfo.state
 
         // App icon
-        setIcon(currentChipView, newChipInfo.routeInfo.packageName)
+        val iconName = setIcon(currentChipView, newChipInfo.routeInfo.clientPackageName)
 
         // Text
         val otherDeviceName = newChipInfo.routeInfo.name.toString()
-        currentChipView.requireViewById<TextView>(R.id.text).apply {
-            text = chipState.getChipTextString(context, otherDeviceName)
-        }
+        val chipText = chipState.getChipTextString(context, otherDeviceName)
+        currentChipView.requireViewById<TextView>(R.id.text).text = chipText
 
         // Loading
         currentChipView.requireViewById<View>(R.id.loading).visibility =
@@ -145,17 +144,29 @@
         // Failure
         currentChipView.requireViewById<View>(R.id.failure_icon).visibility =
             chipState.isTransferFailure.visibleIfTrue()
+
+        // For accessibility
+        currentChipView.requireViewById<ViewGroup>(
+                R.id.media_ttt_sender_chip_inner
+        ).contentDescription = "$iconName $chipText"
     }
 
     override fun animateChipIn(chipView: ViewGroup) {
+        val chipInnerView = chipView.requireViewById<ViewGroup>(R.id.media_ttt_sender_chip_inner)
         ViewHierarchyAnimator.animateAddition(
-            chipView.requireViewById<ViewGroup>(R.id.media_ttt_sender_chip_inner),
+            chipInnerView,
             ViewHierarchyAnimator.Hotspot.TOP,
             Interpolators.EMPHASIZED_DECELERATE,
-            duration = 500L,
+            duration = ANIMATION_DURATION,
             includeMargins = true,
             includeFadeIn = true,
         )
+
+        // We can only request focus once the animation finishes.
+        mainExecutor.executeDelayed(
+                { chipInnerView.requestAccessibilityFocus() },
+                ANIMATION_DURATION
+        )
     }
 
     override fun removeChip(removalReason: String) {
@@ -186,3 +197,4 @@
 }
 
 const val SENDER_TAG = "MediaTapToTransferSender"
+private const val ANIMATION_DURATION = 500L
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
index d701f33..c790cfe 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.qs
 
 import android.content.Intent
+import android.content.res.Configuration
 import android.os.Handler
 import android.os.UserManager
 import android.provider.Settings
@@ -38,9 +39,11 @@
 import com.android.systemui.qs.dagger.QSScope
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.statusbar.phone.MultiUserSwitchController
+import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
 import com.android.systemui.statusbar.policy.UserInfoController
 import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener
+import com.android.systemui.util.LargeScreenUtils
 import com.android.systemui.util.ViewController
 import com.android.systemui.util.settings.GlobalSettings
 import javax.inject.Inject
@@ -69,18 +72,43 @@
     private val uiEventLogger: UiEventLogger,
     @Named(PM_LITE_ENABLED) private val showPMLiteButton: Boolean,
     private val globalSetting: GlobalSettings,
-    private val handler: Handler
+    private val handler: Handler,
+    private val configurationController: ConfigurationController,
 ) : ViewController<FooterActionsView>(view) {
 
     private var globalActionsDialog: GlobalActionsDialogLite? = null
 
     private var lastExpansion = -1f
     private var listening: Boolean = false
+    private var inSplitShade = false
 
-    private val alphaAnimator = TouchAnimator.Builder()
-            .addFloat(mView, "alpha", 0f, 1f)
-            .setStartDelay(0.9f)
+    private val singleShadeAnimator by lazy {
+        // In single shade, the actions footer should only appear at the end of the expansion,
+        // so that it doesn't overlap with the notifications panel.
+        TouchAnimator.Builder().addFloat(mView, "alpha", 0f, 1f).setStartDelay(0.9f).build()
+    }
+
+    private val splitShadeAnimator by lazy {
+        // The Actions footer view has its own background which is the same color as the qs panel's
+        // background.
+        // We don't want it to fade in at the same time as the rest of the panel, otherwise it is
+        // more opaque than the rest of the panel's background. Only applies to split shade.
+        val alphaAnimator = TouchAnimator.Builder().addFloat(mView, "alpha", 0f, 1f).build()
+        val bgAlphaAnimator =
+            TouchAnimator.Builder()
+                .addFloat(mView, "backgroundAlpha", 0f, 1f)
+                .setStartDelay(0.9f)
+                .build()
+        // In split shade, we want the actions footer to fade in exactly at the same time as the
+        // rest of the shade, as there is no overlap.
+        TouchAnimator.Builder()
+            .addFloat(alphaAnimator, "position", 0f, 1f)
+            .addFloat(bgAlphaAnimator, "position", 0f, 1f)
             .build()
+    }
+
+    private val animators: TouchAnimator
+        get() = if (inSplitShade) splitShadeAnimator else singleShadeAnimator
 
     var visible = true
         set(value) {
@@ -95,9 +123,7 @@
     private val multiUserSwitchController = multiUserSwitchControllerFactory.create(view)
 
     @VisibleForTesting
-    internal val securityFootersSeparator = View(context).apply {
-        visibility = View.GONE
-    }
+    internal val securityFootersSeparator = View(context).apply { visibility = View.GONE }
 
     private val onUserInfoChangedListener = OnUserInfoChangedListener { _, picture, _ ->
         val isGuestUser: Boolean = userManager.isGuestUser(KeyguardUpdateMonitor.getCurrentUser())
@@ -133,6 +159,17 @@
         }
     }
 
+    private val configurationListener =
+        object : ConfigurationController.ConfigurationListener {
+            override fun onConfigChanged(newConfig: Configuration?) {
+                updateResources()
+            }
+        }
+
+    private fun updateResources() {
+        inSplitShade = LargeScreenUtils.shouldUseSplitNotificationShade(resources)
+    }
+
     override fun onInit() {
         multiUserSwitchController.init()
         securityFooterController.init()
@@ -189,6 +226,9 @@
         securityFooterController.setOnVisibilityChangedListener(visibilityListener)
         fgsManagerFooterController.setOnVisibilityChangedListener(visibilityListener)
 
+        configurationController.addCallback(configurationListener)
+
+        updateResources()
         updateView()
     }
 
@@ -201,6 +241,7 @@
         globalActionsDialog = null
         setListening(false)
         multiUserSetting.isListening = false
+        configurationController.removeCallback(configurationListener)
     }
 
     fun setListening(listening: Boolean) {
@@ -224,7 +265,7 @@
     }
 
     fun setExpansion(headerExpansionFraction: Float) {
-        alphaAnimator.setPosition(headerExpansionFraction)
+        animators.setPosition(headerExpansionFraction)
     }
 
     fun setKeyguardShowing(showing: Boolean) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsView.kt b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsView.kt
index 05038b7..309ac2a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsView.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsView.kt
@@ -27,6 +27,7 @@
 import android.view.View
 import android.widget.ImageView
 import android.widget.LinearLayout
+import androidx.annotation.Keep
 import com.android.settingslib.Utils
 import com.android.settingslib.drawable.UserIconDrawable
 import com.android.systemui.R
@@ -45,6 +46,19 @@
     private var qsDisabled = false
     private var expansionAmount = 0f
 
+    /**
+     * Sets the alpha of the background of this view.
+     *
+     * Used from a [TouchAnimator] in the controller.
+     */
+    var backgroundAlpha: Float = 1f
+        @Keep
+        set(value) {
+            field = value
+            background?.alpha = (value * 255).toInt()
+        }
+        @Keep get
+
     override fun onFinishInflate() {
         super.onFinishInflate()
         settingsContainer = findViewById(R.id.settings_button_container)
@@ -117,4 +131,4 @@
 private const val TAG = "FooterActionsView"
 private val VERBOSE = Log.isLoggable(TAG, Log.VERBOSE)
 private val MotionEvent.string
-    get() = "($id): ($x,$y)"
\ No newline at end of file
+    get() = "($id): ($x,$y)"
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 8c5e6cc..139fb8b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -557,9 +557,9 @@
     public void setQsExpansion(float expansion, float panelExpansionFraction,
             float proposedTranslation, float squishinessFraction) {
         float headerTranslation = mTransitioningToFullShade ? 0 : proposedTranslation;
-        float progress = mTransitioningToFullShade || mState == StatusBarState.KEYGUARD
+        float alphaProgress = mTransitioningToFullShade || mState == StatusBarState.KEYGUARD
                 ? mFullShadeProgress : panelExpansionFraction;
-        setAlphaAnimationProgress(mInSplitShade ? progress : 1);
+        setAlphaAnimationProgress(mInSplitShade ? alphaProgress : 1);
         mContainer.setExpansion(expansion);
         final float translationScaleY = (mInSplitShade
                 ? 1 : QSAnimator.SHORT_PARALLAX_AMOUNT) * (expansion - 1);
@@ -600,7 +600,9 @@
         }
         mQSPanelController.setIsOnKeyguard(onKeyguard);
         mFooter.setExpansion(onKeyguardAndExpanded ? 1 : expansion);
-        mQSFooterActionController.setExpansion(onKeyguardAndExpanded ? 1 : expansion);
+        float footerActionsExpansion =
+                onKeyguardAndExpanded ? 1 : mInSplitShade ? alphaProgress : expansion;
+        mQSFooterActionController.setExpansion(footerActionsExpansion);
         mQSPanelController.setRevealExpansion(expansion);
         mQSPanelController.getTileLayout().setExpansion(expansion, proposedTranslation);
         mQuickQSPanelController.getTileLayout().setExpansion(expansion, proposedTranslation);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 324c019..7155626 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -128,6 +128,8 @@
         if (mUsingMediaPlayer) {
             mHorizontalLinearLayout = new RemeasuringLinearLayout(mContext);
             mHorizontalLinearLayout.setOrientation(LinearLayout.HORIZONTAL);
+            mHorizontalLinearLayout.setVisibility(
+                    mUsingHorizontalLayout ? View.VISIBLE : View.GONE);
             mHorizontalLinearLayout.setClipChildren(false);
             mHorizontalLinearLayout.setClipToPadding(false);
 
@@ -445,6 +447,8 @@
         mMediaHostView = hostView;
         ViewGroup newParent = horizontal ? mHorizontalLinearLayout : this;
         ViewGroup currentParent = (ViewGroup) hostView.getParent();
+        Log.d(getDumpableTag(), "Reattaching media host: " + horizontal
+                + ", current " + currentParent + ", new " + newParent);
         if (currentParent != newParent) {
             if (currentParent != null) {
                 currentParent.removeView(hostView);
@@ -589,6 +593,7 @@
 
     void setUsingHorizontalLayout(boolean horizontal, ViewGroup mediaHostView, boolean force) {
         if (horizontal != mUsingHorizontalLayout || force) {
+            Log.d(getDumpableTag(), "setUsingHorizontalLayout: " + horizontal + ", " + force);
             mUsingHorizontalLayout = horizontal;
             ViewGroup newParent = horizontal ? mHorizontalContentContainer : this;
             switchAllContentToParent(newParent, mTileLayout);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index ec61ea6..6d5f844 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -88,6 +88,8 @@
                 public void onConfigurationChange(Configuration newConfig) {
                     mShouldUseSplitNotificationShade =
                             LargeScreenUtils.shouldUseSplitNotificationShade(getResources());
+                    mQSLogger.logOnConfigurationChanged(mLastOrientation, newConfig.orientation,
+                            mView.getDumpableTag());
                     onConfigurationChanged();
                     if (newConfig.orientation != mLastOrientation) {
                         mLastOrientation = newConfig.orientation;
@@ -164,6 +166,7 @@
         mHost.addCallback(mQSHostCallback);
         setTiles();
         mLastOrientation = getResources().getConfiguration().orientation;
+        mQSLogger.logOnViewAttached(mLastOrientation, mView.getDumpableTag());
         switchTileLayout(true);
 
         mDumpManager.registerDumpable(mView.getDumpableTag(), this);
@@ -171,6 +174,7 @@
 
     @Override
     protected void onViewDetached() {
+        mQSLogger.logOnViewDetached(mLastOrientation, mView.getDumpableTag());
         mView.removeOnConfigurationChangedListener(mOnConfigurationChangedListener);
         mHost.removeCallback(mQSHostCallback);
 
@@ -325,6 +329,8 @@
         /* Whether or not the panel currently contains a media player. */
         boolean horizontal = shouldUseHorizontalLayout();
         if (horizontal != mUsingHorizontalLayout || force) {
+            mQSLogger.logSwitchTileLayout(horizontal, mUsingHorizontalLayout, force,
+                    mView.getDumpableTag());
             mUsingHorizontalLayout = horizontal;
             mView.setUsingHorizontalLayout(mUsingHorizontalLayout, mMediaHost.getHostView(), force);
             updateMediaDisappearParameters();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index 4552abd..ac46c85 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -29,6 +29,7 @@
 import androidx.annotation.MainThread;
 import androidx.annotation.Nullable;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.InstanceId;
 import com.android.internal.logging.InstanceIdSequence;
 import com.android.internal.logging.UiEventLogger;
@@ -47,6 +48,7 @@
 import com.android.systemui.qs.external.TileServiceKey;
 import com.android.systemui.qs.external.TileServiceRequestController;
 import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.settings.UserFileManager;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.statusbar.phone.AutoTileManager;
@@ -88,6 +90,10 @@
     public static final int POSITION_AT_END = -1;
     public static final String TILES_SETTING = Secure.QS_TILES;
 
+    // Shared prefs that hold tile lifecycle info.
+    @VisibleForTesting
+    static final String TILES = "tiles_prefs";
+
     private final Context mContext;
     private final LinkedHashMap<String, QSTile> mTiles = new LinkedHashMap<>();
     protected final ArrayList<String> mTileSpecs = new ArrayList<>();
@@ -99,6 +105,7 @@
     private final InstanceIdSequence mInstanceIdSequence;
     private final CustomTileStatePersister mCustomTileStatePersister;
     private final Executor mMainExecutor;
+    private final UserFileManager mUserFileManager;
 
     private final List<Callback> mCallbacks = new ArrayList<>();
     @Nullable
@@ -110,6 +117,11 @@
     private Context mUserContext;
     private UserTracker mUserTracker;
     private SecureSettings mSecureSettings;
+    // Keep track of whether mTilesList contains the same information as the Settings value.
+    // This is a performance optimization to reduce the number of blocking calls to Settings from
+    // main thread.
+    // This is enforced by only cleaning the flag at the end of a successful run of #onTuningChanged
+    private boolean mTilesListDirty = true;
 
     private final TileServiceRequestController mTileServiceRequestController;
     private TileLifecycleManager.Factory mTileLifeCycleManagerFactory;
@@ -130,7 +142,8 @@
             SecureSettings secureSettings,
             CustomTileStatePersister customTileStatePersister,
             TileServiceRequestController.Builder tileServiceRequestControllerBuilder,
-            TileLifecycleManager.Factory tileLifecycleManagerFactory
+            TileLifecycleManager.Factory tileLifecycleManagerFactory,
+            UserFileManager userFileManager
     ) {
         mIconController = iconController;
         mContext = context;
@@ -143,6 +156,7 @@
         mMainExecutor = mainExecutor;
         mTileServiceRequestController = tileServiceRequestControllerBuilder.create(this);
         mTileLifeCycleManagerFactory = tileLifecycleManagerFactory;
+        mUserFileManager = userFileManager;
 
         mInstanceIdSequence = new InstanceIdSequence(MAX_QS_INSTANCE_ID);
         mCentralSurfacesOptional = centralSurfacesOptional;
@@ -374,6 +388,7 @@
                 // the ones that are in the setting, update the Setting.
                 saveTilesToSettings(mTileSpecs);
             }
+            mTilesListDirty = false;
             for (int i = 0; i < mCallbacks.size(); i++) {
                 mCallbacks.get(i).onTilesChanged();
             }
@@ -386,6 +401,11 @@
      */
     @Override
     public void removeTile(String spec) {
+        if (spec.startsWith(CustomTile.PREFIX)) {
+            // If the tile is removed (due to it not actually existing), mark it as removed. That
+            // way it will be marked as newly added if it appears in the future.
+            setTileAdded(CustomTile.getComponentFromSpec(spec), mCurrentUser, false);
+        }
         mMainExecutor.execute(() -> changeTileSpecs(tileSpecs-> tileSpecs.remove(spec)));
     }
 
@@ -436,6 +456,7 @@
         );
     }
 
+    // When calling this, you may want to modify mTilesListDirty accordingly.
     @MainThread
     private void saveTilesToSettings(List<String> tileSpecs) {
         mSecureSettings.putStringForUser(TILES_SETTING, TextUtils.join(",", tileSpecs),
@@ -445,9 +466,15 @@
 
     @MainThread
     private void changeTileSpecs(Predicate<List<String>> changeFunction) {
-        final String setting = mSecureSettings.getStringForUser(TILES_SETTING, mCurrentUser);
-        final List<String> tileSpecs = loadTileSpecs(mContext, setting);
+        final List<String> tileSpecs;
+        if (!mTilesListDirty) {
+            tileSpecs = new ArrayList<>(mTileSpecs);
+        } else {
+            tileSpecs = loadTileSpecs(mContext,
+                    mSecureSettings.getStringForUser(TILES_SETTING, mCurrentUser));
+        }
         if (changeFunction.test(tileSpecs)) {
+            mTilesListDirty = true;
             saveTilesToSettings(tileSpecs);
         }
     }
@@ -502,11 +529,12 @@
                 lifecycleManager.onStopListening();
                 lifecycleManager.onTileRemoved();
                 mCustomTileStatePersister.removeState(new TileServiceKey(component, mCurrentUser));
-                TileLifecycleManager.setTileAdded(mContext, component, false);
+                setTileAdded(component, mCurrentUser, false);
                 lifecycleManager.flushMessagesAndUnbind();
             }
         }
         if (DEBUG) Log.d(TAG, "saveCurrentTiles " + newTiles);
+        mTilesListDirty = true;
         saveTilesToSettings(newTiles);
     }
 
@@ -538,6 +566,36 @@
         throw new RuntimeException("Default factory didn't create view for " + tile.getTileSpec());
     }
 
+    /**
+     * Check if a particular {@link CustomTile} has been added for a user and has not been removed
+     * since.
+     * @param componentName the {@link ComponentName} of the
+     *                      {@link android.service.quicksettings.TileService} associated with the
+     *                      tile.
+     * @param userId the user to check
+     */
+    public boolean isTileAdded(ComponentName componentName, int userId) {
+        return mUserFileManager
+                .getSharedPreferences(TILES, 0, userId)
+                .getBoolean(componentName.flattenToString(), false);
+    }
+
+    /**
+     * Persists whether a particular {@link CustomTile} has been added and it's currently in the
+     * set of selected tiles ({@link #mTiles}.
+     * @param componentName the {@link ComponentName} of the
+     *                      {@link android.service.quicksettings.TileService} associated
+     *                      with the tile.
+     * @param userId the user for this tile
+     * @param added {@code true} if the tile is being added, {@code false} otherwise
+     */
+    public void setTileAdded(ComponentName componentName, int userId, boolean added) {
+        mUserFileManager.getSharedPreferences(TILES, 0, userId)
+                .edit()
+                .putBoolean(componentName.flattenToString(), added)
+                .apply();
+    }
+
     protected static List<String> loadTileSpecs(Context context, String tileList) {
         final Resources res = context.getResources();
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
index a49d3fd..3e445dd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
@@ -127,6 +127,10 @@
         TileLifecycleManager create(Intent intent, UserHandle userHandle);
     }
 
+    public int getUserId() {
+        return mUser.getIdentifier();
+    }
+
     public ComponentName getComponent() {
         return mIntent.getComponent();
     }
@@ -507,13 +511,4 @@
     public interface TileChangeListener {
         void onTileChanged(ComponentName tile);
     }
-
-    public static boolean isTileAdded(Context context, ComponentName component) {
-        return context.getSharedPreferences(TILES, 0).getBoolean(component.flattenToString(), false);
-    }
-
-    public static void setTileAdded(Context context, ComponentName component, boolean added) {
-        context.getSharedPreferences(TILES, 0).edit().putBoolean(component.flattenToString(),
-                added).commit();
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
index cfc57db..e86bd7a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
@@ -109,9 +109,9 @@
     void startLifecycleManagerAndAddTile() {
         mStarted = true;
         ComponentName component = mStateManager.getComponent();
-        Context context = mServices.getContext();
-        if (!TileLifecycleManager.isTileAdded(context, component)) {
-            TileLifecycleManager.setTileAdded(context, component, true);
+        final int userId = mStateManager.getUserId();
+        if (!mServices.getHost().isTileAdded(component, userId)) {
+            mServices.getHost().setTileAdded(component, userId, true);
             mStateManager.onTileAdded();
             mStateManager.flushMessagesAndUnbind();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt
index 86ef858..948fb14 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt
@@ -69,36 +69,63 @@
         })
     }
 
-    fun logTileClick(tileSpec: String, statusBarState: Int, state: Int) {
+    fun logTileClick(tileSpec: String, statusBarState: Int, state: Int, eventId: Int) {
         log(DEBUG, {
             str1 = tileSpec
-            int1 = statusBarState
+            int1 = eventId
             str2 = StatusBarState.toString(statusBarState)
             str3 = toStateString(state)
         }, {
-            "[$str1] Tile clicked. StatusBarState=$str2. TileState=$str3"
+            "[$str1][$int1] Tile clicked. StatusBarState=$str2. TileState=$str3"
         })
     }
 
-    fun logTileSecondaryClick(tileSpec: String, statusBarState: Int, state: Int) {
+    fun logHandleClick(tileSpec: String, eventId: Int) {
         log(DEBUG, {
             str1 = tileSpec
-            int1 = statusBarState
-            str2 = StatusBarState.toString(statusBarState)
-            str3 = toStateString(state)
+            int1 = eventId
         }, {
-            "[$str1] Tile long clicked. StatusBarState=$str2. TileState=$str3"
+            "[$str1][$int1] Tile handling click."
         })
     }
 
-    fun logTileLongClick(tileSpec: String, statusBarState: Int, state: Int) {
+    fun logTileSecondaryClick(tileSpec: String, statusBarState: Int, state: Int, eventId: Int) {
         log(DEBUG, {
             str1 = tileSpec
-            int1 = statusBarState
+            int1 = eventId
             str2 = StatusBarState.toString(statusBarState)
             str3 = toStateString(state)
         }, {
-            "[$str1] Tile long clicked. StatusBarState=$str2. TileState=$str3"
+            "[$str1][$int1] Tile secondary clicked. StatusBarState=$str2. TileState=$str3"
+        })
+    }
+
+    fun logHandleSecondaryClick(tileSpec: String, eventId: Int) {
+        log(DEBUG, {
+            str1 = tileSpec
+            int1 = eventId
+        }, {
+            "[$str1][$int1] Tile handling secondary click."
+        })
+    }
+
+    fun logTileLongClick(tileSpec: String, statusBarState: Int, state: Int, eventId: Int) {
+        log(DEBUG, {
+            str1 = tileSpec
+            int1 = eventId
+            str2 = StatusBarState.toString(statusBarState)
+            str3 = toStateString(state)
+        }, {
+            "[$str1][$int1] Tile long clicked. StatusBarState=$str2. TileState=$str3"
+        })
+    }
+
+    fun logHandleLongClick(tileSpec: String, eventId: Int) {
+        log(DEBUG, {
+            str1 = tileSpec
+            int1 = eventId
+        }, {
+            "[$str1][$int1] Tile handling long click."
         })
     }
 
@@ -128,6 +155,54 @@
         })
     }
 
+    fun logOnViewAttached(orientation: Int, containerName: String) {
+        log(DEBUG, {
+            str1 = containerName
+            int1 = orientation
+        }, {
+            "onViewAttached: $str1 orientation $int1"
+        })
+    }
+
+    fun logOnViewDetached(orientation: Int, containerName: String) {
+        log(DEBUG, {
+            str1 = containerName
+            int1 = orientation
+        }, {
+            "onViewDetached: $str1 orientation $int1"
+        })
+    }
+
+    fun logOnConfigurationChanged(
+        lastOrientation: Int,
+        newOrientation: Int,
+        containerName: String
+    ) {
+        log(DEBUG, {
+            str1 = containerName
+            int1 = lastOrientation
+            int2 = newOrientation
+        }, {
+            "configuration change: $str1 orientation was $int1, now $int2"
+        })
+    }
+
+    fun logSwitchTileLayout(
+        after: Boolean,
+        before: Boolean,
+        force: Boolean,
+        containerName: String
+    ) {
+        log(DEBUG, {
+            str1 = containerName
+            bool1 = after
+            bool2 = before
+            bool3 = force
+        }, {
+            "change tile layout: $str1 horizontal=$bool1 (was $bool2), force? $bool3"
+        })
+    }
+
     private fun toStateString(state: Int): String {
         return when (state) {
             Tile.STATE_ACTIVE -> "active"
@@ -144,4 +219,4 @@
     ) {
         buffer.log(TAG, logLevel, initializer, printer)
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 740e12a..2cffe89 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -105,6 +105,9 @@
     private final FalsingManager mFalsingManager;
     protected final QSLogger mQSLogger;
     private volatile int mReadyState;
+    // Keeps track of the click event, to match it with the handling in the background thread
+    // Only read and modified in main thread (where click events come through).
+    private int mClickEventId = 0;
 
     private final ArrayList<Callback> mCallbacks = new ArrayList<>();
     private final Object mStaleListener = new Object();
@@ -295,9 +298,11 @@
                         mStatusBarStateController.getState())));
         mUiEventLogger.logWithInstanceId(QSEvent.QS_ACTION_CLICK, 0, getMetricsSpec(),
                 getInstanceId());
-        mQSLogger.logTileClick(mTileSpec, mStatusBarStateController.getState(), mState.state);
+        final int eventId = mClickEventId++;
+        mQSLogger.logTileClick(mTileSpec, mStatusBarStateController.getState(), mState.state,
+                eventId);
         if (!mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
-            mHandler.obtainMessage(H.CLICK, view).sendToTarget();
+            mHandler.obtainMessage(H.CLICK, eventId, 0, view).sendToTarget();
         }
     }
 
@@ -307,9 +312,10 @@
                         mStatusBarStateController.getState())));
         mUiEventLogger.logWithInstanceId(QSEvent.QS_ACTION_SECONDARY_CLICK, 0, getMetricsSpec(),
                 getInstanceId());
+        final int eventId = mClickEventId++;
         mQSLogger.logTileSecondaryClick(mTileSpec, mStatusBarStateController.getState(),
-                mState.state);
-        mHandler.obtainMessage(H.SECONDARY_CLICK, view).sendToTarget();
+                mState.state, eventId);
+        mHandler.obtainMessage(H.SECONDARY_CLICK, eventId, 0, view).sendToTarget();
     }
 
     @Override
@@ -319,8 +325,10 @@
                         mStatusBarStateController.getState())));
         mUiEventLogger.logWithInstanceId(QSEvent.QS_ACTION_LONG_PRESS, 0, getMetricsSpec(),
                 getInstanceId());
-        mQSLogger.logTileLongClick(mTileSpec, mStatusBarStateController.getState(), mState.state);
-        mHandler.obtainMessage(H.LONG_CLICK, view).sendToTarget();
+        final int eventId = mClickEventId++;
+        mQSLogger.logTileLongClick(mTileSpec, mStatusBarStateController.getState(), mState.state,
+                eventId);
+        mHandler.obtainMessage(H.LONG_CLICK, eventId, 0, view).sendToTarget();
     }
 
     public LogMaker populate(LogMaker logMaker) {
@@ -590,13 +598,16 @@
                                 mContext, mEnforcedAdmin);
                         mActivityStarter.postStartActivityDismissingKeyguard(intent, 0);
                     } else {
+                        mQSLogger.logHandleClick(mTileSpec, msg.arg1);
                         handleClick((View) msg.obj);
                     }
                 } else if (msg.what == SECONDARY_CLICK) {
                     name = "handleSecondaryClick";
+                    mQSLogger.logHandleSecondaryClick(mTileSpec, msg.arg1);
                     handleSecondaryClick((View) msg.obj);
                 } else if (msg.what == LONG_CLICK) {
                     name = "handleLongClick";
+                    mQSLogger.logHandleLongClick(mTileSpec, msg.arg1);
                     handleLongClick((View) msg.obj);
                 } else if (msg.what == REFRESH_STATE) {
                     name = "handleRefreshState";
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 438236d..30862b7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -638,12 +638,7 @@
         // Listen for user setup
         startTracking();
 
-        screenLifecycle.addObserver(new ScreenLifecycle.Observer() {
-            @Override
-            public void onScreenTurnedOn() {
-                notifyScreenTurnedOn();
-            }
-        });
+        screenLifecycle.addObserver(mLifecycleObserver);
 
         // Connect to the service
         updateEnabledState();
@@ -951,20 +946,55 @@
         }
     }
 
-    /**
-     * Notifies the Launcher that screen turned on and ready to use
-     */
-    public void notifyScreenTurnedOn() {
-        try {
-            if (mOverviewProxy != null) {
-                mOverviewProxy.onScreenTurnedOn();
-            } else {
-                Log.e(TAG_OPS, "Failed to get overview proxy for screen turned on event.");
+    private final ScreenLifecycle.Observer mLifecycleObserver = new ScreenLifecycle.Observer() {
+        /**
+         * Notifies the Launcher that screen turned on and ready to use
+         */
+        @Override
+        public void onScreenTurnedOn() {
+            try {
+                if (mOverviewProxy != null) {
+                    mOverviewProxy.onScreenTurnedOn();
+                } else {
+                    Log.e(TAG_OPS, "Failed to get overview proxy for screen turned on event.");
+                }
+            } catch (RemoteException e) {
+                Log.e(TAG_OPS, "Failed to call onScreenTurnedOn()", e);
             }
-        } catch (RemoteException e) {
-            Log.e(TAG_OPS, "Failed to call notifyScreenTurnedOn()", e);
         }
-    }
+
+        /**
+         * Notifies the Launcher that screen is starting to turn on.
+         */
+        @Override
+        public void onScreenTurningOff() {
+            try {
+                if (mOverviewProxy != null) {
+                    mOverviewProxy.onScreenTurningOff();
+                } else {
+                    Log.e(TAG_OPS, "Failed to get overview proxy for screen turning off event.");
+                }
+            } catch (RemoteException e) {
+                Log.e(TAG_OPS, "Failed to call onScreenTurningOff()", e);
+            }
+        }
+
+        /**
+         * Notifies the Launcher that screen is starting to turn on.
+         */
+        @Override
+        public void onScreenTurningOn(@NonNull Runnable ignored) {
+            try {
+                if (mOverviewProxy != null) {
+                    mOverviewProxy.onScreenTurningOn();
+                } else {
+                    Log.e(TAG_OPS, "Failed to get overview proxy for screen turning on event.");
+                }
+            } catch (RemoteException e) {
+                Log.e(TAG_OPS, "Failed to call onScreenTurningOn()", e);
+            }
+        }
+    };
 
     void notifyToggleRecentApps() {
         for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
diff --git a/packages/SystemUI/src/com/android/systemui/ripple/RippleShader.kt b/packages/SystemUI/src/com/android/systemui/ripple/RippleShader.kt
index 0a8e6e2..56a1874 100644
--- a/packages/SystemUI/src/com/android/systemui/ripple/RippleShader.kt
+++ b/packages/SystemUI/src/com/android/systemui/ripple/RippleShader.kt
@@ -39,7 +39,7 @@
         ROUNDED_BOX,
         ELLIPSE
     }
-
+    //language=AGSL
     companion object {
         private const val SHADER_UNIFORMS = """uniform vec2 in_center;
                 uniform vec2 in_size;
diff --git a/packages/SystemUI/src/com/android/systemui/ripple/RippleShaderUtilLibrary.kt b/packages/SystemUI/src/com/android/systemui/ripple/RippleShaderUtilLibrary.kt
index 0cacbc2..6de4648 100644
--- a/packages/SystemUI/src/com/android/systemui/ripple/RippleShaderUtilLibrary.kt
+++ b/packages/SystemUI/src/com/android/systemui/ripple/RippleShaderUtilLibrary.kt
@@ -17,6 +17,7 @@
 
 /** A common utility functions that are used for computing [RippleShader]. */
 class RippleShaderUtilLibrary {
+    //language=AGSL
     companion object {
         const val SHADER_LIB = """
             float triangleNoise(vec2 n) {
diff --git a/packages/SystemUI/src/com/android/systemui/ripple/RippleView.kt b/packages/SystemUI/src/com/android/systemui/ripple/RippleView.kt
index 83d9f2d..8b01201 100644
--- a/packages/SystemUI/src/com/android/systemui/ripple/RippleView.kt
+++ b/packages/SystemUI/src/com/android/systemui/ripple/RippleView.kt
@@ -39,7 +39,9 @@
 open class RippleView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
 
     private lateinit var rippleShader: RippleShader
-    private lateinit var rippleShape: RippleShape
+    lateinit var rippleShape: RippleShape
+        private set
+
     private val ripplePaint = Paint()
 
     var rippleInProgress: Boolean = false
diff --git a/packages/SystemUI/src/com/android/systemui/ripple/SdfShaderLibrary.kt b/packages/SystemUI/src/com/android/systemui/ripple/SdfShaderLibrary.kt
index 7f26146..5e256c6 100644
--- a/packages/SystemUI/src/com/android/systemui/ripple/SdfShaderLibrary.kt
+++ b/packages/SystemUI/src/com/android/systemui/ripple/SdfShaderLibrary.kt
@@ -17,6 +17,7 @@
 
 /** Library class that contains 2D signed distance functions. */
 class SdfShaderLibrary {
+    //language=AGSL
     companion object {
         const val CIRCLE_SDF = """
             float sdCircle(vec2 p, float r) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt
index beb54c8..4397d3d 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt
@@ -18,7 +18,6 @@
 
 import android.net.Uri
 import android.util.Log
-import android.view.WindowManager.ScreenshotType
 import android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN
 import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE
 import android.view.WindowManager.TAKE_SCREENSHOT_SELECTED_REGION
@@ -37,13 +36,12 @@
     private val controller: ScreenshotController,
 ) {
     fun processRequest(
-        @ScreenshotType type: Int,
-        onSavedListener: Consumer<Uri>,
         request: ScreenshotRequest,
+        onSavedListener: Consumer<Uri>,
         callback: RequestCallback
     ) {
 
-        if (type == TAKE_SCREENSHOT_PROVIDED_IMAGE) {
+        if (request.type == TAKE_SCREENSHOT_PROVIDED_IMAGE) {
             val image = HardwareBitmapBundler.bundleToHardwareBitmap(request.bitmapBundle)
 
             controller.handleImageAsScreenshot(
@@ -53,12 +51,12 @@
             return
         }
 
-        when (type) {
+        when (request.type) {
             TAKE_SCREENSHOT_FULLSCREEN ->
                 controller.takeScreenshotFullscreen(null, onSavedListener, callback)
             TAKE_SCREENSHOT_SELECTED_REGION ->
                 controller.takeScreenshotPartial(null, onSavedListener, callback)
-            else -> Log.w(TAG, "Invalid screenshot option: $type")
+            else -> Log.w(TAG, "Invalid screenshot option: ${request.type}")
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index f1f0223..7bf3217 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -229,11 +229,11 @@
 
         if (mFeatureFlags.isEnabled(SCREENSHOT_REQUEST_PROCESSOR)) {
             Log.d(TAG, "handleMessage: Using request processor");
-            mProcessor.processRequest(msg.what, uriConsumer, screenshotRequest, requestCallback);
+            mProcessor.processRequest(screenshotRequest, uriConsumer, requestCallback);
             return true;
         }
 
-        switch (msg.what) {
+        switch (screenshotRequest.getType()) {
             case WindowManager.TAKE_SCREENSHOT_FULLSCREEN:
                 if (DEBUG_SERVICE) {
                     Log.d(TAG, "handleMessage: TAKE_SCREENSHOT_FULLSCREEN");
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 4b8379a..a353e8f 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -127,9 +127,7 @@
 import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
 import com.android.systemui.fragments.FragmentService;
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
-import com.android.systemui.keyguard.domain.usecase.SetClockPositionUseCase;
-import com.android.systemui.keyguard.domain.usecase.SetKeyguardBottomAreaAlphaUseCase;
-import com.android.systemui.keyguard.domain.usecase.SetKeyguardBottomAreaAnimateDozingTransitionsUseCase;
+import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor;
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel;
 import com.android.systemui.media.KeyguardMediaController;
 import com.android.systemui.media.MediaDataManager;
@@ -705,11 +703,7 @@
 
     private final CameraGestureHelper mCameraGestureHelper;
     private final Provider<KeyguardBottomAreaViewModel> mKeyguardBottomAreaViewModelProvider;
-    private final Provider<SetClockPositionUseCase> mSetClockPositionUseCaseProvider;
-    private final Provider<SetKeyguardBottomAreaAlphaUseCase>
-            mSetKeyguardBottomAreaAlphaUseCaseProvider;
-    private final Provider<SetKeyguardBottomAreaAnimateDozingTransitionsUseCase>
-            mSetKeyguardBottomAreaAnimateDozingTransitionsUseCaseProvider;
+    private final Provider<KeyguardBottomAreaInteractor> mKeyguardBottomAreaInteractorProvider;
 
     @Inject
     public NotificationPanelViewController(NotificationPanelView view,
@@ -781,10 +775,7 @@
             SystemClock systemClock,
             CameraGestureHelper cameraGestureHelper,
             Provider<KeyguardBottomAreaViewModel> keyguardBottomAreaViewModelProvider,
-            Provider<SetClockPositionUseCase> setClockPositionUseCaseProvider,
-            Provider<SetKeyguardBottomAreaAlphaUseCase> setKeyguardBottomAreaAlphaUseCaseProvider,
-            Provider<SetKeyguardBottomAreaAnimateDozingTransitionsUseCase>
-                    setKeyguardBottomAreaAnimateDozingTransitionsUseCaseProvider) {
+            Provider<KeyguardBottomAreaInteractor> keyguardBottomAreaInteractorProvider) {
         super(view,
                 falsingManager,
                 dozeLog,
@@ -966,10 +957,7 @@
                     }
                 });
         mCameraGestureHelper = cameraGestureHelper;
-        mSetClockPositionUseCaseProvider = setClockPositionUseCaseProvider;
-        mSetKeyguardBottomAreaAlphaUseCaseProvider = setKeyguardBottomAreaAlphaUseCaseProvider;
-        mSetKeyguardBottomAreaAnimateDozingTransitionsUseCaseProvider =
-                setKeyguardBottomAreaAnimateDozingTransitionsUseCaseProvider;
+        mKeyguardBottomAreaInteractorProvider = keyguardBottomAreaInteractorProvider;
     }
 
     @VisibleForTesting
@@ -1487,7 +1475,7 @@
                 mKeyguardStatusViewController.getClockBottom(mStatusBarHeaderHeightKeyguard),
                 mKeyguardStatusViewController.isClockTopAligned());
         mClockPositionAlgorithm.run(mClockPositionResult);
-        mSetClockPositionUseCaseProvider.get().invoke(
+        mKeyguardBottomAreaInteractorProvider.get().setClockPosition(
                 mClockPositionResult.clockX, mClockPositionResult.clockY);
         boolean animate = mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending();
         boolean animateClock = (animate || mAnimateNextPositionUpdate) && shouldAnimateClockChange;
@@ -3261,7 +3249,7 @@
         float alpha = Math.min(expansionAlpha, 1 - computeQsExpansionFraction());
         alpha *= mBottomAreaShadeAlpha;
         mKeyguardBottomArea.setComponentAlphas(alpha);
-        mSetKeyguardBottomAreaAlphaUseCaseProvider.get().invoke(alpha);
+        mKeyguardBottomAreaInteractorProvider.get().setAlpha(alpha);
         mLockIconViewController.setAlpha(alpha);
     }
 
@@ -3461,7 +3449,7 @@
 
     private void updateDozingVisibilities(boolean animate) {
         mKeyguardBottomArea.setDozing(mDozing, animate);
-        mSetKeyguardBottomAreaAnimateDozingTransitionsUseCaseProvider.get().invoke(animate);
+        mKeyguardBottomAreaInteractorProvider.get().setAnimateDozingTransitions(animate);
         if (!mDozing && animate) {
             mKeyguardStatusBarViewController.animateKeyguardStatusBarIn();
         }
@@ -3764,7 +3752,7 @@
         mDozing = dozing;
         mNotificationStackScrollLayoutController.setDozing(mDozing, animate, wakeUpTouchLocation);
         mKeyguardBottomArea.setDozing(mDozing, animate);
-        mSetKeyguardBottomAreaAnimateDozingTransitionsUseCaseProvider.get().invoke(animate);
+        mKeyguardBottomAreaInteractorProvider.get().setAnimateDozingTransitions(animate);
         mKeyguardStatusBarViewController.setDozing(mDozing);
 
         if (dozing) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
index 13a5615..2a46776 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
@@ -6,7 +6,11 @@
 import android.view.WindowInsets
 import androidx.annotation.VisibleForTesting
 import androidx.constraintlayout.widget.ConstraintSet
-import androidx.constraintlayout.widget.ConstraintSet.*
+import androidx.constraintlayout.widget.ConstraintSet.BOTTOM
+import androidx.constraintlayout.widget.ConstraintSet.END
+import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
+import androidx.constraintlayout.widget.ConstraintSet.START
+import androidx.constraintlayout.widget.ConstraintSet.TOP
 import com.android.systemui.R
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.flags.FeatureFlags
@@ -171,33 +175,23 @@
 
     private fun calculateBottomSpacing(): Paddings {
         val containerPadding: Int
-        var stackScrollMargin = notificationsBottomMargin
-        if (splitShadeEnabled) {
-            if (isGestureNavigation) {
-                // only default cutout padding, taskbar always hides
-                containerPadding = bottomCutoutInsets
-            } else if (taskbarVisible) {
-                // navigation buttons + visible taskbar means we're NOT on homescreen
-                containerPadding = bottomStableInsets
-            } else {
-                // navigation buttons + hidden taskbar means we're on homescreen
-                containerPadding = 0
-                // we need extra margin for notifications as navigation buttons are below them
-                stackScrollMargin = bottomStableInsets + notificationsBottomMargin
-            }
+        val stackScrollMargin: Int
+        if (!splitShadeEnabled && (isQSCustomizing || isQSDetailShowing)) {
+            // Clear out bottom paddings/margins so the qs customization can be full height.
+            containerPadding = 0
+            stackScrollMargin = 0
+        } else if (isGestureNavigation) {
+            // only default cutout padding, taskbar always hides
+            containerPadding = bottomCutoutInsets
+            stackScrollMargin = notificationsBottomMargin
+        } else if (taskbarVisible) {
+            // navigation buttons + visible taskbar means we're NOT on homescreen
+            containerPadding = bottomStableInsets
+            stackScrollMargin = notificationsBottomMargin
         } else {
-            if (isQSCustomizing || isQSDetailShowing) {
-                // Clear out bottom paddings/margins so the qs customization can be full height.
-                containerPadding = 0
-                stackScrollMargin = 0
-            } else if (isGestureNavigation) {
-                containerPadding = bottomCutoutInsets
-            } else if (taskbarVisible) {
-                containerPadding = bottomStableInsets
-            } else {
-                containerPadding = 0
-                stackScrollMargin = bottomStableInsets + notificationsBottomMargin
-            }
+            // navigation buttons + hidden taskbar means we're on homescreen
+            containerPadding = 0
+            stackScrollMargin = bottomStableInsets + notificationsBottomMargin
         }
         val qsContainerPadding = if (!(isQSCustomizing || isQSDetailShowing)) {
             // We also want this padding in the bottom in these cases
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
index 07455a0..15c75ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
@@ -37,7 +37,7 @@
  * remove notifications that appear on screen for a period of time and dismiss themselves at the
  * appropriate time.  These include heads up notifications and ambient pulses.
  */
-public abstract class AlertingNotificationManager implements NotificationLifetimeExtender {
+public abstract class AlertingNotificationManager {
     private static final String TAG = "AlertNotifManager";
     protected final Clock mClock = new Clock();
     protected final ArrayMap<String, AlertEntry> mAlertEntries = new ArrayMap<>();
@@ -47,14 +47,6 @@
         mLogger = logger;
     }
 
-    /**
-     * This is the list of entries that have already been removed from the
-     * NotificationManagerService side, but we keep it to prevent the UI from looking weird and
-     * will remove when possible. See {@link NotificationLifetimeExtender}
-     */
-    protected final ArraySet<NotificationEntry> mExtendedLifetimeAlertEntries = new ArraySet<>();
-
-    protected NotificationSafeToRemoveCallback mNotificationLifetimeFinishedCallback;
     protected int mMinimumDisplayTime;
     protected int mAutoDismissNotificationDecay;
     @VisibleForTesting
@@ -210,12 +202,6 @@
         onAlertEntryRemoved(alertEntry);
         entry.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
         alertEntry.reset();
-        if (mExtendedLifetimeAlertEntries.contains(entry)) {
-            if (mNotificationLifetimeFinishedCallback != null) {
-                mNotificationLifetimeFinishedCallback.onSafeToRemove(key);
-            }
-            mExtendedLifetimeAlertEntries.remove(entry);
-        }
     }
 
     /**
@@ -244,19 +230,6 @@
                 || alertEntry.mEntry.isRowDismissed();
     }
 
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // NotificationLifetimeExtender Methods
-
-    @Override
-    public void setCallback(NotificationSafeToRemoveCallback callback) {
-        mNotificationLifetimeFinishedCallback = callback;
-    }
-
-    @Override
-    public boolean shouldExtendLifetime(NotificationEntry entry) {
-        return !canRemoveImmediately(entry.getKey());
-    }
-
     /**
      * @param key
      * @return true if the entry is pinned
@@ -281,20 +254,6 @@
         return 0;
     }
 
-    @Override
-    public void setShouldManageLifetime(NotificationEntry entry, boolean shouldExtend) {
-        if (shouldExtend) {
-            mExtendedLifetimeAlertEntries.add(entry);
-            // We need to make sure that entries are stopping to alert eventually, let's remove
-            // this as soon as possible.
-            AlertEntry alertEntry = mAlertEntries.get(entry.getKey());
-            alertEntry.removeAsSoonAsPossible();
-        } else {
-            mExtendedLifetimeAlertEntries.remove(entry);
-        }
-    }
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-
     protected class AlertEntry implements Comparable<AlertEntry> {
         @Nullable public NotificationEntry mEntry;
         public long mPostTime;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index ca14728..c983644 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -27,6 +27,7 @@
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_ALIGNMENT;
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BATTERY;
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BIOMETRIC_MESSAGE;
+import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP;
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_DISCLOSURE;
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_LOGOUT;
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_OWNER_INFO;
@@ -36,7 +37,6 @@
 import static com.android.systemui.keyguard.ScreenLifecycle.SCREEN_ON;
 import static com.android.systemui.plugins.FalsingManager.LOW_PENALTY;
 
-import android.app.IActivityManager;
 import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -123,6 +123,8 @@
     private static final int MSG_SHOW_ACTION_TO_UNLOCK = 2;
     private static final int MSG_HIDE_BIOMETRIC_MESSAGE = 3;
     private static final long TRANSIENT_BIOMETRIC_ERROR_TIMEOUT = 1300;
+    public static final long DEFAULT_HIDE_DELAY_MS =
+            3500 + KeyguardIndicationTextView.Y_IN_DURATION;
 
     private final Context mContext;
     private final BroadcastDispatcher mBroadcastDispatcher;
@@ -140,7 +142,6 @@
     protected final @Main DelayableExecutor mExecutor;
     protected final @Background DelayableExecutor mBackgroundExecutor;
     private final LockPatternUtils mLockPatternUtils;
-    private final IActivityManager mIActivityManager;
     private final FalsingManager mFalsingManager;
     private final KeyguardBypassController mKeyguardBypassController;
     private final AccessibilityManager mAccessibilityManager;
@@ -155,6 +156,7 @@
     private CharSequence mTrustGrantedIndication;
     private CharSequence mTransientIndication;
     private CharSequence mBiometricMessage;
+    private CharSequence mBiometricMessageFollowUp;
     protected ColorStateList mInitialTextColorState;
     private boolean mVisible;
     private boolean mOrganizationOwnedDevice;
@@ -171,7 +173,7 @@
     private int mBatteryLevel;
     private boolean mBatteryPresent = true;
     private long mChargingTimeRemaining;
-    private String mMessageToShowOnScreenOn;
+    private String mBiometricErrorMessageToShowOnScreenOn;
     private final Set<Integer> mCoExFaceHelpMsgIdsToShow;
     private boolean mInited;
 
@@ -189,11 +191,11 @@
     private final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() {
         @Override
         public void onScreenTurnedOn() {
-            if (mMessageToShowOnScreenOn != null) {
-                showBiometricMessage(mMessageToShowOnScreenOn);
+            if (mBiometricErrorMessageToShowOnScreenOn != null) {
+                showBiometricMessage(mBiometricErrorMessageToShowOnScreenOn);
                 // We want to keep this message around in case the screen was off
-                hideBiometricMessageDelayed(BaseKeyguardCallback.HIDE_DELAY_MS);
-                mMessageToShowOnScreenOn = null;
+                hideBiometricMessageDelayed(DEFAULT_HIDE_DELAY_MS);
+                mBiometricErrorMessageToShowOnScreenOn = null;
             }
         }
     };
@@ -219,7 +221,6 @@
             FalsingManager falsingManager,
             LockPatternUtils lockPatternUtils,
             ScreenLifecycle screenLifecycle,
-            IActivityManager iActivityManager,
             KeyguardBypassController keyguardBypassController,
             AccessibilityManager accessibilityManager) {
         mContext = context;
@@ -236,7 +237,6 @@
         mExecutor = executor;
         mBackgroundExecutor = bgExecutor;
         mLockPatternUtils = lockPatternUtils;
-        mIActivityManager = iActivityManager;
         mFalsingManager = falsingManager;
         mKeyguardBypassController = keyguardBypassController;
         mAccessibilityManager = accessibilityManager;
@@ -498,8 +498,23 @@
                             .build(),
                     true
             );
+            if (!TextUtils.isEmpty(mBiometricMessageFollowUp)) {
+                mRotateTextViewController.updateIndication(
+                        INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
+                        new KeyguardIndication.Builder()
+                                .setMessage(mBiometricMessageFollowUp)
+                                .setMinVisibilityMillis(IMPORTANT_MSG_MIN_DURATION)
+                                .setTextColor(mInitialTextColorState)
+                                .build(),
+                        true
+                );
+            } else {
+                mRotateTextViewController.hideIndication(
+                        INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP);
+            }
         } else {
             mRotateTextViewController.hideIndication(INDICATION_TYPE_BIOMETRIC_MESSAGE);
+            mRotateTextViewController.hideIndication(INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP);
         }
     }
 
@@ -719,38 +734,45 @@
     private void showTransientIndication(CharSequence transientIndication) {
         mTransientIndication = transientIndication;
         mHandler.removeMessages(MSG_HIDE_TRANSIENT);
-        hideTransientIndicationDelayed(BaseKeyguardCallback.HIDE_DELAY_MS);
+        hideTransientIndicationDelayed(DEFAULT_HIDE_DELAY_MS);
 
         updateTransient();
     }
 
-    /**
-     * Shows {@param biometricMessage} until it is hidden by {@link #hideBiometricMessage}.
-     */
-    public void showBiometricMessage(int biometricMessage) {
-        showBiometricMessage(mContext.getResources().getString(biometricMessage));
+    private void showBiometricMessage(CharSequence biometricMessage) {
+        showBiometricMessage(biometricMessage, null);
     }
 
     /**
-     * Shows {@param biometricMessage} until it is hidden by {@link #hideBiometricMessage}.
+     * Shows {@param biometricMessage} and {@param biometricMessageFollowUp}
+     * until they are hidden by {@link #hideBiometricMessage}. Messages are rotated through
+     * by {@link KeyguardIndicationRotateTextViewController}, see class for rotating message
+     * logic.
      */
-    private void showBiometricMessage(CharSequence biometricMessage) {
+    private void showBiometricMessage(CharSequence biometricMessage,
+            CharSequence biometricMessageFollowUp) {
         if (TextUtils.equals(biometricMessage, mBiometricMessage)) {
             return;
         }
 
         mBiometricMessage = biometricMessage;
+        mBiometricMessageFollowUp = biometricMessageFollowUp;
 
         mHandler.removeMessages(MSG_SHOW_ACTION_TO_UNLOCK);
         mHandler.removeMessages(MSG_HIDE_BIOMETRIC_MESSAGE);
-        hideBiometricMessageDelayed(BaseKeyguardCallback.HIDE_DELAY_MS);
+        hideBiometricMessageDelayed(
+                mBiometricMessageFollowUp != null
+                        ? DEFAULT_HIDE_DELAY_MS * 2
+                        : DEFAULT_HIDE_DELAY_MS
+        );
 
         updateBiometricMessage();
     }
 
     private void hideBiometricMessage() {
-        if (mBiometricMessage != null) {
+        if (mBiometricMessage != null || mBiometricMessageFollowUp != null) {
             mBiometricMessage = null;
+            mBiometricMessageFollowUp = null;
             mHandler.removeMessages(MSG_HIDE_BIOMETRIC_MESSAGE);
             updateBiometricMessage();
         }
@@ -789,9 +811,9 @@
             // colors can be hard to read in low brightness.
             mTopIndicationView.setTextColor(Color.WHITE);
 
-            CharSequence newIndication = null;
+            CharSequence newIndication;
             if (!TextUtils.isEmpty(mBiometricMessage)) {
-                newIndication = mBiometricMessage;
+                newIndication = mBiometricMessage; // note: doesn't show mBiometricMessageFollowUp
             } else if (!TextUtils.isEmpty(mTransientIndication)) {
                 newIndication = mTransientIndication;
             } else if (!mBatteryPresent) {
@@ -909,15 +931,21 @@
                         || mAccessibilityManager.isTouchExplorationEnabled();
                 if (udfpsSupported && faceAuthenticated) { // co-ex
                     if (a11yEnabled) {
-                        showBiometricMessage(mContext.getString(
-                                R.string.keyguard_face_successful_unlock_swipe));
+                        showBiometricMessage(
+                                mContext.getString(R.string.keyguard_face_successful_unlock),
+                                mContext.getString(R.string.keyguard_unlock)
+                        );
                     } else {
-                        showBiometricMessage(mContext.getString(
-                                R.string.keyguard_face_successful_unlock_press));
+                        showBiometricMessage(
+                                mContext.getString(R.string.keyguard_face_successful_unlock),
+                                mContext.getString(R.string.keyguard_unlock_press)
+                        );
                     }
                 } else if (faceAuthenticated) { // face-only
-                    showBiometricMessage(mContext.getString(
-                            R.string.keyguard_face_successful_unlock_swipe));
+                    showBiometricMessage(
+                            mContext.getString(R.string.keyguard_face_successful_unlock),
+                            mContext.getString(R.string.keyguard_unlock)
+                    );
                 } else if (udfpsSupported) { // udfps-only
                     if (a11yEnabled) {
                         showBiometricMessage(mContext.getString(R.string.keyguard_unlock));
@@ -943,10 +971,11 @@
         pw.println("  mPowerCharged: " + mPowerCharged);
         pw.println("  mChargingSpeed: " + mChargingSpeed);
         pw.println("  mChargingWattage: " + mChargingWattage);
-        pw.println("  mMessageToShowOnScreenOn: " + mMessageToShowOnScreenOn);
+        pw.println("  mMessageToShowOnScreenOn: " + mBiometricErrorMessageToShowOnScreenOn);
         pw.println("  mDozing: " + mDozing);
         pw.println("  mTransientIndication: " + mTransientIndication);
         pw.println("  mBiometricMessage: " + mBiometricMessage);
+        pw.println("  mBiometricMessageFollowUp: " + mBiometricMessageFollowUp);
         pw.println("  mBatteryLevel: " + mBatteryLevel);
         pw.println("  mBatteryPresent: " + mBatteryPresent);
         pw.println("  AOD text: " + (
@@ -958,8 +987,6 @@
     }
 
     protected class BaseKeyguardCallback extends KeyguardUpdateMonitorCallback {
-        public static final int HIDE_DELAY_MS = 5000;
-
         @Override
         public void onTimeChanged() {
             if (mVisible) {
@@ -1077,7 +1104,7 @@
             } else if (mScreenLifecycle.getScreenState() == SCREEN_ON) {
                 showBiometricMessage(errString);
             } else {
-                mMessageToShowOnScreenOn = errString;
+                mBiometricErrorMessageToShowOnScreenOn = errString;
             }
         }
 
@@ -1139,7 +1166,7 @@
                 // Let's hide any previous messages when authentication starts, otherwise
                 // multiple auth attempts would overlap.
                 hideBiometricMessage();
-                mMessageToShowOnScreenOn = null;
+                mBiometricErrorMessageToShowOnScreenOn = null;
             }
         }
 
@@ -1179,7 +1206,7 @@
         @Override
         public void onRequireUnlockForNfc() {
             showTransientIndication(mContext.getString(R.string.require_unlock_for_nfc));
-            hideTransientIndicationDelayed(HIDE_DELAY_MS);
+            hideTransientIndicationDelayed(DEFAULT_HIDE_DELAY_MS);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLifetimeExtender.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLifetimeExtender.java
deleted file mode 100644
index 48e2923..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLifetimeExtender.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package com.android.systemui.statusbar;
-
-import androidx.annotation.NonNull;
-
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-
-/**
- * Interface for anything that may need to keep notifications managed even after
- * {@link NotificationListener} removes it.  The lifetime extender is in charge of performing the
- * callback when the notification is then safe to remove.
- */
-public interface NotificationLifetimeExtender {
-
-    /**
-     * Set the handler to callback to when the notification is safe to remove.
-     *
-     * @param callback the handler to callback
-     */
-    void setCallback(@NonNull NotificationSafeToRemoveCallback callback);
-
-    /**
-     * Determines whether or not the extender needs the notification kept after removal.
-     *
-     * @param entry the entry containing the notification to check
-     * @return true if the notification lifetime should be extended
-     */
-    boolean shouldExtendLifetime(@NonNull NotificationEntry entry);
-
-    /**
-     * It's possible that a notification was canceled before it ever became visible. This callback
-     * gives lifetime extenders a chance to make sure it shows up. For example if a foreground
-     * service is canceled too quickly but we still want to make sure a FGS notification shows.
-     * @param pendingEntry the canceled (but pending) entry
-     * @return true if the notification lifetime should be extended
-     */
-    default boolean shouldExtendLifetimeForPendingNotification(
-            @NonNull NotificationEntry pendingEntry) {
-        return false;
-    }
-
-    /**
-     * Sets whether or not the lifetime should be managed by the extender.  In practice, if
-     * shouldManage is true, this is where the extender starts managing the entry internally and is
-     * now responsible for calling {@link NotificationSafeToRemoveCallback#onSafeToRemove(String)}
-     * when the entry is safe to remove.  If shouldManage is false, the extender no longer needs to
-     * worry about it (either because we will be removing it anyway or the entry is no longer
-     * removed due to an update).
-     *
-     * @param entry the entry that needs an extended lifetime
-     * @param shouldManage true if the extender should manage the entry now, false otherwise
-     */
-    void setShouldManageLifetime(@NonNull NotificationEntry entry, boolean shouldManage);
-
-    /**
-     * The callback for when the notification is now safe to remove (i.e. its lifetime has ended).
-     */
-    interface NotificationSafeToRemoveCallback {
-        /**
-         * Called when the lifetime extender determines it's safe to remove.
-         *
-         * @param key key of the entry that is now safe to remove
-         */
-        void onSafeToRemove(String key);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index 78b3b0a..d74d408 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -24,7 +24,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.UserInfo;
-import android.os.Handler;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
@@ -32,7 +31,6 @@
 import android.os.UserManager;
 import android.service.notification.StatusBarNotification;
 import android.text.TextUtils;
-import android.util.ArraySet;
 import android.util.IndentingPrintWriter;
 import android.util.Log;
 import android.util.Pair;
@@ -47,12 +45,10 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
-import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.dagger.CentralSurfacesDependenciesModule;
@@ -75,7 +71,6 @@
 import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
-import java.util.Set;
 import java.util.function.Consumer;
 
 import dagger.Lazy;
@@ -100,8 +95,6 @@
     private final NotificationLockscreenUserManager mLockscreenUserManager;
     private final SmartReplyController mSmartReplyController;
     private final NotificationVisibilityProvider mVisibilityProvider;
-    private final NotificationEntryManager mEntryManager;
-    private final Handler mMainHandler;
     private final ActionClickLogger mLogger;
 
     private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy;
@@ -110,7 +103,6 @@
     protected final NotifPipelineFlags mNotifPipelineFlags;
     private final UserManager mUserManager;
     private final KeyguardManager mKeyguardManager;
-    private final RemoteInputNotificationRebuilder mRebuilder;
     private final StatusBarStateController mStatusBarStateController;
     private final RemoteInputUriController mRemoteInputUriController;
     private final NotificationClickNotifier mClickNotifier;
@@ -265,10 +257,8 @@
             SmartReplyController smartReplyController,
             NotificationVisibilityProvider visibilityProvider,
             NotificationEntryManager notificationEntryManager,
-            RemoteInputNotificationRebuilder rebuilder,
             Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
             StatusBarStateController statusBarStateController,
-            @Main Handler mainHandler,
             RemoteInputUriController remoteInputUriController,
             NotificationClickNotifier clickNotifier,
             ActionClickLogger logger,
@@ -278,14 +268,11 @@
         mLockscreenUserManager = lockscreenUserManager;
         mSmartReplyController = smartReplyController;
         mVisibilityProvider = visibilityProvider;
-        mEntryManager = notificationEntryManager;
         mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
-        mMainHandler = mainHandler;
         mLogger = logger;
         mBarService = IStatusBarService.Stub.asInterface(
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-        mRebuilder = rebuilder;
         mKeyguardManager = context.getSystemService(KeyguardManager.class);
         mStatusBarStateController = statusBarStateController;
         mRemoteInputUriController = remoteInputUriController;
@@ -788,238 +775,4 @@
         /** Called when the RemoteInputController is attached to the manager */
         void setRemoteInputController(@NonNull RemoteInputController remoteInputController);
     }
-
-    @VisibleForTesting
-    protected class LegacyRemoteInputLifetimeExtender implements RemoteInputListener, Dumpable {
-
-        /**
-         * How long to wait before auto-dismissing a notification that was kept for remote input,
-         * and has now sent a remote input. We auto-dismiss, because the app may not see a reason to
-         * cancel these given that they technically don't exist anymore. We wait a bit in case the
-         * app issues an update.
-         */
-        private static final int REMOTE_INPUT_KEPT_ENTRY_AUTO_CANCEL_DELAY = 200;
-
-        /**
-         * Notifications that are already removed but are kept around because we want to show the
-         * remote input history. See {@link RemoteInputHistoryExtender} and
-         * {@link SmartReplyHistoryExtender}.
-         */
-        protected final ArraySet<String> mKeysKeptForRemoteInputHistory = new ArraySet<>();
-
-        /**
-         * Notifications that are already removed but are kept around because the remote input is
-         * actively being used (i.e. user is typing in it).  See {@link RemoteInputActiveExtender}.
-         */
-        protected final ArraySet<NotificationEntry> mEntriesKeptForRemoteInputActive =
-                new ArraySet<>();
-
-        protected NotificationLifetimeExtender.NotificationSafeToRemoveCallback
-                mNotificationLifetimeFinishedCallback;
-
-        protected final ArrayList<NotificationLifetimeExtender> mLifetimeExtenders =
-                new ArrayList<>();
-        private RemoteInputController mRemoteInputController;
-
-        LegacyRemoteInputLifetimeExtender() {
-            addLifetimeExtenders();
-        }
-
-        /**
-         * Adds all the notification lifetime extenders. Each extender represents a reason for the
-         * NotificationRemoteInputManager to keep a notification lifetime extended.
-         */
-        protected void addLifetimeExtenders() {
-            mLifetimeExtenders.add(new RemoteInputHistoryExtender());
-            mLifetimeExtenders.add(new SmartReplyHistoryExtender());
-            mLifetimeExtenders.add(new RemoteInputActiveExtender());
-        }
-
-        @Override
-        public void setRemoteInputController(@NonNull RemoteInputController remoteInputController) {
-            mRemoteInputController= remoteInputController;
-        }
-
-        @Override
-        public void onRemoteInputSent(@NonNull NotificationEntry entry) {
-            if (FORCE_REMOTE_INPUT_HISTORY
-                    && isNotificationKeptForRemoteInputHistory(entry.getKey())) {
-                mNotificationLifetimeFinishedCallback.onSafeToRemove(entry.getKey());
-            } else if (mEntriesKeptForRemoteInputActive.contains(entry)) {
-                // We're currently holding onto this notification, but from the apps point of
-                // view it is already canceled, so we'll need to cancel it on the apps behalf
-                // after sending - unless the app posts an update in the mean time, so wait a
-                // bit.
-                mMainHandler.postDelayed(() -> {
-                    if (mEntriesKeptForRemoteInputActive.remove(entry)) {
-                        mNotificationLifetimeFinishedCallback.onSafeToRemove(entry.getKey());
-                    }
-                }, REMOTE_INPUT_KEPT_ENTRY_AUTO_CANCEL_DELAY);
-            }
-        }
-
-        @Override
-        public void onPanelCollapsed() {
-            for (int i = 0; i < mEntriesKeptForRemoteInputActive.size(); i++) {
-                NotificationEntry entry = mEntriesKeptForRemoteInputActive.valueAt(i);
-                if (mRemoteInputController != null) {
-                    mRemoteInputController.removeRemoteInput(entry, null);
-                }
-                if (mNotificationLifetimeFinishedCallback != null) {
-                    mNotificationLifetimeFinishedCallback.onSafeToRemove(entry.getKey());
-                }
-            }
-            mEntriesKeptForRemoteInputActive.clear();
-        }
-
-        @Override
-        public boolean isNotificationKeptForRemoteInputHistory(@NonNull String key) {
-            return mKeysKeptForRemoteInputHistory.contains(key);
-        }
-
-        @Override
-        public void releaseNotificationIfKeptForRemoteInputHistory(
-                @NonNull NotificationEntry entry) {
-            final String key = entry.getKey();
-            if (isNotificationKeptForRemoteInputHistory(key)) {
-                mMainHandler.postDelayed(() -> {
-                    if (isNotificationKeptForRemoteInputHistory(key)) {
-                        mNotificationLifetimeFinishedCallback.onSafeToRemove(key);
-                    }
-                }, REMOTE_INPUT_KEPT_ENTRY_AUTO_CANCEL_DELAY);
-            }
-        }
-
-        @VisibleForTesting
-        public Set<NotificationEntry> getEntriesKeptForRemoteInputActive() {
-            return mEntriesKeptForRemoteInputActive;
-        }
-
-        @Override
-        public void dump(@NonNull PrintWriter pw,
-                @NonNull String[] args) {
-            pw.println("LegacyRemoteInputLifetimeExtender:");
-            pw.print("  mKeysKeptForRemoteInputHistory: ");
-            pw.println(mKeysKeptForRemoteInputHistory);
-            pw.print("  mEntriesKeptForRemoteInputActive: ");
-            pw.println(mEntriesKeptForRemoteInputActive);
-        }
-
-        /**
-         * NotificationRemoteInputManager has multiple reasons to keep notification lifetime
-         * extended so we implement multiple NotificationLifetimeExtenders
-         */
-        protected abstract class RemoteInputExtender implements NotificationLifetimeExtender {
-            @Override
-            public void setCallback(NotificationSafeToRemoveCallback callback) {
-                if (mNotificationLifetimeFinishedCallback == null) {
-                    mNotificationLifetimeFinishedCallback = callback;
-                }
-            }
-        }
-
-        /**
-         * Notification is kept alive as it was cancelled in response to a remote input interaction.
-         * This allows us to show what you replied and allows you to continue typing into it.
-         */
-        protected class RemoteInputHistoryExtender extends RemoteInputExtender {
-            @Override
-            public boolean shouldExtendLifetime(@NonNull NotificationEntry entry) {
-                return shouldKeepForRemoteInputHistory(entry);
-            }
-
-            @Override
-            public void setShouldManageLifetime(NotificationEntry entry,
-                    boolean shouldExtend) {
-                if (shouldExtend) {
-                    StatusBarNotification newSbn = mRebuilder.rebuildForRemoteInputReply(entry);
-                    entry.onRemoteInputInserted();
-
-                    if (newSbn == null) {
-                        return;
-                    }
-
-                    mEntryManager.updateNotification(newSbn, null);
-
-                    // Ensure the entry hasn't already been removed. This can happen if there is an
-                    // inflation exception while updating the remote history
-                    if (entry.isRemoved()) {
-                        return;
-                    }
-
-                    if (Log.isLoggable(TAG, Log.DEBUG)) {
-                        Log.d(TAG, "Keeping notification around after sending remote input "
-                                + entry.getKey());
-                    }
-
-                    mKeysKeptForRemoteInputHistory.add(entry.getKey());
-                } else {
-                    mKeysKeptForRemoteInputHistory.remove(entry.getKey());
-                }
-            }
-        }
-
-        /**
-         * Notification is kept alive for smart reply history.  Similar to REMOTE_INPUT_HISTORY but
-         * with {@link SmartReplyController} specific logic
-         */
-        protected class SmartReplyHistoryExtender extends RemoteInputExtender {
-            @Override
-            public boolean shouldExtendLifetime(@NonNull NotificationEntry entry) {
-                return shouldKeepForSmartReplyHistory(entry);
-            }
-
-            @Override
-            public void setShouldManageLifetime(NotificationEntry entry,
-                    boolean shouldExtend) {
-                if (shouldExtend) {
-                    StatusBarNotification newSbn = mRebuilder.rebuildForCanceledSmartReplies(entry);
-
-                    if (newSbn == null) {
-                        return;
-                    }
-
-                    mEntryManager.updateNotification(newSbn, null);
-
-                    if (entry.isRemoved()) {
-                        return;
-                    }
-
-                    if (Log.isLoggable(TAG, Log.DEBUG)) {
-                        Log.d(TAG, "Keeping notification around after sending smart reply "
-                                + entry.getKey());
-                    }
-
-                    mKeysKeptForRemoteInputHistory.add(entry.getKey());
-                } else {
-                    mKeysKeptForRemoteInputHistory.remove(entry.getKey());
-                    mSmartReplyController.stopSending(entry);
-                }
-            }
-        }
-
-        /**
-         * Notification is kept alive because the user is still using the remote input
-         */
-        protected class RemoteInputActiveExtender extends RemoteInputExtender {
-            @Override
-            public boolean shouldExtendLifetime(@NonNull NotificationEntry entry) {
-                return isRemoteInputActive(entry);
-            }
-
-            @Override
-            public void setShouldManageLifetime(NotificationEntry entry,
-                    boolean shouldExtend) {
-                if (shouldExtend) {
-                    if (Log.isLoggable(TAG, Log.DEBUG)) {
-                        Log.d(TAG, "Keeping notification around while remote input active "
-                                + entry.getKey());
-                    }
-                    mEntriesKeptForRemoteInputActive.add(entry);
-                } else {
-                    mEntriesKeptForRemoteInputActive.remove(entry);
-                }
-            }
-        }
-    }
 }
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 0951e82..8752f92 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
@@ -115,10 +115,8 @@
                 smartReplyController,
                 visibilityProvider,
                 notificationEntryManager,
-                rebuilder,
                 centralSurfacesOptionalLazy,
                 statusBarStateController,
-                mainHandler,
                 remoteInputUriController,
                 clickNotifier,
                 actionClickLogger,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index 7583a98..e2f87b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -15,66 +15,22 @@
  */
 package com.android.systemui.statusbar.notification;
 
-import static android.service.notification.NotificationListenerService.REASON_ERROR;
-
-import static com.android.systemui.statusbar.notification.collection.NotifCollection.REASON_UNKNOWN;
-import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationCallback;
-
-import android.app.Notification;
-import android.app.NotificationChannel;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.os.Trace;
-import android.os.UserHandle;
 import android.service.notification.NotificationListenerService;
-import android.service.notification.NotificationListenerService.Ranking;
-import android.service.notification.NotificationListenerService.RankingMap;
 import android.service.notification.StatusBarNotification;
 import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.Log;
 
 import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.statusbar.IStatusBarService;
-import com.android.internal.statusbar.NotificationVisibility;
-import com.android.systemui.Dumpable;
-import com.android.systemui.dagger.qualifiers.Background;
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.statusbar.NotificationLifetimeExtender;
-import com.android.systemui.statusbar.NotificationListener;
-import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
-import com.android.systemui.statusbar.NotificationRemoteInputManager;
-import com.android.systemui.statusbar.NotificationRemoveInterceptor;
-import com.android.systemui.statusbar.NotificationUiAdjustment;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
-import com.android.systemui.statusbar.notification.collection.legacy.LegacyNotificationRanker;
-import com.android.systemui.statusbar.notification.collection.legacy.LegacyNotificationRankerStub;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
 import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
-import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
-import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
 import com.android.systemui.statusbar.notification.dagger.NotificationsModule;
-import com.android.systemui.statusbar.notification.logging.NotificationLogger;
-import com.android.systemui.util.Assert;
-import com.android.systemui.util.Compile;
-import com.android.systemui.util.leak.LeakDetector;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.Executor;
-
-import dagger.Lazy;
 
 /**
  * NotificationEntryManager is responsible for the adding, removing, and updating of
@@ -90,33 +46,10 @@
  * inflated, an entry moves into the active state, where it _could_ potentially be shown to the
  * user. After an entry makes its way into the active state, we sort and filter the entire set to
  * repopulate the visible set.
- *
- * There are a few different things that other classes may be interested in, and most of them
- * involve the current set of notifications. Here's a brief overview of things you may want to know:
- * @see #getVisibleNotifications() for the visible set
- * @see #getActiveNotificationUnfiltered(String) to check if a key exists
- * @see #getPendingNotificationsIterator() for an iterator over the pending notifications
- * @see #getPendingOrActiveNotif(String) to find a notification exists for that key in any list
- * @see #getActiveNotificationsForCurrentUser() to see every notification that the current user owns
  */
-public class NotificationEntryManager implements
-        CommonNotifCollection,
-        Dumpable,
-        VisualStabilityManager.Callback {
+public class NotificationEntryManager implements VisualStabilityManager.Callback {
 
     private final NotificationEntryManagerLogger mLogger;
-    private final NotificationGroupManagerLegacy mGroupManager;
-    private final NotifPipelineFlags mNotifPipelineFlags;
-    private final Lazy<NotificationRowBinder> mNotificationRowBinderLazy;
-    private final Lazy<NotificationRemoteInputManager> mRemoteInputManagerLazy;
-    private final LeakDetector mLeakDetector;
-    private final IStatusBarService mStatusBarService;
-    private final DumpManager mDumpManager;
-    private final Executor mBgExecutor;
-
-    private final Set<NotificationEntry> mAllNotifications = new ArraySet<>();
-    private final Set<NotificationEntry> mReadOnlyAllNotifications =
-            Collections.unmodifiableSet(mAllNotifications);
 
     /** Pending notifications are ones awaiting inflation */
     @VisibleForTesting
@@ -129,96 +62,14 @@
     /** This is the list of "active notifications for this user in this context" */
     @VisibleForTesting
     protected final ArrayList<NotificationEntry> mSortedAndFiltered = new ArrayList<>();
-    private final List<NotificationEntry> mReadOnlyNotifications =
-            Collections.unmodifiableList(mSortedAndFiltered);
-
-    private final Map<NotificationEntry, NotificationLifetimeExtender> mRetainedNotifications =
-            new ArrayMap<>();
-
     private final List<NotifCollectionListener> mNotifCollectionListeners = new ArrayList<>();
-
-    private LegacyNotificationRanker mRanker = new LegacyNotificationRankerStub();
-    private RankingMap mLatestRankingMap;
-
-    @VisibleForTesting
-    final ArrayList<NotificationLifetimeExtender> mNotificationLifetimeExtenders
-            = new ArrayList<>();
     private final List<NotificationEntryListener> mNotificationEntryListeners = new ArrayList<>();
-    private final List<NotificationRemoveInterceptor> mRemoveInterceptors = new ArrayList<>();
 
     /**
      * Injected constructor. See {@link NotificationsModule}.
      */
-    public NotificationEntryManager(
-            NotificationEntryManagerLogger logger,
-            NotificationGroupManagerLegacy groupManager,
-            NotifPipelineFlags notifPipelineFlags,
-            Lazy<NotificationRowBinder> notificationRowBinderLazy,
-            Lazy<NotificationRemoteInputManager> notificationRemoteInputManagerLazy,
-            LeakDetector leakDetector,
-            IStatusBarService statusBarService,
-            DumpManager dumpManager,
-            @Background Executor bgExecutor
-    ) {
+    public NotificationEntryManager(NotificationEntryManagerLogger logger) {
         mLogger = logger;
-        mGroupManager = groupManager;
-        mNotifPipelineFlags = notifPipelineFlags;
-        mNotificationRowBinderLazy = notificationRowBinderLazy;
-        mRemoteInputManagerLazy = notificationRemoteInputManagerLazy;
-        mLeakDetector = leakDetector;
-        mStatusBarService = statusBarService;
-        mDumpManager = dumpManager;
-        mBgExecutor = bgExecutor;
-    }
-
-    /** Once called, the NEM will start processing notification events from system server. */
-    public void initialize(
-            NotificationListener notificationListener,
-            LegacyNotificationRanker ranker) {
-        mRanker = ranker;
-        notificationListener.addNotificationHandler(mNotifListener);
-        mDumpManager.registerDumpable(this);
-    }
-
-    @Override
-    public void dump(PrintWriter pw, String[] args) {
-        pw.println("NotificationEntryManager state:");
-        pw.println("  mAllNotifications=");
-        if (mAllNotifications.size() == 0) {
-            pw.println("null");
-        } else {
-            int i = 0;
-            for (NotificationEntry entry : mAllNotifications) {
-                dumpEntry(pw, "  ", i, entry);
-                i++;
-            }
-        }
-        pw.print("  mPendingNotifications=");
-        if (mPendingNotifications.size() == 0) {
-            pw.println("null");
-        } else {
-            for (NotificationEntry entry : mPendingNotifications.values()) {
-                pw.println(entry.getSbn());
-            }
-        }
-        pw.println("  Remove interceptors registered:");
-        for (NotificationRemoveInterceptor interceptor : mRemoveInterceptors) {
-            pw.println("    " + interceptor.getClass().getSimpleName());
-        }
-        pw.println("  Lifetime extenders registered:");
-        for (NotificationLifetimeExtender extender : mNotificationLifetimeExtenders) {
-            pw.println("    " + extender.getClass().getSimpleName());
-        }
-        pw.println("  Lifetime-extended notifications:");
-        if (mRetainedNotifications.isEmpty()) {
-            pw.println("    None");
-        } else {
-            for (Map.Entry<NotificationEntry, NotificationLifetimeExtender> entry
-                    : mRetainedNotifications.entrySet()) {
-                pw.println("    " + entry.getKey().getSbn() + " retained by "
-                        + entry.getValue().getClass().getName());
-            }
-        }
     }
 
     /** Adds a {@link NotificationEntryListener}. */
@@ -234,501 +85,12 @@
         mNotificationEntryListeners.remove(listener);
     }
 
-    /** Add a {@link NotificationRemoveInterceptor}. */
-    public void addNotificationRemoveInterceptor(NotificationRemoveInterceptor interceptor) {
-        mRemoveInterceptors.add(interceptor);
-    }
-
-    /** Remove a {@link NotificationRemoveInterceptor} */
-    public void removeNotificationRemoveInterceptor(NotificationRemoveInterceptor interceptor) {
-        mRemoveInterceptors.remove(interceptor);
-    }
-
-    /** Adds multiple {@link NotificationLifetimeExtender}s. */
-    public void addNotificationLifetimeExtenders(List<NotificationLifetimeExtender> extenders) {
-        for (NotificationLifetimeExtender extender : extenders) {
-            addNotificationLifetimeExtender(extender);
-        }
-    }
-
-    /** Adds a {@link NotificationLifetimeExtender}. */
-    public void addNotificationLifetimeExtender(NotificationLifetimeExtender extender) {
-        mNotificationLifetimeExtenders.add(extender);
-        extender.setCallback(key -> removeNotification(key, mLatestRankingMap,
-                UNDEFINED_DISMISS_REASON));
-    }
-
     @Override
     public void onChangeAllowed() {
         updateNotifications("reordering is now allowed");
     }
 
     /**
-     * User requests a notification to be removed.
-     *
-     * @param n the notification to remove.
-     * @param reason why it is being removed e.g. {@link NotificationListenerService#REASON_CANCEL},
-     *               or 0 if unknown.
-     */
-    public void performRemoveNotification(
-            StatusBarNotification n,
-            @NonNull DismissedByUserStats stats,
-            int reason
-    ) {
-        removeNotificationInternal(
-                n.getKey(),
-                null,
-                stats.notificationVisibility,
-                false /* forceRemove */,
-                stats,
-                reason);
-    }
-
-    private NotificationVisibility obtainVisibility(String key) {
-        NotificationEntry e = mActiveNotifications.get(key);
-        final int rank;
-        if (e != null) {
-            rank = e.getRanking().getRank();
-        } else {
-            rank = 0;
-        }
-
-        final int count = mActiveNotifications.size();
-        NotificationVisibility.NotificationLocation location =
-                NotificationLogger.getNotificationLocation(getActiveNotificationUnfiltered(key));
-        return NotificationVisibility.obtain(key, rank, count, true, location);
-    }
-
-    private void abortExistingInflation(String key, String reason) {
-        if (mPendingNotifications.containsKey(key)) {
-            NotificationEntry entry = mPendingNotifications.get(key);
-            entry.abortTask();
-            mPendingNotifications.remove(key);
-            mLogger.logInflationAborted(key, "pending", reason);
-        }
-        NotificationEntry addedEntry = getActiveNotificationUnfiltered(key);
-        if (addedEntry != null) {
-            addedEntry.abortTask();
-            mLogger.logInflationAborted(key, "active", reason);
-        }
-    }
-
-    /**
-     * Cancel this notification and tell the StatusBarManagerService / NotificationManagerService
-     * about the failure.
-     *
-     * WARNING: this will call back into us.  Don't hold any locks.
-     */
-    private void handleInflationException(StatusBarNotification n, Exception e) {
-        removeNotificationInternal(
-                n.getKey(),
-                null,
-                null,
-                true /* forceRemove */,
-                null /* dismissedByUserStats */,
-                REASON_ERROR);
-        for (NotificationEntryListener listener : mNotificationEntryListeners) {
-            listener.onInflationError(n, e);
-        }
-    }
-
-    private final InflationCallback mInflationCallback = new InflationCallback() {
-        @Override
-        public void handleInflationException(NotificationEntry entry, Exception e) {
-            Trace.beginSection("NotificationEntryManager.handleInflationException");
-            NotificationEntryManager.this.handleInflationException(entry.getSbn(), e);
-            Trace.endSection();
-        }
-
-        @Override
-        public void onAsyncInflationFinished(NotificationEntry entry) {
-            Trace.beginSection("NotificationEntryManager.onAsyncInflationFinished");
-            mPendingNotifications.remove(entry.getKey());
-            // If there was an async task started after the removal, we don't want to add it back to
-            // the list, otherwise we might get leaks.
-            if (!entry.isRowRemoved()) {
-                boolean isNew = getActiveNotificationUnfiltered(entry.getKey()) == null;
-                mLogger.logNotifInflated(entry.getKey(), isNew);
-                if (isNew) {
-                    for (NotificationEntryListener listener : mNotificationEntryListeners) {
-                        listener.onEntryInflated(entry);
-                    }
-                    addActiveNotification(entry);
-                    updateNotifications("onAsyncInflationFinished");
-                    for (NotificationEntryListener listener : mNotificationEntryListeners) {
-                        listener.onNotificationAdded(entry);
-                    }
-                } else {
-                    for (NotificationEntryListener listener : mNotificationEntryListeners) {
-                        listener.onEntryReinflated(entry);
-                    }
-                }
-            }
-            Trace.endSection();
-        }
-    };
-
-    private final NotificationHandler mNotifListener = new NotificationHandler() {
-        @Override
-        public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
-            final boolean isUpdateToInflatedNotif = mActiveNotifications.containsKey(sbn.getKey());
-            if (isUpdateToInflatedNotif) {
-                updateNotification(sbn, rankingMap);
-            } else {
-                addNotification(sbn, rankingMap);
-            }
-        }
-
-        @Override
-        public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap) {
-            removeNotification(sbn.getKey(), rankingMap, UNDEFINED_DISMISS_REASON);
-        }
-
-        @Override
-        public void onNotificationRemoved(
-                StatusBarNotification sbn,
-                RankingMap rankingMap,
-                int reason) {
-            removeNotification(sbn.getKey(), rankingMap, reason);
-        }
-
-        @Override
-        public void onNotificationRankingUpdate(RankingMap rankingMap) {
-            updateNotificationRanking(rankingMap);
-        }
-
-        @Override
-        public void onNotificationsInitialized() {
-        }
-
-        @Override
-        public void onNotificationChannelModified(
-                String pkgName,
-                UserHandle user,
-                NotificationChannel channel,
-                int modificationType) {
-            notifyChannelModified(pkgName, user, channel, modificationType);
-        }
-    };
-
-    /**
-     * Equivalent to the old NotificationData#add
-     * @param entry - an entry which is prepared for display
-     */
-    private void addActiveNotification(NotificationEntry entry) {
-        Assert.isMainThread();
-
-        mActiveNotifications.put(entry.getKey(), entry);
-        mGroupManager.onEntryAdded(entry);
-        updateRankingAndSort(mRanker.getRankingMap(), "addEntryInternalInternal");
-    }
-
-    /**
-     * Available so that tests can directly manipulate the list of active notifications easily
-     *
-     * @param entry the entry to add directly to the visible notification map
-     */
-    @VisibleForTesting
-    public void addActiveNotificationForTest(NotificationEntry entry) {
-        mActiveNotifications.put(entry.getKey(), entry);
-        mGroupManager.onEntryAdded(entry);
-
-        reapplyFilterAndSort("addVisibleNotification");
-    }
-
-    @VisibleForTesting
-    protected void removeNotification(String key, RankingMap ranking, int reason) {
-        removeNotificationInternal(
-                key,
-                ranking,
-                obtainVisibility(key),
-                false /* forceRemove */,
-                null /* dismissedByUserStats */,
-                reason);
-    }
-
-    /**
-     * Internally remove a notification because system server has reported the notification
-     * should be removed OR the user has manually dismissed the notification
-     * @param dismissedByUserStats non-null if the user manually dismissed the notification
-     */
-    private void removeNotificationInternal(
-            String key,
-            @Nullable RankingMap ranking,
-            @Nullable NotificationVisibility visibility,
-            boolean forceRemove,
-            DismissedByUserStats dismissedByUserStats,
-            int reason) {
-        Trace.beginSection("NotificationEntryManager.removeNotificationInternal");
-
-        final NotificationEntry entry = getActiveNotificationUnfiltered(key);
-
-        for (NotificationRemoveInterceptor interceptor : mRemoveInterceptors) {
-            if (interceptor.onNotificationRemoveRequested(key, entry, reason)) {
-                // Remove intercepted; log and skip
-                mLogger.logRemovalIntercepted(key);
-                Trace.endSection();
-                return;
-            }
-        }
-
-        boolean lifetimeExtended = false;
-
-        // Notification was canceled before it got inflated
-        if (entry == null) {
-            NotificationEntry pendingEntry = mPendingNotifications.get(key);
-            if (pendingEntry != null) {
-                for (NotificationLifetimeExtender extender : mNotificationLifetimeExtenders) {
-                    if (extender.shouldExtendLifetimeForPendingNotification(pendingEntry)) {
-                        extendLifetime(pendingEntry, extender);
-                        lifetimeExtended = true;
-                        mLogger.logLifetimeExtended(key, extender.getClass().getName(), "pending");
-                    }
-                }
-                if (!lifetimeExtended) {
-                    // At this point, we are guaranteed the notification will be removed
-                    abortExistingInflation(key, "removeNotification");
-                    // Fix for b/201097913: NotifCollectionListener#onEntryRemoved specifies that
-                    //   #onEntryRemoved should be called when a notification is cancelled,
-                    //   regardless of whether the notification was pending or active.
-                    // Note that mNotificationEntryListeners are NOT notified of #onEntryRemoved
-                    //   because for that interface, #onEntryRemoved should only be called for
-                    //   active entries, NOT pending ones.
-                    for (NotifCollectionListener listener : mNotifCollectionListeners) {
-                        listener.onEntryRemoved(pendingEntry, REASON_UNKNOWN);
-                    }
-                    for (NotifCollectionListener listener : mNotifCollectionListeners) {
-                        listener.onEntryCleanUp(pendingEntry);
-                    }
-                    mAllNotifications.remove(pendingEntry);
-                    mLeakDetector.trackGarbage(pendingEntry);
-                }
-            }
-        } else {
-            // If a manager needs to keep the notification around for whatever reason, we
-            // keep the notification
-            boolean entryDismissed = entry.isRowDismissed();
-            if (!forceRemove && !entryDismissed) {
-                for (NotificationLifetimeExtender extender : mNotificationLifetimeExtenders) {
-                    if (extender.shouldExtendLifetime(entry)) {
-                        mLatestRankingMap = ranking;
-                        extendLifetime(entry, extender);
-                        lifetimeExtended = true;
-                        mLogger.logLifetimeExtended(key, extender.getClass().getName(), "active");
-                        break;
-                    }
-                }
-            }
-
-            if (!lifetimeExtended) {
-                // At this point, we are guaranteed the notification will be removed
-                abortExistingInflation(key, "removeNotification");
-                mAllNotifications.remove(entry);
-
-                // Ensure any managers keeping the lifetime extended stop managing the entry
-                cancelLifetimeExtension(entry);
-
-                if (entry.rowExists()) {
-                    entry.removeRow();
-                }
-
-                // Let's remove the children if this was a summary
-                handleGroupSummaryRemoved(key);
-                removeVisibleNotification(key);
-                updateNotifications("removeNotificationInternal");
-                final boolean removedByUser = dismissedByUserStats != null;
-
-                mLogger.logNotifRemoved(entry.getKey(), removedByUser);
-                if (removedByUser && visibility != null) {
-                    sendNotificationRemovalToServer(entry.getSbn(), dismissedByUserStats);
-                }
-                for (NotificationEntryListener listener : mNotificationEntryListeners) {
-                    listener.onEntryRemoved(entry, visibility, removedByUser, reason);
-                }
-                for (NotifCollectionListener listener : mNotifCollectionListeners) {
-                    // NEM doesn't have a good knowledge of reasons so defaulting to unknown.
-                    listener.onEntryRemoved(entry, REASON_UNKNOWN);
-                }
-                for (NotifCollectionListener listener : mNotifCollectionListeners) {
-                    listener.onEntryCleanUp(entry);
-                }
-                mLeakDetector.trackGarbage(entry);
-            }
-        }
-        Trace.endSection();
-    }
-
-    private void sendNotificationRemovalToServer(
-            StatusBarNotification notification,
-            DismissedByUserStats dismissedByUserStats) {
-        mBgExecutor.execute(() -> {
-            try {
-                mStatusBarService.onNotificationClear(
-                        notification.getPackageName(),
-                        notification.getUser().getIdentifier(),
-                        notification.getKey(),
-                        dismissedByUserStats.dismissalSurface,
-                        dismissedByUserStats.dismissalSentiment,
-                        dismissedByUserStats.notificationVisibility);
-            } catch (RemoteException ex) {
-                // system process is dead if we're here.
-            }
-        });
-    }
-
-    /**
-     * Ensures that the group children are cancelled immediately when the group summary is cancelled
-     * instead of waiting for the notification manager to send all cancels. Otherwise this could
-     * lead to flickers.
-     *
-     * This also ensures that the animation looks nice and only consists of a single disappear
-     * animation instead of multiple.
-     *  @param key the key of the notification was removed
-     *
-     */
-    private void handleGroupSummaryRemoved(String key) {
-        NotificationEntry entry = getActiveNotificationUnfiltered(key);
-        if (entry != null && entry.rowExists() && entry.isSummaryWithChildren()) {
-            if (entry.getSbn().getOverrideGroupKey() != null && !entry.isRowDismissed()) {
-                // We don't want to remove children for autobundled notifications as they are not
-                // always cancelled. We only remove them if they were dismissed by the user.
-                return;
-            }
-            List<NotificationEntry> childEntries = entry.getAttachedNotifChildren();
-            if (childEntries == null) {
-                return;
-            }
-            for (int i = 0; i < childEntries.size(); i++) {
-                NotificationEntry childEntry = childEntries.get(i);
-                boolean isForeground = (entry.getSbn().getNotification().flags
-                        & Notification.FLAG_FOREGROUND_SERVICE) != 0;
-                boolean keepForReply =
-                        mRemoteInputManagerLazy.get().shouldKeepForRemoteInputHistory(childEntry)
-                        || mRemoteInputManagerLazy.get().shouldKeepForSmartReplyHistory(childEntry);
-                if (isForeground || keepForReply) {
-                    // the child is a foreground service notification which we can't remove or it's
-                    // a child we're keeping around for reply!
-                    continue;
-                }
-                childEntry.setKeepInParent(true);
-                // we need to set this state earlier as otherwise we might generate some weird
-                // animations
-                childEntry.removeRow();
-            }
-        }
-    }
-
-    private void addNotificationInternal(
-            StatusBarNotification notification,
-            RankingMap rankingMap) throws InflationException {
-        Trace.beginSection("NotificationEntryManager.addNotificationInternal");
-        String key = notification.getKey();
-        if (DEBUG) {
-            Log.d(TAG, "addNotification key=" + key);
-        }
-
-        updateRankingAndSort(rankingMap, "addNotificationInternal");
-
-        Ranking ranking = new Ranking();
-        rankingMap.getRanking(key, ranking);
-
-        NotificationEntry entry = mPendingNotifications.get(key);
-        if (entry != null) {
-            entry.setSbn(notification);
-            entry.setRanking(ranking);
-        } else {
-            entry = new NotificationEntry(
-                    notification,
-                    ranking,
-                    SystemClock.uptimeMillis());
-            mAllNotifications.add(entry);
-            mLeakDetector.trackInstance(entry);
-
-            for (NotifCollectionListener listener : mNotifCollectionListeners) {
-                listener.onEntryInit(entry);
-            }
-        }
-
-        for (NotifCollectionListener listener : mNotifCollectionListeners) {
-            listener.onEntryBind(entry, notification);
-        }
-
-        mPendingNotifications.put(key, entry);
-        mLogger.logNotifAdded(entry.getKey());
-        for (NotificationEntryListener listener : mNotificationEntryListeners) {
-            listener.onPendingEntryAdded(entry);
-        }
-        for (NotifCollectionListener listener : mNotifCollectionListeners) {
-            listener.onEntryAdded(entry);
-        }
-        for (NotifCollectionListener listener : mNotifCollectionListeners) {
-            listener.onRankingApplied();
-        }
-        Trace.endSection();
-    }
-
-    public void addNotification(StatusBarNotification notification, RankingMap ranking) {
-        try {
-            addNotificationInternal(notification, ranking);
-        } catch (InflationException e) {
-            handleInflationException(notification, e);
-        }
-    }
-
-    private void updateNotificationInternal(StatusBarNotification notification,
-            RankingMap ranking) throws InflationException {
-        Trace.beginSection("NotificationEntryManager.updateNotificationInternal");
-        if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")");
-
-        final String key = notification.getKey();
-        abortExistingInflation(key, "updateNotification");
-        final NotificationEntry entry = getActiveNotificationUnfiltered(key);
-        if (entry == null) {
-            Trace.endSection();
-            return;
-        }
-
-        // Notification is updated so it is essentially re-added and thus alive again.  Don't need
-        // to keep its lifetime extended.
-        cancelLifetimeExtension(entry);
-
-        updateRankingAndSort(ranking, "updateNotificationInternal");
-        StatusBarNotification oldSbn = entry.getSbn();
-        entry.setSbn(notification);
-        for (NotifCollectionListener listener : mNotifCollectionListeners) {
-            listener.onEntryBind(entry, notification);
-        }
-        mGroupManager.onEntryUpdated(entry, oldSbn);
-
-        mLogger.logNotifUpdated(entry.getKey());
-        for (NotificationEntryListener listener : mNotificationEntryListeners) {
-            listener.onPreEntryUpdated(entry);
-        }
-        final boolean fromSystem = ranking != null;
-        for (NotifCollectionListener listener : mNotifCollectionListeners) {
-            listener.onEntryUpdated(entry, fromSystem);
-        }
-
-        updateNotifications("updateNotificationInternal");
-
-        for (NotificationEntryListener listener : mNotificationEntryListeners) {
-            listener.onPostEntryUpdated(entry);
-        }
-        for (NotifCollectionListener listener : mNotifCollectionListeners) {
-            listener.onRankingApplied();
-        }
-        Trace.endSection();
-    }
-
-    public void updateNotification(StatusBarNotification notification, RankingMap ranking) {
-        try {
-            updateNotificationInternal(notification, ranking);
-        } catch (InflationException e) {
-            handleInflationException(notification, e);
-        }
-    }
-
-    /**
      * Update the notifications
      * @param reason why the notifications are updating
      */
@@ -736,128 +98,6 @@
         mLogger.logUseWhileNewPipelineActive("updateNotifications", reason);
     }
 
-    public void updateNotificationRanking(RankingMap rankingMap) {
-        Trace.beginSection("NotificationEntryManager.updateNotificationRanking");
-        List<NotificationEntry> entries = new ArrayList<>();
-        entries.addAll(getVisibleNotifications());
-        entries.addAll(mPendingNotifications.values());
-
-        // Has a copy of the current UI adjustments.
-        ArrayMap<String, NotificationUiAdjustment> oldAdjustments = new ArrayMap<>();
-        ArrayMap<String, Integer> oldImportances = new ArrayMap<>();
-        for (NotificationEntry entry : entries) {
-            NotificationUiAdjustment adjustment =
-                    NotificationUiAdjustment.extractFromNotificationEntry(entry);
-            oldAdjustments.put(entry.getKey(), adjustment);
-            oldImportances.put(entry.getKey(), entry.getImportance());
-        }
-
-        // Populate notification entries from the new rankings.
-        updateRankingAndSort(rankingMap, "updateNotificationRanking");
-        updateRankingOfPendingNotifications(rankingMap);
-
-        // By comparing the old and new UI adjustments, reinflate the view accordingly.
-        for (NotificationEntry entry : entries) {
-            mNotificationRowBinderLazy.get()
-                    .onNotificationRankingUpdated(
-                            entry,
-                            oldImportances.get(entry.getKey()),
-                            oldAdjustments.get(entry.getKey()),
-                            NotificationUiAdjustment.extractFromNotificationEntry(entry),
-                            mInflationCallback);
-        }
-
-        updateNotifications("updateNotificationRanking");
-
-        for (NotificationEntryListener listener : mNotificationEntryListeners) {
-            listener.onNotificationRankingUpdated(rankingMap);
-        }
-        for (NotifCollectionListener listener : mNotifCollectionListeners) {
-            listener.onRankingUpdate(rankingMap);
-        }
-        for (NotifCollectionListener listener : mNotifCollectionListeners) {
-            listener.onRankingApplied();
-        }
-        Trace.endSection();
-    }
-
-    void notifyChannelModified(
-            String pkgName,
-            UserHandle user,
-            NotificationChannel channel,
-            int modificationType) {
-        for (NotifCollectionListener listener : mNotifCollectionListeners) {
-            listener.onNotificationChannelModified(pkgName, user, channel, modificationType);
-        }
-        for (NotificationEntryListener listener : mNotificationEntryListeners) {
-            listener.onNotificationChannelModified(pkgName, user, channel, modificationType);
-        }
-    }
-
-    private void updateRankingOfPendingNotifications(@Nullable RankingMap rankingMap) {
-        if (rankingMap == null) {
-            return;
-        }
-        for (NotificationEntry pendingNotification : mPendingNotifications.values()) {
-            Ranking ranking = new Ranking();
-            if (rankingMap.getRanking(pendingNotification.getKey(), ranking)) {
-                pendingNotification.setRanking(ranking);
-            }
-        }
-    }
-
-    /**
-     * @return An iterator for all "pending" notifications. Pending notifications are newly-posted
-     * notifications whose views have not yet been inflated. In general, the system pretends like
-     * these don't exist, although there are a couple exceptions.
-     */
-    public Iterable<NotificationEntry> getPendingNotificationsIterator() {
-        mNotifPipelineFlags.checkLegacyPipelineEnabled();
-        return mPendingNotifications.values();
-    }
-
-    /**
-     * Use this method to retrieve a notification entry that has been prepared for presentation.
-     * Note that the notification may be filtered out and never shown to the user.
-     *
-     * @see #getVisibleNotifications() for the currently sorted and filtered list
-     *
-     * @return a {@link NotificationEntry} if it has been prepared, else null
-     */
-    public NotificationEntry getActiveNotificationUnfiltered(String key) {
-        mNotifPipelineFlags.checkLegacyPipelineEnabled();
-        return mActiveNotifications.get(key);
-    }
-
-    /**
-     * Gets the pending or visible notification entry with the given key. Returns null if
-     * notification doesn't exist.
-     */
-    public NotificationEntry getPendingOrActiveNotif(String key) {
-        mNotifPipelineFlags.checkLegacyPipelineEnabled();
-        NotificationEntry entry = mPendingNotifications.get(key);
-        if (entry != null) {
-            return entry;
-        }
-        return mActiveNotifications.get(key);
-    }
-
-    private void extendLifetime(NotificationEntry entry, NotificationLifetimeExtender extender) {
-        NotificationLifetimeExtender activeExtender = mRetainedNotifications.get(entry);
-        if (activeExtender != null && activeExtender != extender) {
-            activeExtender.setShouldManageLifetime(entry, false);
-        }
-        mRetainedNotifications.put(entry, extender);
-        extender.setShouldManageLifetime(entry, true);
-    }
-
-    private void cancelLifetimeExtension(NotificationEntry entry) {
-        NotificationLifetimeExtender activeExtender = mRetainedNotifications.remove(entry);
-        if (activeExtender != null) {
-            activeExtender.setShouldManageLifetime(entry, false);
-        }
-    }
-
     /*
      * -----
      * Annexed from NotificationData below:
@@ -865,59 +105,11 @@
      * we'll try to keep the behavior the same and can simplify these interfaces in another pass
      */
 
-    /** Internalization of NotificationData#remove */
-    private void removeVisibleNotification(String key) {
-        // no need to synchronize if we're on the main thread dawg
-        Assert.isMainThread();
-
-        NotificationEntry removed = mActiveNotifications.remove(key);
-
-        if (removed == null) return;
-        mGroupManager.onEntryRemoved(removed);
-    }
-
-    /** @return list of active notifications filtered for the current user */
-    public List<NotificationEntry> getActiveNotificationsForCurrentUser() {
-        Trace.beginSection("NotificationEntryManager.getActiveNotificationsForCurrentUser");
-        Assert.isMainThread();
-        ArrayList<NotificationEntry> filtered = new ArrayList<>();
-
-        final int len = mActiveNotifications.size();
-        for (int i = 0; i < len; i++) {
-            NotificationEntry entry = mActiveNotifications.valueAt(i);
-            if (!mRanker.isNotificationForCurrentProfiles(entry)) {
-                continue;
-            }
-            filtered.add(entry);
-        }
-        Trace.endSection();
-        return filtered;
-    }
-
-    //TODO: Get rid of this in favor of NotificationUpdateHandler#updateNotificationRanking
-    /**
-     * @param rankingMap the {@link RankingMap} to apply to the current notification list
-     * @param reason the reason for calling this method, which will be logged
-     */
-    public void updateRanking(RankingMap rankingMap, String reason) {
-        Trace.beginSection("NotificationEntryManager.updateRanking");
-        updateRankingAndSort(rankingMap, reason);
-        for (NotifCollectionListener listener : mNotifCollectionListeners) {
-            listener.onRankingApplied();
-        }
-        Trace.endSection();
-    }
-
     /** Resorts / filters the current notification set with the current RankingMap */
     public void reapplyFilterAndSort(String reason) {
         mLogger.logUseWhileNewPipelineActive("reapplyFilterAndSort", reason);
     }
 
-    /** Calls to NotificationRankingManager and updates mSortedAndFiltered */
-    private void updateRankingAndSort(RankingMap rankingMap, String reason) {
-        mLogger.logUseWhileNewPipelineActive("updateRankingAndSort", reason);
-    }
-
     /** dump the current active notification list. Called from CentralSurfaces */
     public void dump(PrintWriter pw, String indent) {
         pw.println("NotificationEntryManager (Legacy)");
@@ -955,55 +147,10 @@
         pw.println("      notification=" + n.getNotification());
     }
 
-    /**
-     * This is the answer to the question "what notifications should the user be seeing right now?"
-     * These are sorted and filtered, and directly inform the notification shade what to show
-     *
-     * @return A read-only list of the currently active notifications
-     */
-    public List<NotificationEntry> getVisibleNotifications() {
-        mNotifPipelineFlags.checkLegacyPipelineEnabled();
-        return mReadOnlyNotifications;
-    }
-
-    /**
-     * Returns a collections containing ALL notifications we know about, including ones that are
-     * hidden or for other users. See {@link CommonNotifCollection#getAllNotifs()}.
-     */
-    @NonNull
-    @Override
-    public Collection<NotificationEntry> getAllNotifs() {
-        mNotifPipelineFlags.checkLegacyPipelineEnabled();
-        return mReadOnlyAllNotifications;
-    }
-
-    @Nullable
-    @Override
-    public NotificationEntry getEntry(@NonNull String key) {
-        mNotifPipelineFlags.checkLegacyPipelineEnabled();
-        return getPendingOrActiveNotif(key);
-    }
-
-    /** @return A count of the active notifications */
-    public int getActiveNotificationsCount() {
-        mNotifPipelineFlags.checkLegacyPipelineEnabled();
-        return mReadOnlyNotifications.size();
-    }
-
-    /**
-     * @return {@code true} if there is at least one notification that should be visible right now
-     */
-    public boolean hasActiveNotifications() {
-        mNotifPipelineFlags.checkLegacyPipelineEnabled();
-        return mReadOnlyNotifications.size() != 0;
-    }
-
-    @Override
     public void addCollectionListener(@NonNull NotifCollectionListener listener) {
         mNotifCollectionListeners.add(listener);
     }
 
-    @Override
     public void removeCollectionListener(@NonNull NotifCollectionListener listener) {
         mNotifCollectionListeners.remove(listener);
     }
@@ -1024,9 +171,6 @@
         boolean isNotificationForCurrentProfiles(StatusBarNotification sbn);
     }
 
-    private static final String TAG = "NotificationEntryMgr";
-    private static final boolean DEBUG = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.DEBUG);
-
     /**
      * Used when a notification is removed and it doesn't have a reason that maps to one of the
      * reasons defined in NotificationListenerService
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
deleted file mode 100644
index 54f1380..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification;
-
-import static com.android.systemui.media.MediaDataManagerKt.isMediaNotification;
-
-import android.Manifest;
-import android.app.AppGlobals;
-import android.app.Notification;
-import android.content.pm.IPackageManager;
-import android.content.pm.PackageManager;
-import android.os.RemoteException;
-import android.service.notification.StatusBarNotification;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.ForegroundServiceController;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.media.MediaFeatureFlag;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.provider.DebugModeFilterProvider;
-
-import javax.inject.Inject;
-
-/** Component which manages the various reasons a notification might be filtered out.*/
-// TODO: delete NotificationFilter.java after migrating to new NotifPipeline b/145659174.
-//  Notification filtering is taken care of across the different Coordinators (mostly
-//  KeyguardCoordinator.java)
-@SysUISingleton
-public class NotificationFilter {
-
-    private final DebugModeFilterProvider mDebugNotificationFilter;
-    private final StatusBarStateController mStatusBarStateController;
-    private final KeyguardEnvironment mKeyguardEnvironment;
-    private final ForegroundServiceController mForegroundServiceController;
-    private final NotificationLockscreenUserManager mUserManager;
-    private final Boolean mIsMediaFlagEnabled;
-
-    @Inject
-    public NotificationFilter(
-            DebugModeFilterProvider debugNotificationFilter,
-            StatusBarStateController statusBarStateController,
-            KeyguardEnvironment keyguardEnvironment,
-            ForegroundServiceController foregroundServiceController,
-            NotificationLockscreenUserManager userManager,
-            MediaFeatureFlag mediaFeatureFlag) {
-        mDebugNotificationFilter = debugNotificationFilter;
-        mStatusBarStateController = statusBarStateController;
-        mKeyguardEnvironment = keyguardEnvironment;
-        mForegroundServiceController = foregroundServiceController;
-        mUserManager = userManager;
-        mIsMediaFlagEnabled = mediaFeatureFlag.getEnabled();
-    }
-
-    /**
-     * @return true if the provided notification should NOT be shown right now.
-     */
-    public boolean shouldFilterOut(NotificationEntry entry) {
-        final StatusBarNotification sbn = entry.getSbn();
-        if (mDebugNotificationFilter.shouldFilterOut(entry)) {
-            return true;
-        }
-
-        if (!(mKeyguardEnvironment.isDeviceProvisioned()
-                || showNotificationEvenIfUnprovisioned(sbn))) {
-            return true;
-        }
-
-        if (!mKeyguardEnvironment.isNotificationForCurrentProfiles(sbn)) {
-            return true;
-        }
-
-        if (mUserManager.isLockscreenPublicMode(sbn.getUserId())
-                && (sbn.getNotification().visibility == Notification.VISIBILITY_SECRET
-                        || mUserManager.shouldHideNotifications(sbn.getUserId())
-                        || mUserManager.shouldHideNotifications(sbn.getKey()))) {
-            return true;
-        }
-
-        if (mStatusBarStateController.isDozing() && entry.shouldSuppressAmbient()) {
-            return true;
-        }
-
-        if (!mStatusBarStateController.isDozing() && entry.shouldSuppressNotificationList()) {
-            return true;
-        }
-
-        if (entry.getRanking().isSuspended()) {
-            return true;
-        }
-
-        if (mForegroundServiceController.isDisclosureNotification(sbn)
-                && !mForegroundServiceController.isDisclosureNeededForUser(sbn.getUserId())) {
-            // this is a foreground-service disclosure for a user that does not need to show one
-            return true;
-        }
-
-        if (mIsMediaFlagEnabled && isMediaNotification(sbn)) {
-            return true;
-        }
-        return false;
-    }
-
-    // Q: What kinds of notifications should show during setup?
-    // A: Almost none! Only things coming from packages with permission
-    // android.permission.NOTIFICATION_DURING_SETUP that also have special "kind" tags marking them
-    // as relevant for setup (see below).
-    private static boolean showNotificationEvenIfUnprovisioned(StatusBarNotification sbn) {
-        return showNotificationEvenIfUnprovisioned(AppGlobals.getPackageManager(), sbn);
-    }
-
-    @VisibleForTesting
-    static boolean showNotificationEvenIfUnprovisioned(IPackageManager packageManager,
-            StatusBarNotification sbn) {
-        return checkUidPermission(packageManager, Manifest.permission.NOTIFICATION_DURING_SETUP,
-                sbn.getUid()) == PackageManager.PERMISSION_GRANTED
-                && sbn.getNotification().extras.getBoolean(Notification.EXTRA_ALLOW_DURING_SETUP);
-    }
-
-    private static int checkUidPermission(IPackageManager packageManager, String permission,
-            int uid) {
-        try {
-            return packageManager.checkUidPermission(permission, uid);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index b6392f7..585d871 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -61,11 +61,11 @@
 import com.android.internal.util.ContrastColorUtil;
 import com.android.systemui.statusbar.InflationTask;
 import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifDismissInterceptor;
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
+import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
 import com.android.systemui.statusbar.notification.icon.IconPack;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController;
@@ -421,7 +421,7 @@
      * Get the children that are actually attached to this notification's row.
      *
      * TODO: Seems like most callers here should probably be using
-     * {@link NotificationGroupManagerLegacy#getChildren}
+     * {@link GroupMembershipManager#getChildren(ListEntry)}
      */
     public @Nullable List<NotificationEntry> getAttachedNotifChildren() {
         if (row == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
deleted file mode 100644
index a92cff8..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification.collection
-
-import android.app.Notification
-import android.app.NotificationManager.IMPORTANCE_HIGH
-import android.app.NotificationManager.IMPORTANCE_MIN
-import android.service.notification.NotificationListenerService.Ranking
-import android.service.notification.NotificationListenerService.RankingMap
-import android.service.notification.StatusBarNotification
-import com.android.systemui.statusbar.NotificationMediaManager
-import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment
-import com.android.systemui.statusbar.notification.NotificationEntryManagerLogger
-import com.android.systemui.statusbar.notification.NotificationFilter
-import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
-import com.android.systemui.statusbar.notification.collection.legacy.LegacyNotificationRanker
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy
-import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
-import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
-import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON
-import com.android.systemui.statusbar.notification.stack.BUCKET_ALERTING
-import com.android.systemui.statusbar.notification.stack.BUCKET_FOREGROUND_SERVICE
-import com.android.systemui.statusbar.notification.stack.BUCKET_PEOPLE
-import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT
-import com.android.systemui.statusbar.notification.stack.PriorityBucket
-import com.android.systemui.statusbar.policy.HeadsUpManager
-import dagger.Lazy
-import java.util.Objects
-import javax.inject.Inject
-
-private const val TAG = "NotifRankingManager"
-
-/**
- * NotificationRankingManager is responsible for holding on to the most recent [RankingMap], and
- * updating SystemUI's set of [NotificationEntry]s with their own ranking. It also sorts and filters
- * a set of entries (but retains none of them). We also set buckets on the entries here since
- * bucketing is tied closely to sorting.
- *
- * For the curious: this class is one iteration closer to null of what used to be called
- * NotificationData.java.
- */
-open class NotificationRankingManager @Inject constructor(
-    private val mediaManagerLazy: Lazy<NotificationMediaManager>,
-    private val groupManager: NotificationGroupManagerLegacy,
-    private val headsUpManager: HeadsUpManager,
-    private val notifFilter: NotificationFilter,
-    private val logger: NotificationEntryManagerLogger,
-    private val sectionsFeatureManager: NotificationSectionsFeatureManager,
-    private val peopleNotificationIdentifier: PeopleNotificationIdentifier,
-    private val highPriorityProvider: HighPriorityProvider,
-    private val keyguardEnvironment: KeyguardEnvironment
-) : LegacyNotificationRanker {
-
-    override var rankingMap: RankingMap? = null
-        protected set
-    private val mediaManager by lazy {
-        mediaManagerLazy.get()
-    }
-    private val usePeopleFiltering: Boolean
-        get() = sectionsFeatureManager.isFilteringEnabled()
-    private val rankingComparator: Comparator<NotificationEntry> = Comparator { a, b ->
-        val na = a.sbn
-        val nb = b.sbn
-        val aRank = a.ranking.rank
-        val bRank = b.ranking.rank
-
-        val aIsFsn = a.isColorizedForegroundService()
-        val bIsFsn = b.isColorizedForegroundService()
-
-        val aCall = a.isImportantCall()
-        val bCall = b.isImportantCall()
-
-        val aPersonType = a.getPeopleNotificationType()
-        val bPersonType = b.getPeopleNotificationType()
-
-        val aMedia = a.isImportantMedia()
-        val bMedia = b.isImportantMedia()
-
-        val aSystemMax = a.isSystemMax()
-        val bSystemMax = b.isSystemMax()
-
-        val aHeadsUp = a.isRowHeadsUp
-        val bHeadsUp = b.isRowHeadsUp
-
-        val aIsHighPriority = a.isHighPriority()
-        val bIsHighPriority = b.isHighPriority()
-        when {
-            aHeadsUp != bHeadsUp -> if (aHeadsUp) -1 else 1
-            // Provide consistent ranking with headsUpManager
-            aHeadsUp -> headsUpManager.compare(a, b)
-            aIsFsn != bIsFsn -> if (aIsFsn) -1 else 1
-            aCall != bCall -> if (aCall) -1 else 1
-            usePeopleFiltering && aPersonType != bPersonType ->
-                peopleNotificationIdentifier.compareTo(aPersonType, bPersonType)
-            // Upsort current media notification.
-            aMedia != bMedia -> if (aMedia) -1 else 1
-            // Upsort PRIORITY_MAX system notifications
-            aSystemMax != bSystemMax -> if (aSystemMax) -1 else 1
-            aIsHighPriority != bIsHighPriority ->
-                -1 * aIsHighPriority.compareTo(bIsHighPriority)
-            aRank != bRank -> aRank - bRank
-            else -> nb.notification.`when`.compareTo(na.notification.`when`)
-        }
-    }
-
-    override fun updateRanking(
-        newRankingMap: RankingMap?,
-        entries: Collection<NotificationEntry>,
-        reason: String
-    ): List<NotificationEntry> {
-        // TODO: may not be ideal to guard on null here, but this code is implementing exactly what
-        // NotificationData used to do
-        if (newRankingMap != null) {
-            rankingMap = newRankingMap
-            updateRankingForEntries(entries)
-        }
-        return synchronized(this) {
-            filterAndSortLocked(entries, reason)
-        }
-    }
-
-    override fun isNotificationForCurrentProfiles(
-        entry: NotificationEntry
-    ): Boolean {
-        return keyguardEnvironment.isNotificationForCurrentProfiles(entry.sbn)
-    }
-
-    /** Uses the [rankingComparator] to sort notifications which aren't filtered */
-    private fun filterAndSortLocked(
-        entries: Collection<NotificationEntry>,
-        reason: String
-    ): List<NotificationEntry> {
-        logger.logFilterAndSort(reason)
-        val filtered = entries.asSequence()
-                .filterNot(this::filter)
-                .sortedWith(rankingComparator)
-                .toList()
-        entries.forEach { it.bucket = getBucketForEntry(it) }
-        return filtered
-    }
-
-    private fun filter(entry: NotificationEntry): Boolean {
-        val filtered = notifFilter.shouldFilterOut(entry)
-        if (filtered) {
-            // notification is removed from the list, so we reset its initialization time
-            entry.resetInitializationTime()
-        }
-        return filtered
-    }
-
-    @PriorityBucket
-    private fun getBucketForEntry(entry: NotificationEntry): Int {
-        val isImportantCall = entry.isImportantCall()
-        val isHeadsUp = entry.isRowHeadsUp
-        val isMedia = entry.isImportantMedia()
-        val isSystemMax = entry.isSystemMax()
-        return when {
-            entry.isColorizedForegroundService() || isImportantCall -> BUCKET_FOREGROUND_SERVICE
-            usePeopleFiltering && entry.isConversation() -> BUCKET_PEOPLE
-            isHeadsUp || isMedia || isSystemMax || entry.isHighPriority() -> BUCKET_ALERTING
-            else -> BUCKET_SILENT
-        }
-    }
-
-    private fun updateRankingForEntries(entries: Iterable<NotificationEntry>) {
-        rankingMap?.let { rankingMap ->
-            synchronized(entries) {
-                for (entry in entries) {
-                    val newRanking = Ranking()
-                    if (!rankingMap.getRanking(entry.key, newRanking)) {
-                        continue
-                    }
-                    entry.ranking = newRanking
-
-                    val newOverrideGroupKey = newRanking.overrideGroupKey
-                    if (!Objects.equals(entry.sbn.overrideGroupKey, newOverrideGroupKey)) {
-                        val oldGroupKey = entry.sbn.groupKey
-                        val oldIsGroup = entry.sbn.isGroup
-                        val oldIsGroupSummary = entry.sbn.notification.isGroupSummary
-                        entry.sbn.overrideGroupKey = newOverrideGroupKey
-                        groupManager.onEntryUpdated(entry, oldGroupKey, oldIsGroup,
-                                oldIsGroupSummary)
-                    }
-                }
-            }
-        }
-    }
-
-    private fun NotificationEntry.isImportantMedia() =
-            key == mediaManager.mediaNotificationKey && importance > IMPORTANCE_MIN
-
-    private fun NotificationEntry.isConversation() = getPeopleNotificationType() != TYPE_NON_PERSON
-
-    private fun NotificationEntry.getPeopleNotificationType() =
-            peopleNotificationIdentifier.getPeopleNotificationType(this)
-
-    private fun NotificationEntry.isHighPriority() =
-            highPriorityProvider.isHighPriority(this)
-}
-
-// Convenience functions
-private fun NotificationEntry.isSystemMax() =
-        importance >= IMPORTANCE_HIGH && sbn.isSystemNotification()
-
-private fun StatusBarNotification.isSystemNotification() =
-        "android" == packageName || "com.android.systemui" == packageName
-
-private fun NotificationEntry.isImportantCall() =
-        sbn.notification.isStyle(Notification.CallStyle::class.java) && importance > IMPORTANCE_MIN
-
-private fun NotificationEntry.isColorizedForegroundService() = sbn.notification.run {
-    isForegroundService && isColorized && importance > IMPORTANCE_MIN
-}
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 420f21d..14cc6bf 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
@@ -38,6 +38,7 @@
 import android.service.notification.StatusBarNotification;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.Log;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
@@ -126,6 +127,9 @@
     private List<ListEntry> mReadOnlyNewNotifList = Collections.unmodifiableList(mNewNotifList);
     private final NotifPipelineChoreographer mChoreographer;
 
+    private int mConsecutiveReentrantRebuilds = 0;
+    @VisibleForTesting public static final int MAX_CONSECUTIVE_REENTRANT_REBUILDS = 3;
+
     @Inject
     public ShadeListBuilder(
             DumpManager dumpManager,
@@ -310,7 +314,7 @@
 
                     mLogger.logOnBuildList(reason);
                     mAllEntries = entries;
-                    mChoreographer.schedule();
+                    scheduleRebuild(/* reentrant = */ false);
                 }
             };
 
@@ -1332,11 +1336,64 @@
         throw new RuntimeException("Missing default sectioner!");
     }
 
-    private void rebuildListIfBefore(@PipelineState.StateName int state) {
-        mPipelineState.requireIsBefore(state);
-        if (mPipelineState.is(STATE_IDLE)) {
-            mChoreographer.schedule();
+    private void rebuildListIfBefore(@PipelineState.StateName int rebuildState) {
+        final @PipelineState.StateName int currentState = mPipelineState.getState();
+
+        // If the pipeline is idle, requesting an invalidation is always okay, and starts a new run.
+        if (currentState == STATE_IDLE) {
+            scheduleRebuild(/* reentrant = */ false, rebuildState);
+            return;
         }
+
+        // If the pipeline is running, it is okay to request an invalidation of a *later* stage.
+        // Since the current pipeline run hasn't run it yet, no new pipeline run is needed.
+        if (rebuildState > currentState) {
+            return;
+        }
+
+        // If the pipeline is running, it is bad to request an invalidation of *earlier* stages or
+        // the *current* stage; this will run the pipeline more often than needed, and may even
+        // cause an infinite loop of pipeline runs.
+        //
+        // Unfortunately, there are some unfixed bugs that cause reentrant pipeline runs, so we keep
+        // a counter and allow a few reentrant runs in a row between any two non-reentrant runs.
+        //
+        // It is technically possible for a *pair* of invalidations, one reentrant and one not, to
+        // trigger *each other*, alternating responsibility for pipeline runs in an infinite loop
+        // but constantly resetting the reentrant run counter. Hopefully that doesn't happen.
+        scheduleRebuild(/* reentrant = */ true, rebuildState);
+    }
+
+    private void scheduleRebuild(boolean reentrant) {
+        scheduleRebuild(reentrant, STATE_IDLE);
+    }
+
+    private void scheduleRebuild(boolean reentrant, @PipelineState.StateName int rebuildState) {
+        if (!reentrant) {
+            mConsecutiveReentrantRebuilds = 0;
+            mChoreographer.schedule();
+            return;
+        }
+
+        final @PipelineState.StateName int currentState = mPipelineState.getState();
+
+        final String rebuildStateName = PipelineState.getStateName(rebuildState);
+        final String currentStateName = PipelineState.getStateName(currentState);
+        final IllegalStateException exception = new IllegalStateException(
+                "Reentrant notification pipeline rebuild of state " + rebuildStateName
+                        + " while pipeline in state " + currentStateName + ".");
+
+        mConsecutiveReentrantRebuilds++;
+
+        if (mConsecutiveReentrantRebuilds > MAX_CONSECUTIVE_REENTRANT_REBUILDS) {
+            Log.e(TAG, "Crashing after more than " + MAX_CONSECUTIVE_REENTRANT_REBUILDS
+                    + " consecutive reentrant notification pipeline rebuilds.", exception);
+            throw exception;
+        }
+
+        Log.e(TAG, "Allowing " + mConsecutiveReentrantRebuilds
+                + " consecutive reentrant notification pipeline rebuild(s).", exception);
+        mChoreographer.schedule();
     }
 
     private static int countChildren(List<ListEntry> entries) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
index ef1e57b..6e76691 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
@@ -286,7 +286,7 @@
                 if (isInflated(child)) {
                     // TODO: May want to put an animation hint here so view manager knows to treat
                     //  this differently from a regular removal animation
-                    freeNotifViews(child);
+                    freeNotifViews(child, "Past last visible group child");
                 }
             }
         }
@@ -379,7 +379,8 @@
         mNotifInflatingFilter.invalidateList("onInflationFinished for " + logKey(entry));
     }
 
-    private void freeNotifViews(NotificationEntry entry) {
+    private void freeNotifViews(NotificationEntry entry, String reason) {
+        mLogger.logFreeNotifViews(entry, reason);
         mViewBarn.removeViewForEntry(entry);
         mNotifInflater.releaseViews(entry);
         // TODO: clear the entry's row here, or even better, stop setting the row on the entry!
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt
index 30f1315..c4f4ed5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt
@@ -31,7 +31,7 @@
         buffer.log(TAG, LogLevel.DEBUG, {
             str1 = entry.logKey
         }, {
-            "NOTIF INFLATED $str1"
+            "Inflation completed for notif $str1"
         })
     }
 
@@ -40,7 +40,16 @@
             str1 = entry.logKey
             str2 = reason
         }, {
-            "NOTIF INFLATION ABORTED $str1 reason=$str2"
+            "Infation aborted for notif $str1 reason=$str2"
+        })
+    }
+
+    fun logFreeNotifViews(entry: NotificationEntry, reason: String) {
+        buffer.log(TAG, LogLevel.DEBUG, {
+            str1 = entry.logKey
+            str2 = reason
+        }, {
+            "Freeing content views for notif $str1 reason=$str2"
         })
     }
 
@@ -70,4 +79,4 @@
     }
 }
 
-private const val TAG = "PreparationCoordinator"
\ No newline at end of file
+private const val TAG = "PreparationCoordinator"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/BindEventManagerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/BindEventManagerImpl.kt
index 9d5b859..496266f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/BindEventManagerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/BindEventManagerImpl.kt
@@ -17,8 +17,6 @@
 package com.android.systemui.statusbar.notification.collection.inflation
 
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.statusbar.notification.NotificationEntryListener
-import com.android.systemui.statusbar.notification.NotificationEntryManager
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.collection.inflation.BindEventManager.Listener
 import javax.inject.Inject
@@ -31,12 +29,4 @@
     /** Emit the [Listener.onViewBound] event to all registered listeners. */
     fun notifyViewBound(entry: NotificationEntry) =
         listeners.forEach { listener -> listener.onViewBound(entry) }
-
-    /** Initialize this for the legacy pipeline. */
-    fun attachToLegacyPipeline(notificationEntryManager: NotificationEntryManager) {
-        notificationEntryManager.addNotificationEntryListener(object : NotificationEntryListener {
-            override fun onEntryInflated(entry: NotificationEntry) = notifyViewBound(entry)
-            override fun onEntryReinflated(entry: NotificationEntry) = notifyViewBound(entry)
-        })
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LegacyNotificationRanker.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LegacyNotificationRanker.kt
deleted file mode 100644
index 49bc48e..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LegacyNotificationRanker.kt
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification.collection.legacy
-
-import android.service.notification.NotificationListenerService
-import com.android.systemui.statusbar.notification.collection.NotificationEntry
-
-interface LegacyNotificationRanker {
-    val rankingMap: NotificationListenerService.RankingMap?
-
-    fun updateRanking(
-        newRankingMap: NotificationListenerService.RankingMap?,
-        entries: Collection<NotificationEntry>,
-        reason: String
-    ): List<NotificationEntry>
-
-    fun isNotificationForCurrentProfiles(
-        entry: NotificationEntry
-    ): Boolean
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LegacyNotificationRankerStub.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LegacyNotificationRankerStub.java
deleted file mode 100644
index 12353f8..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LegacyNotificationRankerStub.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification.collection.legacy;
-
-import android.service.notification.NotificationListenerService.Ranking;
-import android.service.notification.NotificationListenerService.RankingMap;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.List;
-
-/**
- * Stub implementation that we use until we get passed the "real" one in the form of
- * {@link com.android.systemui.statusbar.notification.collection.NotificationRankingManager}
- */
-public class LegacyNotificationRankerStub implements LegacyNotificationRanker {
-    private RankingMap mRankingMap = new RankingMap(new Ranking[] {});
-
-    @NonNull
-    @Override
-    public List<NotificationEntry> updateRanking(
-            @Nullable RankingMap newRankingMap,
-            @NonNull Collection<NotificationEntry> entries,
-            @NonNull String reason) {
-        if (newRankingMap != null) {
-            mRankingMap = newRankingMap;
-        }
-        List<NotificationEntry> ranked = new ArrayList<>(entries);
-        ranked.sort(mEntryComparator);
-        return ranked;
-    }
-
-    @Nullable
-    @Override
-    public RankingMap getRankingMap() {
-        return mRankingMap;
-    }
-
-    private final Comparator<NotificationEntry> mEntryComparator = Comparator.comparingLong(
-            o -> o.getSbn().getNotification().when);
-
-    @Override
-    public boolean isNotificationForCurrentProfiles(@NonNull NotificationEntry entry) {
-        return true;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LowPriorityInflationHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LowPriorityInflationHelper.java
index ae4f2bb..89445a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LowPriorityInflationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LowPriorityInflationHelper.java
@@ -19,9 +19,6 @@
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.row.RowContentBindParams;
-import com.android.systemui.statusbar.notification.row.RowContentBindStage;
 
 import javax.inject.Inject;
 
@@ -32,44 +29,17 @@
 @SysUISingleton
 public class LowPriorityInflationHelper {
     private final NotificationGroupManagerLegacy mGroupManager;
-    private final RowContentBindStage mRowContentBindStage;
     private final NotifPipelineFlags mNotifPipelineFlags;
 
     @Inject
     LowPriorityInflationHelper(
             NotificationGroupManagerLegacy groupManager,
-            RowContentBindStage rowContentBindStage,
             NotifPipelineFlags notifPipelineFlags) {
         mGroupManager = groupManager;
-        mRowContentBindStage = rowContentBindStage;
         mNotifPipelineFlags = notifPipelineFlags;
     }
 
     /**
-     * Check if we inflated the wrong version of the view and if we need to reinflate the
-     * content views to be their low priority version or not.
-     *
-     * Whether we inflate the low priority view or not depends on the notification being visually
-     * part of a group. Since group membership is determined AFTER inflation, we're forced to check
-     * again at a later point in the pipeline to see if we inflated the wrong view and reinflate
-     * the correct one here.
-     *
-     * TODO: The group manager should run before inflation so that we don't deal with this
-     */
-    public void recheckLowPriorityViewAndInflate(
-            NotificationEntry entry,
-            ExpandableNotificationRow row) {
-        mNotifPipelineFlags.checkLegacyPipelineEnabled();
-        RowContentBindParams params = mRowContentBindStage.getStageParams(entry);
-        final boolean shouldBeLowPriority = shouldUseLowPriorityView(entry);
-        if (!row.isRemoved() && row.isLowPriority() != shouldBeLowPriority) {
-            params.setUseLowPriority(shouldBeLowPriority);
-            mRowContentBindStage.requestRebind(entry,
-                    en -> row.setIsLowPriority(shouldBeLowPriority));
-        }
-    }
-
-    /**
      * Whether the notification should inflate a low priority version of its content views.
      */
     public boolean shouldUseLowPriorityView(NotificationEntry entry) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java
index b8da9a8..d41f6fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java
@@ -33,13 +33,9 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.notification.collection.ListEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
-import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
+import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager.OnGroupExpansionChangeListener;
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
 import com.android.systemui.util.Compile;
 import com.android.wm.shell.bubbles.Bubbles;
 
@@ -47,7 +43,6 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
@@ -65,12 +60,7 @@
  * 2. Tracking group expansion states
  */
 @SysUISingleton
-public class NotificationGroupManagerLegacy implements
-        OnHeadsUpChangedListener,
-        StateListener,
-        GroupMembershipManager,
-        GroupExpansionManager,
-        Dumpable {
+public class NotificationGroupManagerLegacy implements StateListener, Dumpable {
 
     private static final String TAG = "LegacyNotifGroupManager";
     private static final boolean DEBUG = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.DEBUG);
@@ -81,14 +71,10 @@
      */
     private static final long POST_BATCH_MAX_AGE = 5000;
     private final HashMap<String, NotificationGroup> mGroupMap = new HashMap<>();
-    private final ArraySet<OnGroupExpansionChangeListener> mExpansionChangeListeners =
-            new ArraySet<>();
     private final Lazy<PeopleNotificationIdentifier> mPeopleNotificationIdentifier;
     private final Optional<Bubbles> mBubblesOptional;
     private final GroupEventDispatcher mEventDispatcher = new GroupEventDispatcher(mGroupMap::get);
-    private int mBarState = -1;
-    private HashMap<String, StatusBarNotification> mIsolatedEntries = new HashMap<>();
-    private HeadsUpManager mHeadsUpManager;
+    private final HashMap<String, StatusBarNotification> mIsolatedEntries = new HashMap<>();
     private boolean mIsUpdatingUnchangedGroup;
 
     @Inject
@@ -111,47 +97,8 @@
         mEventDispatcher.registerGroupChangeListener(listener);
     }
 
-    @Override
-    public void registerGroupExpansionChangeListener(OnGroupExpansionChangeListener listener) {
-        mExpansionChangeListeners.add(listener);
-    }
-
-    @Override
-    public boolean isGroupExpanded(NotificationEntry entry) {
-        NotificationGroup group = mGroupMap.get(getGroupKey(entry.getSbn()));
-        if (group == null) {
-            return false;
-        }
-        return group.expanded;
-    }
-
-    /**
-     * @return if the group that this notification is associated with logically is expanded
-     */
-    public boolean isLogicalGroupExpanded(StatusBarNotification sbn) {
-        NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
-        if (group == null) {
-            return false;
-        }
-        return group.expanded;
-    }
-
-    @Override
-    public void setGroupExpanded(NotificationEntry entry, boolean expanded) {
-        NotificationGroup group = mGroupMap.get(getGroupKey(entry.getSbn()));
-        if (group == null) {
-            return;
-        }
-        setGroupExpanded(group, expanded);
-    }
-
     private void setGroupExpanded(NotificationGroup group, boolean expanded) {
         group.expanded = expanded;
-        if (group.summary != null) {
-            for (OnGroupExpansionChangeListener listener : mExpansionChangeListeners) {
-                listener.onGroupExpansionChange(group.summary.getRow(), expanded);
-            }
-        }
     }
 
     /**
@@ -212,19 +159,6 @@
         }
     }
 
-    /**
-     * Notify the group manager that a new entry was added
-     */
-    public void onEntryAdded(final NotificationEntry added) {
-        if (SPEW) {
-            Log.d(TAG, "onEntryAdded: entry=" + logKey(added));
-        }
-        mEventDispatcher.openBufferScope();
-        updateIsolation(added);
-        onEntryAddedInternal(added);
-        mEventDispatcher.closeBufferScope();
-    }
-
     private void onEntryAddedInternal(final NotificationEntry added) {
         if (added.isRowRemoved()) {
             added.setDebugThrowable(new Throwable());
@@ -499,106 +433,13 @@
         return result;
     }
 
-    /**
-     * Update an entry's group information
-     * @param entry notification entry to update
-     * @param oldNotification previous notification info before this update
-     */
-    public void onEntryUpdated(NotificationEntry entry, StatusBarNotification oldNotification) {
-        if (SPEW) {
-            Log.d(TAG, "onEntryUpdated: entry=" + logKey(entry));
-        }
-        onEntryUpdated(entry, oldNotification.getGroupKey(), oldNotification.isGroup(),
-                oldNotification.getNotification().isGroupSummary());
-    }
-
-    /**
-     * Updates an entry's group information
-     * @param entry notification entry to update
-     * @param oldGroupKey the notification's previous group key before this update
-     * @param oldIsGroup whether this notification was a group before this update
-     * @param oldIsGroupSummary whether this notification was a group summary before this update
-     */
-    public void onEntryUpdated(NotificationEntry entry, String oldGroupKey, boolean oldIsGroup,
-            boolean oldIsGroupSummary) {
-        String newGroupKey = entry.getSbn().getGroupKey();
-        boolean groupKeysChanged = !oldGroupKey.equals(newGroupKey);
-        boolean wasGroupChild = isGroupChild(entry.getKey(), oldIsGroup, oldIsGroupSummary);
-        boolean isGroupChild = isGroupChild(entry.getSbn());
-        mEventDispatcher.openBufferScope();
-        mIsUpdatingUnchangedGroup = !groupKeysChanged && wasGroupChild == isGroupChild;
-        if (mGroupMap.get(getGroupKey(entry.getKey(), oldGroupKey)) != null) {
-            onEntryRemovedInternal(entry, oldGroupKey, oldIsGroup, oldIsGroupSummary);
-        }
-        onEntryAddedInternal(entry);
-        mIsUpdatingUnchangedGroup = false;
-        if (isIsolated(entry.getSbn().getKey())) {
-            mIsolatedEntries.put(entry.getKey(), entry.getSbn());
-            if (groupKeysChanged) {
-                updateSuppression(mGroupMap.get(oldGroupKey));
-            }
-            // Always update the suppression of the group from which you're isolated, in case
-            // this entry was or now is the alertOverride for that group.
-            updateSuppression(mGroupMap.get(newGroupKey));
-        } else if (!wasGroupChild && isGroupChild) {
-            onEntryBecomingChild(entry);
-        }
-        mEventDispatcher.closeBufferScope();
-    }
-
-    /**
-     * Whether the given notification is the summary of a group that is being suppressed
-     */
-    public boolean isSummaryOfSuppressedGroup(StatusBarNotification sbn) {
-        return sbn.getNotification().isGroupSummary() && isGroupSuppressed(getGroupKey(sbn));
-    }
-
-    /**
-     * If the given notification is a summary, get the group for it.
-     */
-    public NotificationGroup getGroupForSummary(StatusBarNotification sbn) {
-        if (sbn.getNotification().isGroupSummary()) {
-            return mGroupMap.get(getGroupKey(sbn));
-        }
-        return null;
-    }
-
-    private boolean isOnlyChild(StatusBarNotification sbn) {
-        return !sbn.getNotification().isGroupSummary()
-                && getTotalNumberOfChildren(sbn) == 1;
-    }
-
-    @Override
-    public boolean isOnlyChildInGroup(NotificationEntry entry) {
-        final StatusBarNotification sbn = entry.getSbn();
-        if (!isOnlyChild(sbn)) {
-            return false;
-        }
-        NotificationEntry logicalGroupSummary = getLogicalGroupSummary(entry);
-        return logicalGroupSummary != null && !logicalGroupSummary.getSbn().equals(sbn);
-    }
-
-    private int getTotalNumberOfChildren(StatusBarNotification sbn) {
-        int isolatedChildren = getNumberOfIsolatedChildren(sbn.getGroupKey());
-        NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
-        int realChildren = group != null ? group.children.size() : 0;
-        return isolatedChildren + realChildren;
-    }
-
-    private boolean isGroupSuppressed(String groupKey) {
-        NotificationGroup group = mGroupMap.get(groupKey);
-        return group != null && group.suppressed;
-    }
-
     private void setStatusBarState(int newState) {
-        mBarState = newState;
-        if (mBarState == StatusBarState.KEYGUARD) {
+        if (newState == StatusBarState.KEYGUARD) {
             collapseGroups();
         }
     }
 
-    @Override
-    public void collapseGroups() {
+    private void collapseGroups() {
         // Because notifications can become isolated when the group becomes suppressed it can
         // lead to concurrent modifications while looping. We need to make a copy.
         ArrayList<NotificationGroup> groupCopy = new ArrayList<>(mGroupMap.values());
@@ -612,7 +453,6 @@
         }
     }
 
-    @Override
     public boolean isChildInGroup(NotificationEntry entry) {
         final StatusBarNotification sbn = entry.getSbn();
         if (!isGroupChild(sbn)) {
@@ -631,67 +471,6 @@
         return true;
     }
 
-    @Override
-    public boolean isGroupSummary(NotificationEntry entry) {
-        final StatusBarNotification sbn = entry.getSbn();
-        if (!isGroupSummary(sbn)) {
-            return false;
-        }
-        NotificationGroup group = mGroupMap.get(getGroupKey(sbn));
-        if (group == null || group.summary == null) {
-            return false;
-        }
-        return !group.children.isEmpty() && Objects.equals(group.summary.getSbn(), sbn);
-    }
-
-    @Override
-    public NotificationEntry getGroupSummary(NotificationEntry entry) {
-        return getGroupSummary(getGroupKey(entry.getSbn()));
-    }
-
-    @Override
-    public NotificationEntry getLogicalGroupSummary(NotificationEntry entry) {
-        return getGroupSummary(entry.getSbn().getGroupKey());
-    }
-
-    @Nullable
-    private NotificationEntry getGroupSummary(String groupKey) {
-        NotificationGroup group = mGroupMap.get(groupKey);
-        //TODO: see if this can become an Entry
-        return group == null ? null
-                : group.summary;
-    }
-
-    /**
-     * Get the children that are logically in the summary's group, whether or not they are isolated.
-     *
-     * @param summary summary of a group
-     * @return list of the children
-     */
-    public ArrayList<NotificationEntry> getLogicalChildren(StatusBarNotification summary) {
-        NotificationGroup group = mGroupMap.get(summary.getGroupKey());
-        if (group == null) {
-            return null;
-        }
-        ArrayList<NotificationEntry> children = new ArrayList<>(group.children.values());
-        for (StatusBarNotification sbn : mIsolatedEntries.values()) {
-            if (sbn.getGroupKey().equals(summary.getGroupKey())) {
-                children.add(mGroupMap.get(sbn.getKey()).summary);
-            }
-        }
-        return children;
-    }
-
-    @Override
-    public @Nullable List<NotificationEntry> getChildren(ListEntry listEntrySummary) {
-        NotificationEntry summary = listEntrySummary.getRepresentativeEntry();
-        NotificationGroup group = mGroupMap.get(summary.getSbn().getGroupKey());
-        if (group == null) {
-            return null;
-        }
-        return new ArrayList<>(group.children.values());
-    }
-
     /**
      * If there is a {@link NotificationGroup} associated with the provided entry, this method
      * will update the suppression of that group.
@@ -710,7 +489,7 @@
      * @param sbn notification to check
      * @return the key of the notification
      */
-    public String getGroupKey(StatusBarNotification sbn) {
+    private String getGroupKey(StatusBarNotification sbn) {
         return getGroupKey(sbn.getKey(), sbn.getGroupKey());
     }
 
@@ -721,37 +500,17 @@
         return groupKey;
     }
 
-    @Override
-    public boolean toggleGroupExpansion(NotificationEntry entry) {
-        NotificationGroup group = mGroupMap.get(getGroupKey(entry.getSbn()));
-        if (group == null) {
-            return false;
-        }
-        setGroupExpanded(group, !group.expanded);
-        return group.expanded;
-    }
-
     private boolean isIsolated(String sbnKey) {
         return mIsolatedEntries.containsKey(sbnKey);
     }
 
     /**
-     * Is this notification the summary of a group?
-     */
-    public boolean isGroupSummary(StatusBarNotification sbn) {
-        if (isIsolated(sbn.getKey())) {
-            return true;
-        }
-        return sbn.getNotification().isGroupSummary();
-    }
-
-    /**
      * Whether a notification is visually a group child.
      *
      * @param sbn notification to check
      * @return true if it is visually a group child
      */
-    public boolean isGroupChild(StatusBarNotification sbn) {
+    private boolean isGroupChild(StatusBarNotification sbn) {
         return isGroupChild(sbn.getKey(), sbn.isGroup(), sbn.getNotification().isGroupSummary());
     }
 
@@ -762,11 +521,6 @@
         return isGroup && !isGroupSummary;
     }
 
-    @Override
-    public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
-        updateIsolation(entry);
-    }
-
     /**
      * Whether a notification that is normally part of a group should be temporarily isolated from
      * the group and put in their own group visually.  This generally happens when the notification
@@ -783,9 +537,6 @@
         if (isImportantConversation(entry)) {
             return true;
         }
-        if (mHeadsUpManager != null && !mHeadsUpManager.isAlerting(entry.getKey())) {
-            return false;
-        }
         NotificationGroup notificationGroup = mGroupMap.get(sbn.getGroupKey());
         return (sbn.getNotification().fullScreenIntent != null
                     || notificationGroup == null
@@ -825,7 +576,7 @@
     /**
      * Update the isolation of an entry, splitting it from the group.
      */
-    public void updateIsolation(NotificationEntry entry) {
+    private void updateIsolation(NotificationEntry entry) {
         // We need to buffer a few events because we do isolation changes in 3 steps:
         // removeInternal, update mIsolatedEntries, addInternal.  This means that often the
         // alertOverride will update on the removal, however processing the event in that case can
@@ -866,13 +617,6 @@
                 || notificationGroup.summary.isGroupNotFullyVisible();
     }
 
-    /**
-     * Directly set the heads up manager to avoid circular dependencies
-     */
-    public void setHeadsUpManager(HeadsUpManager headsUpManager) {
-        mHeadsUpManager = headsUpManager;
-    }
-
     @Override
     public void dump(PrintWriter pw, String[] args) {
         pw.println("GroupManagerLegacy state:");
@@ -893,7 +637,7 @@
     }
 
     /** Get the group key, reformatted for logging, for the (optional) group */
-    public static String logGroupKey(NotificationGroup group) {
+    private static String logGroupKey(NotificationGroup group) {
         if (group == null) {
             return "null";
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/VisualStabilityManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/VisualStabilityManager.java
index 456bf51..bb8c0e0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/VisualStabilityManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/VisualStabilityManager.java
@@ -16,84 +16,32 @@
 
 package com.android.systemui.statusbar.notification.collection.legacy;
 
-import android.os.Handler;
-import android.os.SystemClock;
-import android.view.View;
-
-import androidx.collection.ArraySet;
-
-import com.android.systemui.Dumpable;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.dump.DumpManager;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.notification.NotificationEntryListener;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.VisibilityLocationProvider;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
 import com.android.systemui.statusbar.notification.dagger.NotificationsModule;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
 
 /**
  * A manager that ensures that notifications are visually stable. It will suppress reorderings
  * and reorder at the right time when they are out of view.
  */
-public class VisualStabilityManager implements OnHeadsUpChangedListener, Dumpable {
+public class VisualStabilityManager {
 
-    private static final long TEMPORARY_REORDERING_ALLOWED_DURATION = 1000;
-
-    private final ArrayList<Callback> mReorderingAllowedCallbacks = new ArrayList<>();
-    private final ArraySet<Callback> mPersistentReorderingCallbacks = new ArraySet<>();
-    private final ArrayList<Callback> mGroupChangesAllowedCallbacks = new ArrayList<>();
-    private final ArraySet<Callback> mPersistentGroupCallbacks = new ArraySet<>();
-    private final Handler mHandler;
     private final VisualStabilityProvider mVisualStabilityProvider;
 
     private boolean mPanelExpanded;
     private boolean mScreenOn;
-    private boolean mReorderingAllowed;
-    private boolean mGroupChangedAllowed;
-    private boolean mIsTemporaryReorderingAllowed;
-    private long mTemporaryReorderingStart;
-    private VisibilityLocationProvider mVisibilityLocationProvider;
-    private ArraySet<View> mAllowedReorderViews = new ArraySet<>();
-    private ArraySet<NotificationEntry> mLowPriorityReorderingViews = new ArraySet<>();
-    private ArraySet<View> mAddedChildren = new ArraySet<>();
     private boolean mPulsing;
 
     /**
      * Injected constructor. See {@link NotificationsModule}.
      */
     public VisualStabilityManager(
-            NotificationEntryManager notificationEntryManager,
             VisualStabilityProvider visualStabilityProvider,
-            @Main Handler handler,
             StatusBarStateController statusBarStateController,
-            WakefulnessLifecycle wakefulnessLifecycle,
-            DumpManager dumpManager) {
+            WakefulnessLifecycle wakefulnessLifecycle) {
 
         mVisualStabilityProvider = visualStabilityProvider;
-        mHandler = handler;
-        dumpManager.registerDumpable(this);
-
-        if (notificationEntryManager != null) {
-            notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
-                @Override
-                public void onPreEntryUpdated(NotificationEntry entry) {
-                    final boolean ambientStateHasChanged =
-                            entry.isAmbient() != entry.getRow().isLowPriority();
-                    if (ambientStateHasChanged) {
-                        // note: entries are removed in onReorderingFinished
-                        mLowPriorityReorderingViews.add(entry);
-                    }
-                }
-            });
-        }
 
         if (statusBarStateController != null) {
             setPulsing(statusBarStateController.isPulsing());
@@ -116,40 +64,6 @@
     }
 
     /**
-     * Add a callback to invoke when reordering is allowed again.
-     *
-     * @param callback the callback to add
-     * @param persistent {@code true} if this callback should this callback be persisted, otherwise
-     *                               it will be removed after a single invocation
-     */
-    public void addReorderingAllowedCallback(Callback callback, boolean persistent) {
-        if (persistent) {
-            mPersistentReorderingCallbacks.add(callback);
-        }
-        if (mReorderingAllowedCallbacks.contains(callback)) {
-            return;
-        }
-        mReorderingAllowedCallbacks.add(callback);
-    }
-
-    /**
-     * Add a callback to invoke when group changes are allowed again.
-     *
-     * @param callback the callback to add
-     * @param persistent {@code true} if this callback should this callback be persisted, otherwise
-     *                               it will be removed after a single invocation
-     */
-    public void addGroupChangesAllowedCallback(Callback callback, boolean persistent) {
-        if (persistent) {
-            mPersistentGroupCallbacks.add(callback);
-        }
-        if (mGroupChangesAllowedCallbacks.contains(callback)) {
-            return;
-        }
-        mGroupChangesAllowedCallbacks.add(callback);
-    }
-
-    /**
      * @param screenOn whether the screen is on
      */
     private void setScreenOn(boolean screenOn) {
@@ -177,133 +91,8 @@
     }
 
     private void updateAllowedStates() {
-        boolean reorderingAllowed =
-                (!mScreenOn || !mPanelExpanded || mIsTemporaryReorderingAllowed) && !mPulsing;
-        boolean changedToTrue = reorderingAllowed && !mReorderingAllowed;
-        mReorderingAllowed = reorderingAllowed;
-        if (changedToTrue) {
-            notifyChangeAllowed(mReorderingAllowedCallbacks, mPersistentReorderingCallbacks);
-        }
+        boolean reorderingAllowed = (!mScreenOn || !mPanelExpanded) && !mPulsing;
         mVisualStabilityProvider.setReorderingAllowed(reorderingAllowed);
-        boolean groupChangesAllowed = (!mScreenOn || !mPanelExpanded) && !mPulsing;
-        changedToTrue = groupChangesAllowed && !mGroupChangedAllowed;
-        mGroupChangedAllowed = groupChangesAllowed;
-        if (changedToTrue) {
-            notifyChangeAllowed(mGroupChangesAllowedCallbacks, mPersistentGroupCallbacks);
-        }
-    }
-
-    private void notifyChangeAllowed(ArrayList<Callback> callbacks,
-            ArraySet<Callback> persistentCallbacks) {
-        for (int i = 0; i < callbacks.size(); i++) {
-            Callback callback = callbacks.get(i);
-            callback.onChangeAllowed();
-            if (!persistentCallbacks.contains(callback)) {
-                callbacks.remove(callback);
-                i--;
-            }
-        }
-    }
-
-    /**
-     * @return whether reordering is currently allowed in general.
-     */
-    public boolean isReorderingAllowed() {
-        return mReorderingAllowed;
-    }
-
-    /**
-     * @return whether changes in the grouping should be allowed right now.
-     */
-    public boolean areGroupChangesAllowed() {
-        return mGroupChangedAllowed;
-    }
-
-    /**
-     * @return whether a specific notification is allowed to reorder. Certain notifications are
-     * allowed to reorder even if {@link #isReorderingAllowed()} returns false, like newly added
-     * notifications or heads-up notifications that are out of view.
-     */
-    public boolean canReorderNotification(ExpandableNotificationRow row) {
-        if (mReorderingAllowed) {
-            return true;
-        }
-        if (mAddedChildren.contains(row)) {
-            return true;
-        }
-        if (mLowPriorityReorderingViews.contains(row.getEntry())) {
-            return true;
-        }
-        if (mAllowedReorderViews.contains(row)
-                && !mVisibilityLocationProvider.isInVisibleLocation(row.getEntry())) {
-            return true;
-        }
-        return false;
-    }
-
-    public void setVisibilityLocationProvider(
-            VisibilityLocationProvider visibilityLocationProvider) {
-        mVisibilityLocationProvider = visibilityLocationProvider;
-    }
-
-    /**
-     * Notifications have been reordered, so reset all the allowed list of views that are allowed
-     * to reorder.
-     */
-    public void onReorderingFinished() {
-        mAllowedReorderViews.clear();
-        mAddedChildren.clear();
-        mLowPriorityReorderingViews.clear();
-    }
-
-    @Override
-    public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
-        if (isHeadsUp) {
-            // Heads up notifications should in general be allowed to reorder if they are out of
-            // view and stay at the current location if they aren't.
-            mAllowedReorderViews.add(entry.getRow());
-        }
-    }
-
-    /**
-     * Temporarily allows reordering of the entire shade for a period of 1000ms. Subsequent calls
-     * to this method will extend the timer.
-     */
-    public void temporarilyAllowReordering() {
-        mHandler.removeCallbacks(mOnTemporaryReorderingExpired);
-        mHandler.postDelayed(mOnTemporaryReorderingExpired, TEMPORARY_REORDERING_ALLOWED_DURATION);
-        if (!mIsTemporaryReorderingAllowed) {
-            mTemporaryReorderingStart = SystemClock.elapsedRealtime();
-        }
-        mIsTemporaryReorderingAllowed = true;
-        updateAllowedStates();
-    }
-
-    private final Runnable mOnTemporaryReorderingExpired = () -> {
-        mIsTemporaryReorderingAllowed = false;
-        updateAllowedStates();
-    };
-
-    /**
-     * Notify the visual stability manager that a new view was added and should be allowed to
-     * reorder next time.
-     */
-    public void notifyViewAddition(View view) {
-        mAddedChildren.add(view);
-    }
-
-    @Override
-    public void dump(PrintWriter pw, String[] args) {
-        pw.println("VisualStabilityManager state:");
-        pw.print("  mIsTemporaryReorderingAllowed="); pw.println(mIsTemporaryReorderingAllowed);
-        pw.print("  mTemporaryReorderingStart="); pw.println(mTemporaryReorderingStart);
-
-        long now = SystemClock.elapsedRealtime();
-        pw.print("    Temporary reordering window has been open for ");
-        pw.print(now - (mIsTemporaryReorderingAllowed ? mTemporaryReorderingStart : now));
-        pw.println("ms");
-
-        pw.println();
     }
 
     final WakefulnessLifecycle.Observer mWakefulnessObserver = new WakefulnessLifecycle.Observer() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index fac234c..eda2eec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -30,7 +30,6 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dagger.qualifiers.UiBackground;
-import com.android.systemui.dump.DumpManager;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -53,7 +52,6 @@
 import com.android.systemui.statusbar.notification.collection.inflation.BindEventManager;
 import com.android.systemui.statusbar.notification.collection.inflation.BindEventManagerImpl;
 import com.android.systemui.statusbar.notification.collection.inflation.NotifInflater;
-import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
 import com.android.systemui.statusbar.notification.collection.inflation.OnUserInteractionCallbackImpl;
 import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
 import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
@@ -123,22 +121,13 @@
             NotificationEntryManagerLogger logger,
             NotificationGroupManagerLegacy groupManager,
             NotifPipelineFlags notifPipelineFlags,
-            Lazy<NotificationRowBinder> notificationRowBinderLazy,
             Lazy<NotificationRemoteInputManager> notificationRemoteInputManagerLazy,
             LeakDetector leakDetector,
             IStatusBarService statusBarService,
-            DumpManager dumpManager,
             @Background Executor bgExecutor) {
         return new NotificationEntryManager(
-                logger,
-                groupManager,
-                notifPipelineFlags,
-                notificationRowBinderLazy,
-                notificationRemoteInputManagerLazy,
-                leakDetector,
-                statusBarService,
-                dumpManager,
-                bgExecutor);
+                logger
+        );
     }
 
     /** Provides an instance of {@link NotificationGutsManager} */
@@ -162,8 +151,7 @@
             Optional<BubblesManager> bubblesManagerOptional,
             UiEventLogger uiEventLogger,
             OnUserInteractionCallback onUserInteractionCallback,
-            ShadeController shadeController,
-            DumpManager dumpManager) {
+            ShadeController shadeController) {
         return new NotificationGutsManager(
                 context,
                 centralSurfacesOptionalLazy,
@@ -181,8 +169,8 @@
                 bubblesManagerOptional,
                 uiEventLogger,
                 onUserInteractionCallback,
-                shadeController,
-                dumpManager);
+                shadeController
+        );
     }
 
     /** Provides an instance of {@link NotifGutsViewManager} */
@@ -193,19 +181,14 @@
     @SysUISingleton
     @Provides
     static VisualStabilityManager provideVisualStabilityManager(
-            NotificationEntryManager notificationEntryManager,
             VisualStabilityProvider visualStabilityProvider,
-            @Main Handler handler,
             StatusBarStateController statusBarStateController,
-            WakefulnessLifecycle wakefulnessLifecycle,
-            DumpManager dumpManager) {
+            WakefulnessLifecycle wakefulnessLifecycle) {
         return new VisualStabilityManager(
-                notificationEntryManager,
                 visualStabilityProvider,
-                handler,
                 statusBarStateController,
-                wakefulnessLifecycle,
-                dumpManager);
+                wakefulnessLifecycle
+        );
     }
 
     /** Provides an instance of {@link NotificationLogger} */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpController.java
deleted file mode 100644
index 74fb3f7..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpController.java
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification.interruption;
-
-import static com.android.systemui.statusbar.NotificationRemoteInputManager.FORCE_REMOTE_INPUT_HISTORY;
-
-import android.app.Notification;
-import android.service.notification.StatusBarNotification;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.NotificationListener;
-import com.android.systemui.statusbar.NotificationRemoteInputManager;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
-import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
-
-import javax.inject.Inject;
-
-/**
- * Controller class for old pipeline heads up logic. It listens to {@link NotificationEntryManager}
- * entry events and appropriately binds or unbinds the heads up view and promotes it to the top
- * of the screen.
- */
-@SysUISingleton
-public class HeadsUpController {
-    private final HeadsUpViewBinder mHeadsUpViewBinder;
-    private final NotificationInterruptStateProvider mInterruptStateProvider;
-    private final NotificationRemoteInputManager mRemoteInputManager;
-    private final VisualStabilityManager mVisualStabilityManager;
-    private final StatusBarStateController mStatusBarStateController;
-    private final NotificationListener mNotificationListener;
-    private final HeadsUpManager mHeadsUpManager;
-
-    @Inject
-    HeadsUpController(
-            HeadsUpViewBinder headsUpViewBinder,
-            NotificationInterruptStateProvider notificationInterruptStateProvider,
-            HeadsUpManager headsUpManager,
-            NotificationRemoteInputManager remoteInputManager,
-            StatusBarStateController statusBarStateController,
-            VisualStabilityManager visualStabilityManager,
-            NotificationListener notificationListener) {
-        mHeadsUpViewBinder = headsUpViewBinder;
-        mHeadsUpManager = headsUpManager;
-        mInterruptStateProvider = notificationInterruptStateProvider;
-        mRemoteInputManager = remoteInputManager;
-        mStatusBarStateController = statusBarStateController;
-        mVisualStabilityManager = visualStabilityManager;
-        mNotificationListener = notificationListener;
-    }
-
-    /**
-     * Attach this controller and add its listeners.
-     */
-    public void attach(
-            NotificationEntryManager entryManager,
-            HeadsUpManager headsUpManager) {
-        entryManager.addCollectionListener(mCollectionListener);
-        headsUpManager.addListener(mOnHeadsUpChangedListener);
-    }
-
-    private NotifCollectionListener mCollectionListener = new NotifCollectionListener() {
-        @Override
-        public void onEntryAdded(NotificationEntry entry) {
-            if (mInterruptStateProvider.shouldHeadsUp(entry)) {
-                mHeadsUpViewBinder.bindHeadsUpView(
-                        entry, HeadsUpController.this::showAlertingView);
-            }
-        }
-
-        @Override
-        public void onEntryUpdated(NotificationEntry entry) {
-            updateHunState(entry);
-        }
-
-        @Override
-        public void onEntryRemoved(NotificationEntry entry, int reason) {
-            stopAlerting(entry);
-        }
-
-        @Override
-        public void onEntryCleanUp(NotificationEntry entry) {
-            mHeadsUpViewBinder.abortBindCallback(entry);
-        }
-    };
-
-    /**
-     * Adds the entry to the HUN manager and show it for the first time.
-     */
-    private void showAlertingView(NotificationEntry entry) {
-        mHeadsUpManager.showNotification(entry);
-        if (!mStatusBarStateController.isDozing()) {
-            // Mark as seen immediately
-            setNotificationShown(entry.getSbn());
-        }
-    }
-
-    private void updateHunState(NotificationEntry entry) {
-        boolean hunAgain = alertAgain(entry, entry.getSbn().getNotification());
-        // includes check for whether this notification should be filtered:
-        boolean shouldHeadsUp = mInterruptStateProvider.shouldHeadsUp(entry);
-        final boolean wasHeadsUp = mHeadsUpManager.isAlerting(entry.getKey());
-        if (wasHeadsUp) {
-            if (shouldHeadsUp) {
-                mHeadsUpManager.updateNotification(entry.getKey(), hunAgain);
-            } else {
-                // We don't want this to be interrupting anymore, let's remove it
-                mHeadsUpManager.removeNotification(entry.getKey(), false /* removeImmediately */);
-            }
-        } else if (shouldHeadsUp && hunAgain) {
-            mHeadsUpViewBinder.bindHeadsUpView(entry, mHeadsUpManager::showNotification);
-        }
-    }
-
-    private void setNotificationShown(StatusBarNotification n) {
-        try {
-            mNotificationListener.setNotificationsShown(new String[]{n.getKey()});
-        } catch (RuntimeException e) {
-            Log.d(TAG, "failed setNotificationsShown: ", e);
-        }
-    }
-
-    private void stopAlerting(NotificationEntry entry) {
-        // Attempt to remove notifications from their HUN manager.
-        // Though the remove itself may fail, it lets the manager know to remove as soon as
-        // possible.
-        String key = entry.getKey();
-        if (mHeadsUpManager.isAlerting(key)) {
-            // A cancel() in response to a remote input shouldn't be delayed, as it makes the
-            // sending look longer than it takes.
-            // Also we should not defer the removal if reordering isn't allowed since otherwise
-            // some notifications can't disappear before the panel is closed.
-            boolean ignoreEarliestRemovalTime =
-                    mRemoteInputManager.isSpinning(key)
-                            && !FORCE_REMOTE_INPUT_HISTORY
-                            || !mVisualStabilityManager.isReorderingAllowed();
-            mHeadsUpManager.removeNotification(key, ignoreEarliestRemovalTime);
-        }
-    }
-
-    /**
-     * Checks whether an update for a notification warrants an alert for the user.
-     *
-     * @param oldEntry the entry for this notification.
-     * @param newNotification the new notification for this entry.
-     * @return whether this notification should alert the user.
-     */
-    public static boolean alertAgain(
-            NotificationEntry oldEntry, Notification newNotification) {
-        return oldEntry == null || !oldEntry.hasInterrupted()
-                || (newNotification.flags & Notification.FLAG_ONLY_ALERT_ONCE) == 0;
-    }
-
-    private OnHeadsUpChangedListener mOnHeadsUpChangedListener  = new OnHeadsUpChangedListener() {
-        @Override
-        public void onHeadsUpStateChanged(@NonNull NotificationEntry entry, boolean isHeadsUp) {
-            if (!isHeadsUp && !entry.getRow().isRemoved()) {
-                mHeadsUpViewBinder.unbindHeadsUpView(entry);
-            }
-        }
-    };
-
-    private static final String TAG = "HeadsUpBindController";
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinder.java
index 5ef2b9e..6f41425 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinder.java
@@ -41,8 +41,7 @@
  * figuring out the right heads up inflation parameters and inflating/freeing the heads up
  * content view.
  *
- * TODO: This should be moved into {@link HeadsUpCoordinator} when the old pipeline is deprecated
- * (i.e. when {@link HeadsUpController} is removed).
+ * TODO: This should be moved into {@link HeadsUpCoordinator} when the old pipeline is deprecated.
  */
 @SysUISingleton
 public class HeadsUpViewBinder {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProvider.kt
index 0b6b929..c956a2e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProvider.kt
@@ -1,6 +1,7 @@
 package com.android.systemui.statusbar.notification.interruption
 
 import android.app.Notification
+import android.app.Notification.VISIBILITY_SECRET
 import android.content.BroadcastReceiver
 import android.content.Context
 import android.content.Intent
@@ -172,6 +173,8 @@
         !lockscreenUserManager.shouldShowLockscreenNotifications() -> true
         // User settings do not allow this notification on the lockscreen, so hide it.
         userSettingsDisallowNotification(entry) -> true
+        // Entry is explicitly marked SECRET, so hide it.
+        entry.sbn.notification.visibility == VISIBILITY_SECRET -> true
         // if entry is silent, apply custom logic to see if should hide
         shouldHideIfEntrySilent(entry) -> true
         else -> false
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 3c01802..9ad906c 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
@@ -94,7 +94,6 @@
 import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorController;
 import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
 import com.android.systemui.statusbar.notification.logging.NotificationCounters;
@@ -904,21 +903,6 @@
         return mChildrenContainer == null ? null : mChildrenContainer.getAttachedChildren();
     }
 
-    /**
-     * Apply the order given in the list to the children.
-     *
-     * @param childOrder the new list order
-     * @param visualStabilityManager
-     * @param callback the callback to invoked in case it is not allowed
-     * @return whether the list order has changed
-     */
-    public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder,
-            VisualStabilityManager visualStabilityManager,
-            VisualStabilityManager.Callback callback) {
-        return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder,
-                visualStabilityManager, callback);
-    }
-
     /** Updates states of all children. */
     public void updateChildrenStates(AmbientState ambientState) {
         if (mIsSummaryWithChildren) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FeedbackInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FeedbackInfo.java
index 2b782b6..3f4fd50 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FeedbackInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FeedbackInfo.java
@@ -165,7 +165,7 @@
     }
 
     private void positiveFeedback(View v) {
-        mGutsContainer.closeControls(v, false);
+        mGutsContainer.closeControls(v, /* save= */ false);
         handleFeedback(true);
     }
 
@@ -176,7 +176,7 @@
             menuItem = mMenuRowPlugin.getLongpressMenuItem(mContext);
         }
 
-        mGutsContainer.closeControls(v, false);
+        mGutsContainer.closeControls(v, /* save= */ false);
         mNotificationGutsManager.openGuts(mExpandableNotificationRow, 0, 0, menuItem);
         handleFeedback(false);
     }
@@ -203,7 +203,7 @@
     }
 
     private void closeControls(View v) {
-        mGutsContainer.closeControls(v, false);
+        mGutsContainer.closeControls(v, /* save= */ false);
     }
 
     @Override
@@ -232,7 +232,7 @@
     }
 
     @Override
-    public boolean shouldBeSaved() {
+    public boolean shouldBeSavedOnClose() {
         return false;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
index 7120fe5..0ce9656 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
@@ -157,7 +157,7 @@
             mShadeController.animateCollapsePanels();
             mPeopleSpaceWidgetManager.requestPinAppWidget(mShortcutInfo, new Bundle());
         }
-        mGutsContainer.closeControls(v, true);
+        mGutsContainer.closeControls(v, /* save= */ true);
     };
 
     public NotificationConversationInfo(Context context, AttributeSet attrs) {
@@ -186,7 +186,6 @@
     }
 
     public void bindNotification(
-            @Action int selectedAction,
             ShortcutManager shortcutManager,
             PackageManager pm,
             PeopleSpaceWidgetManager peopleSpaceWidgetManager,
@@ -205,8 +204,6 @@
             OnConversationSettingsClickListener onConversationSettingsClickListener,
             Optional<BubblesManager> bubblesManagerOptional,
             ShadeController shadeController) {
-        mPressedApply = false;
-        mSelectedAction = selectedAction;
         mINotificationManager = iNotificationManager;
         mPeopleSpaceWidgetManager = peopleSpaceWidgetManager;
         mOnUserInteractionCallback = onUserInteractionCallback;
@@ -417,9 +414,7 @@
     }
 
     @Override
-    public void onFinishedClosing() {
-        mSelectedAction = -1;
-    }
+    public void onFinishedClosing() { }
 
     @Override
     public boolean needsFalsingProtection() {
@@ -564,7 +559,7 @@
     }
 
     @Override
-    public boolean shouldBeSaved() {
+    public boolean shouldBeSavedOnClose() {
         return mPressedApply;
     }
 
@@ -578,6 +573,12 @@
         if (save && mSelectedAction > -1) {
             updateChannel();
         }
+
+        // Clear the selected importance when closing, so when when we open again,
+        // we starts from a clean state.
+        mSelectedAction = -1;
+        mPressedApply = false;
+
         return false;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
index fc296e1..93f0812 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
@@ -76,7 +76,7 @@
 
                     switch (action) {
                         case AccessibilityNodeInfo.ACTION_LONG_CLICK:
-                            closeControls(host, false);
+                            closeControls(host, /* save= */ false);
                             return true;
                     }
 
@@ -123,7 +123,7 @@
         /**
          * Return whether something changed and needs to be saved, possibly requiring a bouncer.
          */
-        boolean shouldBeSaved();
+        boolean shouldBeSavedOnClose();
 
         /**
          * Called when the guts view has finished its close animation.
@@ -259,7 +259,7 @@
         if (mGutsContent != null) {
             if ((mGutsContent.isLeavebehind() && leavebehinds)
                     || (!mGutsContent.isLeavebehind() && controls)) {
-                closeControls(x, y, mGutsContent.shouldBeSaved(), force);
+                closeControls(x, y, mGutsContent.shouldBeSavedOnClose(), force);
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index c4ff259..ea12b82 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -55,7 +55,6 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.settings.UserContextProvider;
 import com.android.systemui.shade.ShadeController;
-import com.android.systemui.statusbar.NotificationLifetimeExtender;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.StatusBarState;
@@ -81,8 +80,7 @@
  * Handles various NotificationGuts related tasks, such as binding guts to a row, opening and
  * closing guts, and keeping track of the currently exposed notification guts.
  */
-public class NotificationGutsManager implements Dumpable, NotificationLifetimeExtender,
-        NotifGutsViewManager {
+public class NotificationGutsManager implements NotifGutsViewManager {
     private static final String TAG = "NotificationGutsManager";
 
     // Must match constant in Settings. Used to highlight preferences when linking to Settings.
@@ -107,13 +105,10 @@
     // which notification is currently being longpress-examined by the user
     private NotificationGuts mNotificationGutsExposed;
     private NotificationMenuRowPlugin.MenuItem mGutsMenuItem;
-    private NotificationSafeToRemoveCallback mNotificationLifetimeFinishedCallback;
     private NotificationPresenter mPresenter;
     private NotificationActivityStarter mNotificationActivityStarter;
     private NotificationListContainer mListContainer;
     private OnSettingsClickListener mOnSettingsClickListener;
-    @VisibleForTesting
-    protected String mKeyToRemoveOnGutsClosed;
 
     private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy;
     private final Handler mMainHandler;
@@ -148,8 +143,7 @@
             Optional<BubblesManager> bubblesManagerOptional,
             UiEventLogger uiEventLogger,
             OnUserInteractionCallback onUserInteractionCallback,
-            ShadeController shadeController,
-            DumpManager dumpManager) {
+            ShadeController shadeController) {
         mContext = context;
         mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
         mMainHandler = mainHandler;
@@ -167,8 +161,6 @@
         mUiEventLogger = uiEventLogger;
         mOnUserInteractionCallback = onUserInteractionCallback;
         mShadeController = shadeController;
-
-        dumpManager.registerDumpable(this);
     }
 
     public void setUpWithPresenter(NotificationPresenter presenter,
@@ -266,12 +258,6 @@
                 mGutsListener.onGutsClose(entry);
             }
             String key = entry.getKey();
-            if (key.equals(mKeyToRemoveOnGutsClosed)) {
-                mKeyToRemoveOnGutsClosed = null;
-                if (mNotificationLifetimeFinishedCallback != null) {
-                    mNotificationLifetimeFinishedCallback.onSafeToRemove(key);
-                }
-            }
         });
 
         View gutsView = item.getGutsView();
@@ -477,7 +463,6 @@
                         R.dimen.notification_guts_conversation_icon_size));
 
         notificationInfoView.bindNotification(
-                notificationInfoView.getSelectedAction(),
                 mShortcutManager,
                 pmUser,
                 mPeopleSpaceWidgetManager,
@@ -658,46 +643,6 @@
         return true;
     }
 
-    @Override
-    public void setCallback(NotificationSafeToRemoveCallback callback) {
-        mNotificationLifetimeFinishedCallback = callback;
-    }
-
-    @Override
-    public boolean shouldExtendLifetime(NotificationEntry entry) {
-        return entry != null
-                &&(mNotificationGutsExposed != null
-                    && entry.getGuts() != null
-                    && mNotificationGutsExposed == entry.getGuts()
-                    && !mNotificationGutsExposed.isLeavebehind());
-    }
-
-    @Override
-    public void setShouldManageLifetime(NotificationEntry entry, boolean shouldExtend) {
-        if (shouldExtend) {
-            mKeyToRemoveOnGutsClosed = entry.getKey();
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "Keeping notification because it's showing guts. " + entry.getKey());
-            }
-        } else {
-            if (mKeyToRemoveOnGutsClosed != null
-                    && mKeyToRemoveOnGutsClosed.equals(entry.getKey())) {
-                mKeyToRemoveOnGutsClosed = null;
-                if (Log.isLoggable(TAG, Log.DEBUG)) {
-                    Log.d(TAG, "Notification that was kept for guts was updated. "
-                            + entry.getKey());
-                }
-            }
-        }
-    }
-
-    @Override
-    public void dump(PrintWriter pw, String[] args) {
-        pw.println("NotificationGutsManager state:");
-        pw.print("  mKeyToRemoveOnGutsClosed (legacy): ");
-        pw.println(mKeyToRemoveOnGutsClosed);
-    }
-
     /**
      * @param gutsListener the listener for open and close guts events
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
index 8b01a47..ea0060a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
@@ -158,7 +158,7 @@
     // used by standard ui
     private OnClickListener mOnDismissSettings = v -> {
         mPressedApply = true;
-        mGutsContainer.closeControls(v, true);
+        mGutsContainer.closeControls(v, /* save= */ true);
     };
 
     public NotificationInfo(Context context, AttributeSet attrs) {
@@ -541,10 +541,6 @@
 
     @Override
     public void onFinishedClosing() {
-        if (mChosenImportance != null) {
-            mStartingChannelImportance = mChosenImportance;
-        }
-
         bindInlineControls();
 
         logUiEvent(NotificationControlsEvent.NOTIFICATION_CONTROLS_CLOSE);
@@ -604,7 +600,7 @@
     }
 
     @Override
-    public boolean shouldBeSaved() {
+    public boolean shouldBeSavedOnClose() {
         return mPressedApply;
     }
 
@@ -627,6 +623,12 @@
         if (save) {
             saveImportance();
         }
+
+        // Clear the selected importance when closing, so when when we open again,
+        // we starts from a clean state.
+        mChosenImportance = null;
+        mPressedApply = false;
+
         return false;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
index 512b049..adbfa75 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
@@ -384,7 +384,7 @@
     private void undoSnooze(View v) {
         mSelectedOption = null;
         showSnoozeOptions(false);
-        mGutsContainer.closeControls(v, false);
+        mGutsContainer.closeControls(v, /* save= */ false);
     }
 
     @Override
@@ -433,7 +433,7 @@
     }
 
     @Override
-    public boolean shouldBeSaved() {
+    public boolean shouldBeSavedOnClose() {
         return true;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
index 186ffa6..ac97e77 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
@@ -16,22 +16,13 @@
 
 package com.android.systemui.statusbar.notification.row;
 
-import static android.app.Notification.EXTRA_IS_GROUP_CONVERSATION;
-
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
-import android.annotation.IntDef;
 import android.app.INotificationManager;
-import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationChannelGroup;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
-import android.os.Bundle;
-import android.os.Parcelable;
 import android.os.RemoteException;
 import android.service.notification.StatusBarNotification;
 import android.text.TextUtils;
@@ -46,8 +37,6 @@
 import com.android.systemui.R;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
-import java.lang.annotation.Retention;
-import java.util.List;
 import java.util.Set;
 
 /**
@@ -71,8 +60,6 @@
     private Set<NotificationChannel> mUniqueChannelsInRow;
     private Drawable mPkgIcon;
 
-    private @Action int mSelectedAction = -1;
-    private boolean mPressedApply;
     private boolean mPresentingChannelEditorDialog = false;
 
     private NotificationInfo.OnSettingsClickListener mOnSettingsClickListener;
@@ -82,14 +69,8 @@
     @VisibleForTesting
     boolean mSkipPost = false;
 
-    @Retention(SOURCE)
-    @IntDef({ACTION_SETTINGS})
-    private @interface Action {}
-    static final int ACTION_SETTINGS = 5;
-
     private OnClickListener mOnDone = v -> {
-        mPressedApply = true;
-        mGutsContainer.closeControls(v, true);
+        mGutsContainer.closeControls(v, /* save= */ false);
     };
 
     public PartialConversationInfo(Context context, AttributeSet attrs) {
@@ -107,7 +88,6 @@
             NotificationInfo.OnSettingsClickListener onSettingsClick,
             boolean isDeviceProvisioned,
             boolean isNonBlockable) {
-        mSelectedAction = -1;
         mINotificationManager = iNotificationManager;
         mPackageName = pkg;
         mSbn = entry.getSbn();
@@ -286,8 +266,8 @@
     }
 
     @Override
-    public boolean shouldBeSaved() {
-        return mPressedApply;
+    public boolean shouldBeSavedOnClose() {
+        return false;
     }
 
     @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 a76f0827..d77e03f 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
@@ -43,7 +43,6 @@
 import com.android.systemui.statusbar.notification.FeedbackIcon;
 import com.android.systemui.statusbar.notification.NotificationFadeAware;
 import com.android.systemui.statusbar.notification.NotificationUtils;
-import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
 import com.android.systemui.statusbar.notification.row.HybridGroupManager;
@@ -462,39 +461,6 @@
         return mAttachedChildren;
     }
 
-    /**
-     * Apply the order given in the list to the children.
-     *
-     * @param childOrder the new list order
-     * @param visualStabilityManager
-     * @param callback
-     * @return whether the list order has changed
-     */
-    public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder,
-            VisualStabilityManager visualStabilityManager,
-            VisualStabilityManager.Callback callback) {
-        if (childOrder == null) {
-            return false;
-        }
-        boolean result = false;
-        for (int i = 0; i < mAttachedChildren.size() && i < childOrder.size(); i++) {
-            ExpandableNotificationRow child = mAttachedChildren.get(i);
-            ExpandableNotificationRow desiredChild = childOrder.get(i);
-            if (child != desiredChild) {
-                if (visualStabilityManager.canReorderNotification(desiredChild)) {
-                    mAttachedChildren.remove(desiredChild);
-                    mAttachedChildren.add(i, desiredChild);
-                    result = true;
-                } else {
-                    visualStabilityManager.addReorderingAllowedCallback(callback,
-                            false /* persistent */);
-                }
-            }
-        }
-        updateExpansionStates();
-        return result;
-    }
-
     /** To be called any time the rows have been updated */
     public void updateExpansionStates() {
         if (mChildrenExpanded || mUserLocked) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
index 54e26c3..91a2813 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
@@ -20,9 +20,6 @@
 import android.view.View
 import com.android.internal.annotations.VisibleForTesting
 import com.android.systemui.media.KeyguardMediaController
-import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.statusbar.StatusBarState
-import com.android.systemui.statusbar.notification.NotifPipelineFlags
 import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
 import com.android.systemui.statusbar.notification.collection.render.MediaContainerController
 import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController
@@ -33,32 +30,20 @@
 import com.android.systemui.statusbar.notification.dagger.SilentHeader
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.ExpandableView
-import com.android.systemui.statusbar.notification.row.StackScrollerDecorView
 import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.SectionProvider
 import com.android.systemui.statusbar.policy.ConfigurationController
-import com.android.systemui.util.children
 import com.android.systemui.util.foldToSparseArray
-import com.android.systemui.util.takeUntil
-import com.android.systemui.util.traceSection
 import javax.inject.Inject
 
 /**
- * Manages the boundaries of the notification sections (incoming, conversations, high priority, and
- * low priority).
- *
- * In the legacy notification pipeline, this is responsible for correctly positioning all section
- * headers after the [NotificationStackScrollLayout] has had notifications added/removed/changed. In
- * the new pipeline, this is handled as part of the [ShadeViewManager].
+ * Manages section headers in the NSSL.
  *
  * TODO: Move remaining sections logic from NSSL into this class.
  */
 class NotificationSectionsManager @Inject internal constructor(
-    private val statusBarStateController: StatusBarStateController,
     private val configurationController: ConfigurationController,
     private val keyguardMediaController: KeyguardMediaController,
     private val sectionsFeatureManager: NotificationSectionsFeatureManager,
-    private val logger: NotificationSectionsLogger,
-    private val notifPipelineFlags: NotifPipelineFlags,
     private val mediaContainerController: MediaContainerController,
     @IncomingHeader private val incomingHeaderController: SectionHeaderController,
     @PeopleHeader private val peopleHeaderController: SectionHeaderController,
@@ -139,205 +124,6 @@
         else -> null
     }
 
-    private fun logShadeChild(i: Int, child: View) {
-        when {
-            child === incomingHeaderView -> logger.logIncomingHeader(i)
-            child === mediaControlsView -> logger.logMediaControls(i)
-            child === peopleHeaderView -> logger.logConversationsHeader(i)
-            child === alertingHeaderView -> logger.logAlertingHeader(i)
-            child === silentHeaderView -> logger.logSilentHeader(i)
-            child !is ExpandableNotificationRow -> logger.logOther(i, child.javaClass)
-            else -> {
-                val isHeadsUp = child.isHeadsUp
-                when (child.entry.bucket) {
-                    BUCKET_HEADS_UP -> logger.logHeadsUp(i, isHeadsUp)
-                    BUCKET_PEOPLE -> logger.logConversation(i, isHeadsUp)
-                    BUCKET_ALERTING -> logger.logAlerting(i, isHeadsUp)
-                    BUCKET_SILENT -> logger.logSilent(i, isHeadsUp)
-                }
-            }
-        }
-    }
-    private fun logShadeContents() = traceSection("NotifSectionsManager.logShadeContents") {
-        parent.children.forEachIndexed(::logShadeChild)
-    }
-
-    private val isUsingMultipleSections: Boolean
-        get() = sectionsFeatureManager.getNumberOfBuckets() > 1
-
-    @VisibleForTesting
-    fun updateSectionBoundaries() = updateSectionBoundaries("test")
-
-    private interface SectionUpdateState<out T : ExpandableView> {
-        val header: T
-        var currentPosition: Int?
-        var targetPosition: Int?
-        fun adjustViewPosition()
-    }
-
-    private fun <T : ExpandableView> expandableViewHeaderState(header: T): SectionUpdateState<T> =
-            object : SectionUpdateState<T> {
-                override val header = header
-                override var currentPosition: Int? = null
-                override var targetPosition: Int? = null
-
-                override fun adjustViewPosition() {
-                    notifPipelineFlags.checkLegacyPipelineEnabled()
-                    val target = targetPosition
-                    val current = currentPosition
-                    if (target == null) {
-                        if (current != null) {
-                            parent.removeView(header)
-                        }
-                    } else {
-                        if (current == null) {
-                            // If the header is animating away, it will still have a parent, so
-                            // detach it first
-                            // TODO: We should really cancel the active animations here. This will
-                            //  happen automatically when the view's intro animation starts, but
-                            //  it's a fragile link.
-                            header.removeFromTransientContainer()
-                            parent.addView(header, target)
-                        } else {
-                            parent.changeViewPosition(header, target)
-                        }
-                    }
-                }
-    }
-
-    private fun <T : StackScrollerDecorView> decorViewHeaderState(
-        header: T
-    ): SectionUpdateState<T> {
-        notifPipelineFlags.checkLegacyPipelineEnabled()
-        val inner = expandableViewHeaderState(header)
-        return object : SectionUpdateState<T> by inner {
-            override fun adjustViewPosition() {
-                inner.adjustViewPosition()
-                if (targetPosition != null && currentPosition == null) {
-                    header.isContentVisible = true
-                }
-            }
-        }
-    }
-
-    /**
-     * Should be called whenever notifs are added, removed, or updated. Updates section boundary
-     * bookkeeping and adds/moves/removes section headers if appropriate.
-     */
-    fun updateSectionBoundaries(reason: String) = traceSection("NotifSectionsManager.update") {
-        notifPipelineFlags.checkLegacyPipelineEnabled()
-        if (!isUsingMultipleSections) {
-            return@traceSection
-        }
-        logger.logStartSectionUpdate(reason)
-
-        // The overall strategy here is to iterate over the current children of mParent, looking
-        // for where the sections headers are currently positioned, and where each section begins.
-        // Then, once we find the start of a new section, we track that position as the "target" for
-        // the section header, adjusted for the case where existing headers are in front of that
-        // target, but won't be once they are moved / removed after the pass has completed.
-
-        val showHeaders = statusBarStateController.state != StatusBarState.KEYGUARD
-        val usingMediaControls = sectionsFeatureManager.isMediaControlsEnabled()
-
-        val mediaState = mediaControlsView?.let(::expandableViewHeaderState)
-        val incomingState = incomingHeaderView?.let(::decorViewHeaderState)
-        val peopleState = peopleHeaderView?.let(::decorViewHeaderState)
-        val alertingState = alertingHeaderView?.let(::decorViewHeaderState)
-        val gentleState = silentHeaderView?.let(::decorViewHeaderState)
-
-        fun getSectionState(view: View): SectionUpdateState<ExpandableView>? = when {
-            view === mediaControlsView -> mediaState
-            view === incomingHeaderView -> incomingState
-            view === peopleHeaderView -> peopleState
-            view === alertingHeaderView -> alertingState
-            view === silentHeaderView -> gentleState
-            else -> null
-        }
-
-        val headersOrdered = sequenceOf(
-                mediaState, incomingState, peopleState, alertingState, gentleState
-        ).filterNotNull()
-
-        var peopleNotifsPresent = false
-        var nextBucket: Int? = null
-        var inIncomingSection = false
-
-        // Iterating backwards allows for easier construction of the Incoming section, as opposed
-        // to backtracking when a discontinuity in the sections is discovered.
-        // Iterating to -1 in order to support the case where a header is at the very top of the
-        // shade.
-        for (i in parent.childCount - 1 downTo -1) {
-            val child: View? = parent.getChildAt(i)
-
-            child?.let {
-                logShadeChild(i, child)
-                // If this child is a header, update the tracked positions
-                getSectionState(child)?.let { state ->
-                    state.currentPosition = i
-                    // If headers that should appear above this one in the shade already have a
-                    // target index, then we need to decrement them in order to account for this one
-                    // being either removed, or moved below them.
-                    headersOrdered.takeUntil { it === state }
-                            .forEach { it.targetPosition = it.targetPosition?.minus(1) }
-                }
-            }
-
-            val row = (child as? ExpandableNotificationRow)
-                    ?.takeUnless { it.visibility == View.GONE }
-
-            // Is there a section discontinuity? This usually occurs due to HUNs
-            inIncomingSection = inIncomingSection || nextBucket?.let { next ->
-                row?.entry?.bucket?.let { curr -> next < curr }
-            } == true
-
-            if (inIncomingSection) {
-                // Update the bucket to reflect that it's being placed in the Incoming section
-                row?.entry?.bucket = BUCKET_HEADS_UP
-            }
-
-            // Insert a header in front of the next row, if there's a boundary between it and this
-            // row, or if it is the topmost row.
-            val isSectionBoundary = nextBucket != null &&
-                    (child == null || row != null && nextBucket != row.entry.bucket)
-            if (isSectionBoundary && showHeaders) {
-                when (nextBucket) {
-                    BUCKET_SILENT -> gentleState?.targetPosition = i + 1
-                }
-            }
-
-            row ?: continue
-
-            // Check if there are any people notifications
-            peopleNotifsPresent = peopleNotifsPresent || row.entry.bucket == BUCKET_PEOPLE
-            nextBucket = row.entry.bucket
-        }
-
-        mediaState?.targetPosition = if (usingMediaControls) 0 else null
-
-        logger.logStr("New header target positions:")
-        logger.logMediaControls(mediaState?.targetPosition ?: -1)
-        logger.logIncomingHeader(incomingState?.targetPosition ?: -1)
-        logger.logConversationsHeader(peopleState?.targetPosition ?: -1)
-        logger.logAlertingHeader(alertingState?.targetPosition ?: -1)
-        logger.logSilentHeader(gentleState?.targetPosition ?: -1)
-
-        // Update headers in reverse order to preserve indices, otherwise movements earlier in the
-        // list will affect the target indices of the headers later in the list.
-        headersOrdered.asIterable().reversed().forEach { it.adjustViewPosition() }
-
-        logger.logStr("Final order:")
-        logShadeContents()
-        logger.logStr("Section boundary update complete")
-
-        // Update headers to reflect state of section contents
-        silentHeaderView?.run {
-            val hasActiveClearableNotifications = this@NotificationSectionsManager.parent
-                    .hasActiveClearableNotifications(NotificationStackScrollLayout.ROWS_GENTLE)
-            setClearSectionButtonEnabled(hasActiveClearableNotifications)
-        }
-    }
-
     private sealed class SectionBounds {
 
         data class Many(
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 427004e..952bafb 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
@@ -5822,12 +5822,6 @@
         mSpeedBumpIndexDirty = true;
     }
 
-    /** Updates the indices of the boundaries between sections. */
-    @ShadeViewRefactor(RefactorComponent.INPUT)
-    public void updateSectionBoundaries(String reason) {
-        mSectionsManager.updateSectionBoundaries(reason);
-    }
-
     void updateContinuousBackgroundDrawing() {
         boolean continuousBackground = !mAmbientState.isFullyAwake()
                 && mSwipeHelper.isSwiping();
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 cc539b0..9998fe4 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
@@ -90,7 +90,6 @@
 import com.android.systemui.statusbar.notification.collection.PipelineDumper;
 import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
 import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy.OnGroupChangeListener;
-import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
@@ -162,7 +161,6 @@
     private final NotificationEntryManager mNotificationEntryManager;
     private final UiEventLogger mUiEventLogger;
     private final NotificationRemoteInputManager mRemoteInputManager;
-    private final VisualStabilityManager mVisualStabilityManager;
     private final ShadeController mShadeController;
     private final KeyguardMediaController mKeyguardMediaController;
     private final SysuiStatusBarStateController mStatusBarStateController;
@@ -646,7 +644,6 @@
             ShadeTransitionController shadeTransitionController,
             UiEventLogger uiEventLogger,
             NotificationRemoteInputManager remoteInputManager,
-            VisualStabilityManager visualStabilityManager,
             ShadeController shadeController,
             InteractionJankMonitor jankMonitor,
             StackStateLogger stackLogger,
@@ -693,7 +690,6 @@
         mNotificationEntryManager = notificationEntryManager;
         mUiEventLogger = uiEventLogger;
         mRemoteInputManager = remoteInputManager;
-        mVisualStabilityManager = visualStabilityManager;
         mShadeController = shadeController;
         updateResources();
     }
@@ -765,8 +761,6 @@
         mNotificationRoundnessManager.setOnRoundingChangedCallback(mView::invalidate);
         mView.addOnExpandedHeightChangedListener(mNotificationRoundnessManager::setExpanded);
 
-        mVisualStabilityManager.setVisibilityLocationProvider(this::isInVisibleLocation);
-
         mTunerService.addTunable(
                 (key, newValue) -> {
                     switch (key) {
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 ee45c42..7da1d6c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -31,7 +31,7 @@
 import static androidx.lifecycle.Lifecycle.State.RESUMED;
 
 import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME;
-import static com.android.systemui.charging.WirelessChargingLayout.UNKNOWN_BATTERY_LEVEL;
+import static com.android.systemui.charging.WirelessChargingAnimation.UNKNOWN_BATTERY_LEVEL;
 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
 import static com.android.systemui.statusbar.NotificationLockscreenUserManager.PERMISSION_SELF;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
@@ -172,6 +172,7 @@
 import com.android.systemui.qs.QSFragment;
 import com.android.systemui.qs.QSPanelController;
 import com.android.systemui.recents.ScreenPinningRequest;
+import com.android.systemui.ripple.RippleShader.RippleShape;
 import com.android.systemui.scrim.ScrimView;
 import com.android.systemui.settings.brightness.BrightnessSliderController;
 import com.android.systemui.shade.NotificationPanelViewController;
@@ -206,7 +207,6 @@
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
-import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.init.NotificationsController;
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
@@ -704,7 +704,6 @@
             WakefulnessLifecycle wakefulnessLifecycle,
             SysuiStatusBarStateController statusBarStateController,
             Optional<Bubbles> bubblesOptional,
-            VisualStabilityManager visualStabilityManager,
             DeviceProvisionedController deviceProvisionedController,
             NavigationBarController navigationBarController,
             AccessibilityFloatingMenuController accessibilityFloatingMenuController,
@@ -792,7 +791,6 @@
         mWakefulnessLifecycle = wakefulnessLifecycle;
         mStatusBarStateController = statusBarStateController;
         mBubblesOptional = bubblesOptional;
-        mVisualStabilityManager = visualStabilityManager;
         mDeviceProvisionedController = deviceProvisionedController;
         mNavigationBarController = navigationBarController;
         mAccessibilityFloatingMenuController = accessibilityFloatingMenuController;
@@ -2211,7 +2209,8 @@
                     public void onAnimationEnded() {
                         mNotificationShadeWindowController.setRequestTopUi(false, TAG);
                     }
-                }, false, sUiEventLogger).show(animationDelay);
+                }, /* isDozing= */ false, RippleShape.CIRCLE,
+                sUiEventLogger).show(animationDelay);
     }
 
     @Override
@@ -3929,9 +3928,6 @@
     // all notifications
     protected NotificationStackScrollLayout mStackScroller;
 
-    // handling reordering
-    private final VisualStabilityManager mVisualStabilityManager;
-
     protected AccessibilityManager mAccessibilityManager;
 
     protected boolean mDeviceInteractive;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index 80432db..51536c3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -326,14 +326,6 @@
         dumpInternal(pw, args);
     }
 
-    @Override
-    public boolean shouldExtendLifetime(NotificationEntry entry) {
-        // We should not defer the removal if reordering isn't allowed since otherwise
-        // these won't disappear until reordering is allowed again, which happens only once
-        // the notification panel is collapsed again.
-        return mVisualStabilityProvider.isReorderingAllowed() && super.shouldExtendLifetime(entry);
-    }
-
     ///////////////////////////////////////////////////////////////////////////////////////////////
     //  OnReorderingAllowedListener:
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
index 339f371..d24469e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
@@ -39,6 +39,8 @@
  * A view to show hints on Keyguard ("Swipe up to unlock", "Tap again to open").
  */
 public class KeyguardIndicationTextView extends TextView {
+    public static final long Y_IN_DURATION = 600L;
+
     @StyleRes
     private static int sStyleId = R.style.TextAppearance_Keyguard_BottomArea;
     @StyleRes
@@ -259,7 +261,7 @@
 
     private long getYInDuration() {
         if (!mAnimationsEnabled) return 0L;
-        return 600L;
+        return Y_IN_DURATION;
     }
 
     private long getFadeOutDuration() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProvider.kt
index 96b9aca..2763750 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProvider.kt
@@ -17,11 +17,14 @@
 package com.android.systemui.statusbar.phone
 
 import android.annotation.ColorInt
+import android.app.WallpaperManager
 import android.graphics.Color
+import android.os.Handler
 import android.os.RemoteException
 import android.view.IWindowManager
 import com.android.systemui.Dumpable
 import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent
 import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent.CentralSurfacesScope
@@ -37,6 +40,8 @@
     private val windowManager: IWindowManager,
     @Background private val backgroundExecutor: Executor,
     private val dumpManager: DumpManager,
+    private val wallpaperManager: WallpaperManager,
+    @Main private val mainHandler: Handler,
 ) : CentralSurfacesComponent.Startable, Dumpable {
 
     @ColorInt
@@ -46,9 +51,18 @@
     var isLetterboxBackgroundMultiColored: Boolean = false
         private set
 
+    private val wallpaperColorsListener =
+        WallpaperManager.OnColorsChangedListener { _, _ ->
+            fetchBackgroundColorInfo()
+        }
+
     override fun start() {
         dumpManager.registerDumpable(javaClass.simpleName, this)
+        fetchBackgroundColorInfo()
+        wallpaperManager.addOnColorsChangedListener(wallpaperColorsListener, mainHandler)
+    }
 
+    private fun fetchBackgroundColorInfo() {
         // Using a background executor, as binder calls to IWindowManager are blocking
         backgroundExecutor.execute {
             try {
@@ -62,6 +76,7 @@
 
     override fun stop() {
         dumpManager.unregisterDumpable(javaClass.simpleName)
+        wallpaperManager.removeOnColorsChangedListener(wallpaperColorsListener)
     }
 
     override fun dump(pw: PrintWriter, args: Array<out String>) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
deleted file mode 100644
index ca6e67e..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
+++ /dev/null
@@ -1,717 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.phone;
-
-import static com.android.systemui.statusbar.notification.NotificationUtils.logKey;
-import static com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy.logGroupKey;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.Notification;
-import android.os.SystemClock;
-import android.service.notification.StatusBarNotification;
-import android.util.ArrayMap;
-import android.util.Log;
-
-import com.android.internal.statusbar.NotificationVisibility;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
-import com.android.systemui.statusbar.notification.NotificationEntryListener;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy.NotificationGroup;
-import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
-import com.android.systemui.statusbar.notification.row.RowContentBindParams;
-import com.android.systemui.statusbar.notification.row.RowContentBindStage;
-import com.android.systemui.statusbar.phone.dagger.StatusBarPhoneModule;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
-import com.android.systemui.util.Compile;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-
-import javax.inject.Inject;
-
-/**
- * A helper class dealing with the alert interactions between {@link NotificationGroupManagerLegacy}
- * and {@link HeadsUpManager}. In particular, this class deals with keeping
- * the correct notification in a group alerting based off the group suppression and alertOverride.
- */
-@SysUISingleton
-public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedListener,
-        StateListener {
-
-    private static final long ALERT_TRANSFER_TIMEOUT = 300;
-    private static final String TAG = "NotifGroupAlertTransfer";
-    private static final boolean DEBUG = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.DEBUG);
-    private static final boolean SPEW = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.VERBOSE);
-
-    /**
-     * The list of entries containing group alert metadata for each group. Keyed by group key.
-     */
-    private final ArrayMap<String, GroupAlertEntry> mGroupAlertEntries = new ArrayMap<>();
-
-    /**
-     * The list of entries currently inflating that should alert after inflation. Keyed by
-     * notification key.
-     */
-    private final ArrayMap<String, PendingAlertInfo> mPendingAlerts = new ArrayMap<>();
-
-    private HeadsUpManager mHeadsUpManager;
-    private final RowContentBindStage mRowContentBindStage;
-    private final NotificationGroupManagerLegacy mGroupManager;
-
-    private NotificationEntryManager mEntryManager;
-
-    private boolean mIsDozing;
-
-    /**
-     * Injected constructor. See {@link StatusBarPhoneModule}.
-     */
-    @Inject
-    public NotificationGroupAlertTransferHelper(
-            RowContentBindStage bindStage,
-            StatusBarStateController statusBarStateController,
-            NotificationGroupManagerLegacy notificationGroupManagerLegacy) {
-        mRowContentBindStage = bindStage;
-        mGroupManager = notificationGroupManagerLegacy;
-        statusBarStateController.addCallback(this);
-    }
-
-    /** Causes the TransferHelper to register itself as a listener to the appropriate classes. */
-    public void bind(NotificationEntryManager entryManager,
-            NotificationGroupManagerLegacy groupManager) {
-        if (mEntryManager != null) {
-            throw new IllegalStateException("Already bound.");
-        }
-
-        // TODO(b/119637830): It would be good if GroupManager already had all pending notifications
-        // as normal children (i.e. add notifications to GroupManager before inflation) so that we
-        // don't have to have this dependency. We'd also have to worry less about the suppression
-        // not being up to date.
-        mEntryManager = entryManager;
-
-        mEntryManager.addNotificationEntryListener(mNotificationEntryListener);
-        groupManager.registerGroupChangeListener(mOnGroupChangeListener);
-    }
-
-    /**
-     * Whether or not a notification has transferred its alert state to the notification and
-     * the notification should alert after inflating.
-     *
-     * @param entry notification to check
-     * @return true if the entry was transferred to and should inflate + alert
-     */
-    public boolean isAlertTransferPending(@NonNull NotificationEntry entry) {
-        PendingAlertInfo alertInfo = mPendingAlerts.get(entry.getKey());
-        return alertInfo != null && alertInfo.isStillValid();
-    }
-
-    public void setHeadsUpManager(HeadsUpManager headsUpManager) {
-        mHeadsUpManager = headsUpManager;
-    }
-
-    @Override
-    public void onStateChanged(int newState) {}
-
-    @Override
-    public void onDozingChanged(boolean isDozing) {
-        if (mIsDozing != isDozing) {
-            for (GroupAlertEntry groupAlertEntry : mGroupAlertEntries.values()) {
-                groupAlertEntry.mLastAlertTransferTime = 0;
-                groupAlertEntry.mAlertSummaryOnNextAddition = false;
-            }
-        }
-        mIsDozing = isDozing;
-    }
-
-    private final NotificationGroupManagerLegacy.OnGroupChangeListener mOnGroupChangeListener =
-            new NotificationGroupManagerLegacy.OnGroupChangeListener() {
-        @Override
-        public void onGroupCreated(NotificationGroup group, String groupKey) {
-            mGroupAlertEntries.put(groupKey, new GroupAlertEntry(group));
-        }
-
-        @Override
-        public void onGroupRemoved(NotificationGroup group, String groupKey) {
-            mGroupAlertEntries.remove(groupKey);
-        }
-
-        @Override
-        public void onGroupSuppressionChanged(NotificationGroup group, boolean suppressed) {
-            if (DEBUG) {
-                Log.d(TAG, "!! onGroupSuppressionChanged:"
-                        + " group=" + logGroupKey(group)
-                        + " group.summary=" + logKey(group.summary)
-                        + " suppressed=" + suppressed);
-            }
-            NotificationEntry oldAlertOverride = group.alertOverride;
-            onGroupChanged(group, oldAlertOverride);
-        }
-
-        @Override
-        public void onGroupAlertOverrideChanged(NotificationGroup group,
-                @Nullable NotificationEntry oldAlertOverride,
-                @Nullable NotificationEntry newAlertOverride) {
-            if (DEBUG) {
-                Log.d(TAG, "!! onGroupAlertOverrideChanged:"
-                        + " group=" + logGroupKey(group)
-                        + " group.summary=" + logKey(group.summary)
-                        + " oldAlertOverride=" + logKey(oldAlertOverride)
-                        + " newAlertOverride=" + logKey(newAlertOverride));
-            }
-            onGroupChanged(group, oldAlertOverride);
-        }
-    };
-
-    /**
-     * Called when either the suppressed or alertOverride fields of the group changed
-     *
-     * @param group the group which changed
-     * @param oldAlertOverride the previous value of group.alertOverride
-     */
-    private void onGroupChanged(NotificationGroup group,
-            NotificationEntry oldAlertOverride) {
-        // Group summary can be null if we are no longer suppressed because the summary was
-        // removed. In that case, we don't need to alert the summary.
-        if (group.summary == null) {
-            if (DEBUG) {
-                Log.d(TAG, "onGroupChanged: summary is null");
-            }
-            return;
-        }
-        if (group.suppressed || group.alertOverride != null) {
-            checkForForwardAlertTransfer(group.summary, oldAlertOverride);
-        } else {
-            if (DEBUG) {
-                Log.d(TAG, "onGroupChanged: maybe transfer back");
-            }
-            GroupAlertEntry groupAlertEntry = mGroupAlertEntries.get(mGroupManager.getGroupKey(
-                    group.summary.getSbn()));
-            // Group is no longer suppressed or overridden.
-            // We should check if we need to transfer the alert back to the summary.
-            if (groupAlertEntry.mAlertSummaryOnNextAddition) {
-                if (!mHeadsUpManager.isAlerting(group.summary.getKey())) {
-                    alertNotificationWhenPossible(group.summary);
-                }
-                groupAlertEntry.mAlertSummaryOnNextAddition = false;
-            } else {
-                checkShouldTransferBack(groupAlertEntry);
-            }
-        }
-    }
-
-    @Override
-    public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
-        if (DEBUG) {
-            Log.d(TAG, "!! onHeadsUpStateChanged:"
-                    + " entry=" + logKey(entry)
-                    + " isHeadsUp=" + isHeadsUp);
-        }
-        if (isHeadsUp && entry.getSbn().getNotification().isGroupSummary()) {
-            // a group summary is alerting; trigger the forward transfer checks
-            checkForForwardAlertTransfer(entry, /* oldAlertOverride */ null);
-        }
-    }
-
-    /**
-     * Handles changes in a group's suppression or alertOverride, but where at least one of those
-     * conditions is still true (either the group is suppressed, the group has an alertOverride,
-     * or both).  The method determined which kind of child needs to receive the alert, finds the
-     * entry currently alerting, and makes the transfer.
-     *
-     * Internally, this is handled with two main cases: the override needs the alert, or there is
-     * no override but the summary is suppressed (so an isolated child needs the alert).
-     *
-     * @param summary the notification entry of the summary of the logical group.
-     * @param oldAlertOverride the former value of group.alertOverride, before whatever event
-     *                         required us to check for for a transfer condition.
-     */
-    private void checkForForwardAlertTransfer(NotificationEntry summary,
-            NotificationEntry oldAlertOverride) {
-        if (DEBUG) {
-            Log.d(TAG, "checkForForwardAlertTransfer: enter");
-        }
-        NotificationGroup group = mGroupManager.getGroupForSummary(summary.getSbn());
-        if (group != null && group.alertOverride != null) {
-            handleOverriddenSummaryAlerted(summary);
-        } else if (mGroupManager.isSummaryOfSuppressedGroup(summary.getSbn())) {
-            handleSuppressedSummaryAlerted(summary, oldAlertOverride);
-        }
-        if (DEBUG) {
-            Log.d(TAG, "checkForForwardAlertTransfer: done");
-        }
-    }
-
-    private final NotificationEntryListener mNotificationEntryListener =
-            new NotificationEntryListener() {
-        // Called when a new notification has been posted but is not inflated yet. We use this to
-        // see as early as we can if we need to abort a transfer.
-        @Override
-        public void onPendingEntryAdded(NotificationEntry entry) {
-            if (DEBUG) {
-                Log.d(TAG, "!! onPendingEntryAdded: entry=" + logKey(entry));
-            }
-            String groupKey = mGroupManager.getGroupKey(entry.getSbn());
-            GroupAlertEntry groupAlertEntry = mGroupAlertEntries.get(groupKey);
-            if (groupAlertEntry != null && groupAlertEntry.mGroup.alertOverride == null) {
-                // new pending group entries require us to transfer back from the child to the
-                // group, but alertOverrides are only present in very limited circumstances, so
-                // while it's possible the group should ALSO alert, the previous detection which set
-                // this alertOverride won't be invalidated by this notification added to this group.
-                checkShouldTransferBack(groupAlertEntry);
-            }
-        }
-
-        @Override
-        public void onEntryRemoved(
-                @Nullable NotificationEntry entry,
-                NotificationVisibility visibility,
-                boolean removedByUser,
-                int reason) {
-            // Removes any alerts pending on this entry. Note that this will not stop any inflation
-            // tasks started by a transfer, so this should only be used as clean-up for when
-            // inflation is stopped and the pending alert no longer needs to happen.
-            mPendingAlerts.remove(entry.getKey());
-        }
-    };
-
-    /**
-     * Gets the number of new notifications pending inflation that will be added to the group
-     * but currently aren't and should not alert.
-     *
-     * @param group group to check
-     * @return the number of new notifications that will be added to the group
-     */
-    private int getPendingChildrenNotAlerting(@NonNull NotificationGroup group) {
-        if (mEntryManager == null) {
-            return 0;
-        }
-        int number = 0;
-        Iterable<NotificationEntry> values = mEntryManager.getPendingNotificationsIterator();
-        for (NotificationEntry entry : values) {
-            if (isPendingNotificationInGroup(entry, group) && onlySummaryAlerts(entry)) {
-                number++;
-            }
-        }
-        return number;
-    }
-
-    /**
-     * Checks if the pending inflations will add children to this group.
-     *
-     * @param group group to check
-     * @return true if a pending notification will add to this group
-     */
-    private boolean pendingInflationsWillAddChildren(@NonNull NotificationGroup group) {
-        if (mEntryManager == null) {
-            return false;
-        }
-        Iterable<NotificationEntry> values = mEntryManager.getPendingNotificationsIterator();
-        for (NotificationEntry entry : values) {
-            if (isPendingNotificationInGroup(entry, group)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Checks if a new pending notification will be added to the group.
-     *
-     * @param entry pending notification
-     * @param group group to check
-     * @return true if the notification will add to the group, false o/w
-     */
-    private boolean isPendingNotificationInGroup(@NonNull NotificationEntry entry,
-            @NonNull NotificationGroup group) {
-        String groupKey = mGroupManager.getGroupKey(group.summary.getSbn());
-        return mGroupManager.isGroupChild(entry.getSbn())
-                && Objects.equals(mGroupManager.getGroupKey(entry.getSbn()), groupKey)
-                && !group.children.containsKey(entry.getKey());
-    }
-
-    /**
-     * Handles the scenario where a summary that has been suppressed is itself, or has a former
-     * alertOverride (in the form of an isolated logical child) which was alerted.  A suppressed
-     * summary should for all intents and purposes be invisible to the user and as a result should
-     * not alert.  When this is the case, it is our responsibility to pass the alert to the
-     * appropriate child which will be the representative notification alerting for the group.
-     *
-     * @param summary the summary that is suppressed and (potentially) alerting
-     * @param oldAlertOverride the alertOverride before whatever event triggered this method.  If
-     *                         the alert override was removed, this will be the entry that should
-     *                         be transferred back from.
-     */
-    private void handleSuppressedSummaryAlerted(@NonNull NotificationEntry summary,
-            NotificationEntry oldAlertOverride) {
-        if (DEBUG) {
-            Log.d(TAG, "handleSuppressedSummaryAlerted: summary=" + logKey(summary));
-        }
-        GroupAlertEntry groupAlertEntry =
-                mGroupAlertEntries.get(mGroupManager.getGroupKey(summary.getSbn()));
-
-        if (!mGroupManager.isSummaryOfSuppressedGroup(summary.getSbn())
-                || groupAlertEntry == null) {
-            if (DEBUG) {
-                Log.d(TAG, "handleSuppressedSummaryAlerted: invalid state");
-            }
-            return;
-        }
-        boolean summaryIsAlerting = mHeadsUpManager.isAlerting(summary.getKey());
-        boolean priorityIsAlerting = oldAlertOverride != null
-                && mHeadsUpManager.isAlerting(oldAlertOverride.getKey());
-        if (!summaryIsAlerting && !priorityIsAlerting) {
-            if (DEBUG) {
-                Log.d(TAG, "handleSuppressedSummaryAlerted: no summary or override alerting");
-            }
-            return;
-        }
-
-        if (pendingInflationsWillAddChildren(groupAlertEntry.mGroup)) {
-            // New children will actually be added to this group, let's not transfer the alert.
-            if (DEBUG) {
-                Log.d(TAG, "handleSuppressedSummaryAlerted: pending inflations");
-            }
-            return;
-        }
-
-        NotificationEntry child =
-                mGroupManager.getLogicalChildren(summary.getSbn()).iterator().next();
-        if (summaryIsAlerting) {
-            if (DEBUG) {
-                Log.d(TAG, "handleSuppressedSummaryAlerted: transfer summary -> child");
-            }
-            tryTransferAlertState(summary, /*from*/ summary, /*to*/ child, groupAlertEntry);
-            return;
-        }
-        // Summary didn't have the alert, so we're in "transfer back" territory.  First, make sure
-        // it's not too late to transfer back, then transfer the alert from the oldAlertOverride to
-        // the isolated child which should receive the alert.
-        if (!canStillTransferBack(groupAlertEntry)) {
-            if (DEBUG) {
-                Log.d(TAG, "handleSuppressedSummaryAlerted: transfer from override: too late");
-            }
-            return;
-        }
-
-        if (DEBUG) {
-            Log.d(TAG, "handleSuppressedSummaryAlerted: transfer override -> child");
-        }
-        tryTransferAlertState(summary, /*from*/ oldAlertOverride, /*to*/ child, groupAlertEntry);
-    }
-
-    /**
-     * Checks for and handles the scenario where the given entry is the summary of a group which
-     * has an alertOverride, and either the summary itself or one of its logical isolated children
-     * is currently alerting (which happens if the summary is suppressed).
-     */
-    private void handleOverriddenSummaryAlerted(NotificationEntry summary) {
-        if (DEBUG) {
-            Log.d(TAG, "handleOverriddenSummaryAlerted: summary=" + logKey(summary));
-        }
-        GroupAlertEntry groupAlertEntry =
-                mGroupAlertEntries.get(mGroupManager.getGroupKey(summary.getSbn()));
-        NotificationGroup group = mGroupManager.getGroupForSummary(summary.getSbn());
-        if (group == null || group.alertOverride == null || groupAlertEntry == null) {
-            if (DEBUG) {
-                Log.d(TAG, "handleOverriddenSummaryAlerted: invalid state");
-            }
-            return;
-        }
-        boolean summaryIsAlerting = mHeadsUpManager.isAlerting(summary.getKey());
-        if (summaryIsAlerting) {
-            if (DEBUG) {
-                Log.d(TAG, "handleOverriddenSummaryAlerted: transfer summary -> override");
-            }
-            tryTransferAlertState(summary, /*from*/ summary, group.alertOverride, groupAlertEntry);
-            return;
-        }
-        // Summary didn't have the alert, so we're in "transfer back" territory.  First, make sure
-        // it's not too late to transfer back, then remove the alert from any of the logical
-        // children, and if one of them was alerting, we can alert the override.
-        if (!canStillTransferBack(groupAlertEntry)) {
-            if (DEBUG) {
-                Log.d(TAG, "handleOverriddenSummaryAlerted: transfer from child: too late");
-            }
-            return;
-        }
-        List<NotificationEntry> children = mGroupManager.getLogicalChildren(summary.getSbn());
-        if (children == null) {
-            if (DEBUG) {
-                Log.d(TAG, "handleOverriddenSummaryAlerted: no children");
-            }
-            return;
-        }
-        children.remove(group.alertOverride); // do not release the alert on our desired destination
-        boolean releasedChild = releaseChildAlerts(children);
-        if (releasedChild) {
-            if (DEBUG) {
-                Log.d(TAG, "handleOverriddenSummaryAlerted: transfer child -> override");
-            }
-            tryTransferAlertState(summary, /*from*/ null, group.alertOverride, groupAlertEntry);
-        } else {
-            if (DEBUG) {
-                Log.d(TAG, "handleOverriddenSummaryAlerted: no child alert released");
-            }
-        }
-    }
-
-    /**
-     * Transfers the alert state one entry to another. We remove the alert from the first entry
-     * immediately to have the incorrect one up as short as possible. The second should alert
-     * when possible.
-     *
-     * @param summary entry of the summary
-     * @param fromEntry entry to transfer alert from
-     * @param toEntry entry to transfer to
-     */
-    private void tryTransferAlertState(
-            NotificationEntry summary,
-            NotificationEntry fromEntry,
-            NotificationEntry toEntry,
-            GroupAlertEntry groupAlertEntry) {
-        if (toEntry != null) {
-            if (toEntry.getRow().keepInParent()
-                    || toEntry.isRowRemoved()
-                    || toEntry.isRowDismissed()) {
-                // The notification is actually already removed. No need to alert it.
-                return;
-            }
-            if (!mHeadsUpManager.isAlerting(toEntry.getKey()) && onlySummaryAlerts(summary)) {
-                groupAlertEntry.mLastAlertTransferTime = SystemClock.elapsedRealtime();
-            }
-            if (DEBUG) {
-                Log.d(TAG, "transferAlertState:"
-                        + " fromEntry=" + logKey(fromEntry)
-                        + " toEntry=" + logKey(toEntry));
-            }
-            transferAlertState(fromEntry, toEntry);
-        }
-    }
-    private void transferAlertState(@Nullable NotificationEntry fromEntry,
-            @NonNull NotificationEntry toEntry) {
-        if (fromEntry != null) {
-            mHeadsUpManager.removeNotification(fromEntry.getKey(), true /* releaseImmediately */);
-        }
-        alertNotificationWhenPossible(toEntry);
-    }
-
-    /**
-     * Determines if we need to transfer the alert back to the summary from the child and does
-     * so if needed.
-     *
-     * This can happen since notification groups are not delivered as a whole unit and it is
-     * possible we erroneously transfer the alert from the summary to the child even though
-     * more children are coming. Thus, if a child is added within a certain timeframe after we
-     * transfer, we back out and alert the summary again.
-     *
-     * An alert can only transfer back within a small window of time after a transfer away from the
-     * summary to a child happened.
-     *
-     * @param groupAlertEntry group alert entry to check
-     */
-    private void checkShouldTransferBack(@NonNull GroupAlertEntry groupAlertEntry) {
-        if (canStillTransferBack(groupAlertEntry)) {
-            NotificationEntry summary = groupAlertEntry.mGroup.summary;
-
-            if (!onlySummaryAlerts(summary)) {
-                return;
-            }
-            ArrayList<NotificationEntry> children = mGroupManager.getLogicalChildren(
-                    summary.getSbn());
-            int numActiveChildren = children.size();
-            int numPendingChildren = getPendingChildrenNotAlerting(groupAlertEntry.mGroup);
-            int numChildren = numActiveChildren + numPendingChildren;
-            if (numChildren <= 1) {
-                return;
-            }
-            boolean releasedChild = releaseChildAlerts(children);
-            if (releasedChild && !mHeadsUpManager.isAlerting(summary.getKey())) {
-                boolean notifyImmediately = numActiveChildren > 1;
-                if (notifyImmediately) {
-                    alertNotificationWhenPossible(summary);
-                } else {
-                    // Should wait until the pending child inflates before alerting.
-                    groupAlertEntry.mAlertSummaryOnNextAddition = true;
-                }
-                groupAlertEntry.mLastAlertTransferTime = 0;
-            }
-        }
-    }
-
-    private boolean canStillTransferBack(@NonNull GroupAlertEntry groupAlertEntry) {
-        return SystemClock.elapsedRealtime() - groupAlertEntry.mLastAlertTransferTime
-                < ALERT_TRANSFER_TIMEOUT;
-    }
-
-    private boolean releaseChildAlerts(List<NotificationEntry> children) {
-        boolean releasedChild = false;
-        if (SPEW) {
-            Log.d(TAG, "releaseChildAlerts: numChildren=" + children.size());
-        }
-        for (int i = 0; i < children.size(); i++) {
-            NotificationEntry entry = children.get(i);
-            if (SPEW) {
-                Log.d(TAG, "releaseChildAlerts: checking i=" + i + " entry=" + entry
-                        + " onlySummaryAlerts=" + onlySummaryAlerts(entry)
-                        + " isAlerting=" + mHeadsUpManager.isAlerting(entry.getKey())
-                        + " isPendingAlert=" + mPendingAlerts.containsKey(entry.getKey()));
-            }
-            if (onlySummaryAlerts(entry) && mHeadsUpManager.isAlerting(entry.getKey())) {
-                releasedChild = true;
-                mHeadsUpManager.removeNotification(
-                        entry.getKey(), true /* releaseImmediately */);
-            }
-            if (mPendingAlerts.containsKey(entry.getKey())) {
-                // This is the child that would've been removed if it was inflated.
-                releasedChild = true;
-                mPendingAlerts.get(entry.getKey()).mAbortOnInflation = true;
-            }
-        }
-        if (SPEW) {
-            Log.d(TAG, "releaseChildAlerts: didRelease=" + releasedChild);
-        }
-        return releasedChild;
-    }
-
-    /**
-     * Tries to alert the notification. If its content view is not inflated, we inflate and continue
-     * when the entry finishes inflating the view.
-     *
-     * @param entry entry to show
-     */
-    private void alertNotificationWhenPossible(@NonNull NotificationEntry entry) {
-        @InflationFlag int contentFlag = mHeadsUpManager.getContentFlag();
-        final RowContentBindParams params = mRowContentBindStage.getStageParams(entry);
-        if ((params.getContentViews() & contentFlag) == 0) {
-            if (DEBUG) {
-                Log.d(TAG, "alertNotificationWhenPossible:"
-                        + " async requestRebind entry=" + logKey(entry));
-            }
-            mPendingAlerts.put(entry.getKey(), new PendingAlertInfo(entry));
-            params.requireContentViews(contentFlag);
-            mRowContentBindStage.requestRebind(entry, en -> {
-                PendingAlertInfo alertInfo = mPendingAlerts.remove(entry.getKey());
-                if (alertInfo != null) {
-                    if (alertInfo.isStillValid()) {
-                        alertNotificationWhenPossible(entry);
-                    } else {
-                        if (DEBUG) {
-                            Log.d(TAG, "alertNotificationWhenPossible:"
-                                    + " markContentViewsFreeable entry=" + logKey(entry));
-                        }
-                        // The transfer is no longer valid. Free the content.
-                        mRowContentBindStage.getStageParams(entry).markContentViewsFreeable(
-                                contentFlag);
-                        mRowContentBindStage.requestRebind(entry, null);
-                    }
-                }
-            });
-            return;
-        }
-        if (mHeadsUpManager.isAlerting(entry.getKey())) {
-            if (DEBUG) {
-                Log.d(TAG, "alertNotificationWhenPossible:"
-                        + " continue alerting entry=" + logKey(entry));
-            }
-            mHeadsUpManager.updateNotification(entry.getKey(), true /* alert */);
-        } else {
-            if (DEBUG) {
-                Log.d(TAG, "alertNotificationWhenPossible:"
-                        + " start alerting entry=" + logKey(entry));
-            }
-            mHeadsUpManager.showNotification(entry);
-        }
-    }
-
-    private boolean onlySummaryAlerts(NotificationEntry entry) {
-        return entry.getSbn().getNotification().getGroupAlertBehavior()
-                == Notification.GROUP_ALERT_SUMMARY;
-    }
-
-    /**
-     * Information about a pending alert used to determine if the alert is still needed when
-     * inflation completes.
-     */
-    private class PendingAlertInfo {
-
-        /**
-         * The original notification when the transfer is initiated. This is used to determine if
-         * the transfer is still valid if the notification is updated.
-         */
-        final StatusBarNotification mOriginalNotification;
-        final NotificationEntry mEntry;
-
-        /**
-         * The notification is still pending inflation but we've decided that we no longer need
-         * the content view (e.g. suppression might have changed and we decided we need to transfer
-         * back).
-         *
-         * TODO: Replace this entire structure with {@link RowContentBindStage#requestRebind)}.
-         */
-        boolean mAbortOnInflation;
-
-        PendingAlertInfo(NotificationEntry entry) {
-            mOriginalNotification = entry.getSbn();
-            mEntry = entry;
-        }
-
-        /**
-         * Whether or not the pending alert is still valid and should still alert after inflation.
-         *
-         * @return true if the pending alert should still occur, false o/w
-         */
-        private boolean isStillValid() {
-            if (mAbortOnInflation) {
-                // Notification is aborted due to the transfer being explicitly cancelled
-                return false;
-            }
-            if (!mEntry.getSbn().getGroupKey().equals(mOriginalNotification.getGroupKey())) {
-                // Groups have changed
-                return false;
-            }
-            if (mEntry.getSbn().getNotification().isGroupSummary()
-                    != mOriginalNotification.getNotification().isGroupSummary()) {
-                // Notification has changed from group summary to not or vice versa
-                return false;
-            }
-            return true;
-        }
-    }
-
-    /**
-     * Contains alert metadata for the notification group used to determine when/how the alert
-     * should be transferred.
-     */
-    private static class GroupAlertEntry {
-        /**
-         * The time when the last alert transfer from summary to child happened.
-         */
-        long mLastAlertTransferTime;
-        boolean mAlertSummaryOnNextAddition;
-        final NotificationGroup mGroup;
-
-        GroupAlertEntry(NotificationGroup group) {
-            this.mGroup = group;
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/CoroutinesModule.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/CoroutinesModule.kt
index 05d087e..0a44bda 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/CoroutinesModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/CoroutinesModule.kt
@@ -37,5 +37,5 @@
     @Provides
     @SysUISingleton
     @Background
-    fun bgDispatcher(): CoroutineDispatcher = Dispatchers.Default
+    fun bgDispatcher(): CoroutineDispatcher = Dispatchers.IO
 }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUserSwitcherAnchorTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUserSwitcherAnchorTest.kt
new file mode 100644
index 0000000..08185af
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUserSwitcherAnchorTest.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard
+
+import android.testing.AndroidTestingRunner
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class KeyguardUserSwitcherAnchorTest : SysuiTestCase() {
+
+    private lateinit var keyguardUserSwitcherAnchor: KeyguardUserSwitcherAnchor
+
+    @Before
+    fun setUp() {
+        keyguardUserSwitcherAnchor = KeyguardUserSwitcherAnchor(context)
+    }
+
+    @Test
+    fun roleDescription_is_set_to_pulldown_menu() {
+        // GIVEN
+        val roleDescriptionString =
+                context.getString(R.string.accessibility_multi_user_list_switcher)
+
+        // WHEN
+        val result = keyguardUserSwitcherAnchor.createAccessibilityNodeInfo()
+
+        // THEN
+        assertThat(
+                AccessibilityNodeInfoCompat.wrap(result).roleDescription
+        ).isEqualTo(roleDescriptionString)
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarItemsProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarItemsProviderTest.java
new file mode 100644
index 0000000..a78886f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarItemsProviderTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.dreams;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.testing.AndroidTestingRunner;
+
+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.List;
+import java.util.concurrent.Executor;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class DreamOverlayStatusBarItemsProviderTest extends SysuiTestCase {
+    @Mock
+    DreamOverlayStatusBarItemsProvider.Callback mCallback;
+    @Mock
+    DreamOverlayStatusBarItemsProvider.StatusBarItem mStatusBarItem;
+
+    private final Executor mMainExecutor = Runnable::run;
+
+    DreamOverlayStatusBarItemsProvider mProvider;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mProvider = new DreamOverlayStatusBarItemsProvider(mMainExecutor);
+    }
+
+    @Test
+    public void addingCallbackCallsOnStatusBarItemsChanged() {
+        mProvider.addStatusBarItem(mStatusBarItem);
+        mProvider.addCallback(mCallback);
+        verify(mCallback).onStatusBarItemsChanged(List.of(mStatusBarItem));
+    }
+
+    @Test
+    public void addingStatusBarItemCallsOnStatusBarItemsChanged() {
+        mProvider.addCallback(mCallback);
+        mProvider.addStatusBarItem(mStatusBarItem);
+        verify(mCallback).onStatusBarItemsChanged(List.of(mStatusBarItem));
+    }
+
+    @Test
+    public void addingDuplicateStatusBarItemDoesNotCallOnStatusBarItemsChanged() {
+        mProvider.addCallback(mCallback);
+        mProvider.addStatusBarItem(mStatusBarItem);
+        mProvider.addStatusBarItem(mStatusBarItem);
+        // Called only once for addStatusBarItem.
+        verify(mCallback, times(1))
+                .onStatusBarItemsChanged(List.of(mStatusBarItem));
+    }
+
+    @Test
+    public void removingStatusBarItemCallsOnStatusBarItemsChanged() {
+        mProvider.addCallback(mCallback);
+        mProvider.addStatusBarItem(mStatusBarItem);
+        mProvider.removeStatusBarItem(mStatusBarItem);
+        // Called once for addStatusBarItem and once for removeStatusBarItem.
+        verify(mCallback, times(2)).onStatusBarItemsChanged(any());
+    }
+
+    @Test
+    public void removingNonexistentStatusBarItemDoesNotCallOnStatusBarItemsChanged() {
+        mProvider.addCallback(mCallback);
+        mProvider.removeStatusBarItem(mStatusBarItem);
+        verify(mCallback, never()).onStatusBarItemsChanged(any());
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
index 60e5a94..01309f8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
@@ -57,6 +57,7 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.List;
 import java.util.Optional;
 import java.util.concurrent.Executor;
 
@@ -94,6 +95,12 @@
     DreamOverlayNotificationCountProvider mDreamOverlayNotificationCountProvider;
     @Mock
     StatusBarWindowStateController mStatusBarWindowStateController;
+    @Mock
+    DreamOverlayStatusBarItemsProvider mDreamOverlayStatusBarItemsProvider;
+    @Mock
+    DreamOverlayStatusBarItemsProvider.StatusBarItem mStatusBarItem;
+    @Mock
+    View mStatusBarItemView;
 
     private final Executor mMainExecutor = Runnable::run;
 
@@ -118,7 +125,8 @@
                 mSensorPrivacyController,
                 Optional.of(mDreamOverlayNotificationCountProvider),
                 mZenModeController,
-                mStatusBarWindowStateController);
+                mStatusBarWindowStateController,
+                mDreamOverlayStatusBarItemsProvider);
     }
 
     @Test
@@ -128,6 +136,7 @@
         verify(mSensorPrivacyController).addCallback(any());
         verify(mZenModeController).addCallback(any());
         verify(mDreamOverlayNotificationCountProvider).addCallback(any());
+        verify(mDreamOverlayStatusBarItemsProvider).addCallback(any());
     }
 
     @Test
@@ -256,7 +265,8 @@
                 mSensorPrivacyController,
                 Optional.empty(),
                 mZenModeController,
-                mStatusBarWindowStateController);
+                mStatusBarWindowStateController,
+                mDreamOverlayStatusBarItemsProvider);
         controller.onViewAttached();
         verify(mView, never()).showIcon(
                 eq(DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(true), any());
@@ -294,6 +304,7 @@
         verify(mSensorPrivacyController).removeCallback(any());
         verify(mZenModeController).removeCallback(any());
         verify(mDreamOverlayNotificationCountProvider).removeCallback(any());
+        verify(mDreamOverlayStatusBarItemsProvider).removeCallback(any());
     }
 
     @Test
@@ -462,4 +473,18 @@
 
         verify(mView, never()).setVisibility(anyInt());
     }
+
+    @Test
+    public void testExtraStatusBarItemSetWhenItemsChange() {
+        mController.onViewAttached();
+        when(mStatusBarItem.getView()).thenReturn(mStatusBarItemView);
+
+        final ArgumentCaptor<DreamOverlayStatusBarItemsProvider.Callback>
+                callbackCapture = ArgumentCaptor.forClass(
+                        DreamOverlayStatusBarItemsProvider.Callback.class);
+        verify(mDreamOverlayStatusBarItemsProvider).addCallback(callbackCapture.capture());
+        callbackCapture.getValue().onStatusBarItemsChanged(List.of(mStatusBarItem));
+
+        verify(mView).setExtraStatusBarItemViews(List.of(mStatusBarItemView));
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/FakeKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/FakeKeyguardQuickAffordanceConfig.kt
deleted file mode 100644
index 6fff440..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/FakeKeyguardQuickAffordanceConfig.kt
+++ /dev/null
@@ -1,60 +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.keyguard.data.repository
-
-import com.android.systemui.animation.ActivityLaunchAnimator
-import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig
-import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.OnClickedResult
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.yield
-
-/**
- * Fake implementation of a quick affordance data source.
- *
- * This class is abstract to force tests to provide extensions of it as the system that references
- * these configs uses each implementation's class type to refer to them.
- */
-abstract class FakeKeyguardQuickAffordanceConfig : KeyguardQuickAffordanceConfig {
-
-    private val _onClickedInvocations = mutableListOf<ActivityLaunchAnimator.Controller?>()
-    val onClickedInvocations: List<ActivityLaunchAnimator.Controller?> = _onClickedInvocations
-
-    var onClickedResult: OnClickedResult = OnClickedResult.Handled
-
-    private val _state =
-        MutableStateFlow<KeyguardQuickAffordanceConfig.State>(
-            KeyguardQuickAffordanceConfig.State.Hidden
-        )
-    override val state: Flow<KeyguardQuickAffordanceConfig.State> = _state
-
-    override fun onQuickAffordanceClicked(
-        animationController: ActivityLaunchAnimator.Controller?,
-    ): OnClickedResult {
-        _onClickedInvocations.add(animationController)
-        return onClickedResult
-    }
-
-    suspend fun setState(state: KeyguardQuickAffordanceConfig.State) {
-        _state.value = state
-        // Yield to allow the test's collection coroutine to "catch up" and collect this value
-        // before the test continues to the next line.
-        // TODO(b/239834928): once coroutines.test is updated, switch to the approach described in
-        // https://developer.android.com/kotlin/flow/test#continuous-collection and remove this.
-        yield()
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/FakeKeyguardQuickAffordanceConfigs.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/FakeKeyguardQuickAffordanceConfigs.kt
deleted file mode 100644
index a24fc93..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/FakeKeyguardQuickAffordanceConfigs.kt
+++ /dev/null
@@ -1,44 +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.keyguard.data.repository
-
-import com.android.systemui.keyguard.data.config.KeyguardQuickAffordanceConfigs
-import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig
-import com.android.systemui.keyguard.shared.model.KeyguardQuickAffordancePosition
-import kotlin.reflect.KClass
-
-/** Fake implementation of [KeyguardQuickAffordanceConfigs], for tests. */
-class FakeKeyguardQuickAffordanceConfigs(
-    private val configsByPosition:
-        Map<KeyguardQuickAffordancePosition, List<KeyguardQuickAffordanceConfig>>,
-) : KeyguardQuickAffordanceConfigs {
-
-    override fun getAll(
-        position: KeyguardQuickAffordancePosition
-    ): List<KeyguardQuickAffordanceConfig> {
-        return configsByPosition.getValue(position)
-    }
-
-    override fun get(
-        configClass: KClass<out KeyguardQuickAffordanceConfig>
-    ): KeyguardQuickAffordanceConfig {
-        return configsByPosition.values
-            .flatten()
-            .associateBy { config -> config::class }
-            .getValue(configClass)
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/FakeKeyguardQuickAffordanceRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/FakeKeyguardQuickAffordanceRepository.kt
deleted file mode 100644
index 10d2e4d..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/FakeKeyguardQuickAffordanceRepository.kt
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.keyguard.data.repository
-
-import com.android.systemui.keyguard.shared.model.KeyguardQuickAffordanceModel
-import com.android.systemui.keyguard.shared.model.KeyguardQuickAffordancePosition
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.yield
-
-/** Fake implementation of [KeyguardQuickAffordanceRepository], for tests. */
-class FakeKeyguardQuickAffordanceRepository : KeyguardQuickAffordanceRepository {
-
-    private val modelByPosition =
-        mutableMapOf<
-            KeyguardQuickAffordancePosition, MutableStateFlow<KeyguardQuickAffordanceModel>>()
-
-    init {
-        KeyguardQuickAffordancePosition.values().forEach { value ->
-            modelByPosition[value] = MutableStateFlow(KeyguardQuickAffordanceModel.Hidden)
-        }
-    }
-
-    override fun affordance(
-        position: KeyguardQuickAffordancePosition
-    ): Flow<KeyguardQuickAffordanceModel> {
-        return modelByPosition.getValue(position)
-    }
-
-    suspend fun setModel(
-        position: KeyguardQuickAffordancePosition,
-        model: KeyguardQuickAffordanceModel
-    ) {
-        modelByPosition.getValue(position).value = model
-        // Yield to allow the test's collection coroutine to "catch up" and collect this value
-        // before the test continues to the next line.
-        // TODO(b/239834928): once coroutines.test is updated, switch to the approach described in
-        // https://developer.android.com/kotlin/flow/test#continuous-collection and remove this.
-        yield()
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
index d40b985..11eb4e3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
@@ -16,7 +16,7 @@
 
 package com.android.systemui.keyguard.data.repository
 
-import com.android.systemui.common.data.model.Position
+import com.android.systemui.common.shared.model.Position
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
@@ -43,11 +43,6 @@
     private val _dozeAmount = MutableStateFlow(0f)
     override val dozeAmount: Flow<Float> = _dozeAmount
 
-    init {
-        setDozeAmount(0f)
-        setDozing(false)
-    }
-
     override fun setAnimateDozingTransitions(animate: Boolean) {
         _animateBottomAreaDozingTransitions.tryEmit(animate)
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryImplTest.kt
deleted file mode 100644
index dc0e6f7..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryImplTest.kt
+++ /dev/null
@@ -1,193 +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.keyguard.data.repository
-
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig
-import com.android.systemui.keyguard.shared.model.KeyguardQuickAffordanceModel
-import com.android.systemui.keyguard.shared.model.KeyguardQuickAffordancePosition
-import com.android.systemui.util.mockito.mock
-import com.google.common.truth.Truth.assertThat
-import kotlin.reflect.KClass
-import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.test.runBlockingTest
-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 KeyguardQuickAffordanceRepositoryImplTest : SysuiTestCase() {
-
-    private lateinit var underTest: KeyguardQuickAffordanceRepository
-
-    private lateinit var homeControls: FakeKeyguardQuickAffordanceConfig
-    private lateinit var quickAccessWallet: FakeKeyguardQuickAffordanceConfig
-    private lateinit var qrCodeScanner: FakeKeyguardQuickAffordanceConfig
-
-    @Before
-    fun setUp() {
-        MockitoAnnotations.initMocks(this)
-
-        homeControls = object : FakeKeyguardQuickAffordanceConfig() {}
-        quickAccessWallet = object : FakeKeyguardQuickAffordanceConfig() {}
-        qrCodeScanner = object : FakeKeyguardQuickAffordanceConfig() {}
-
-        underTest =
-            KeyguardQuickAffordanceRepositoryImpl(
-                configs =
-                    FakeKeyguardQuickAffordanceConfigs(
-                        mapOf(
-                            KeyguardQuickAffordancePosition.BOTTOM_START to
-                                listOf(
-                                    homeControls,
-                                ),
-                            KeyguardQuickAffordancePosition.BOTTOM_END to
-                                listOf(
-                                    quickAccessWallet,
-                                    qrCodeScanner,
-                                ),
-                        ),
-                    ),
-            )
-    }
-
-    @Test
-    fun `bottom start affordance - none`() = runBlockingTest {
-        // TODO(b/239834928): once coroutines.test is updated, switch to the approach described in
-        // https://developer.android.com/kotlin/flow/test#continuous-collection
-        var latest: KeyguardQuickAffordanceModel? = null
-        val job =
-            underTest
-                .affordance(KeyguardQuickAffordancePosition.BOTTOM_START)
-                .onEach { latest = it }
-                .launchIn(this)
-
-        assertThat(latest).isEqualTo(KeyguardQuickAffordanceModel.Hidden)
-        job.cancel()
-    }
-
-    @Test
-    fun `bottom start affordance - home controls`() = runBlockingTest {
-        // TODO(b/239834928): once coroutines.test is updated, switch to the approach described in
-        // https://developer.android.com/kotlin/flow/test#continuous-collection
-        var latest: KeyguardQuickAffordanceModel? = null
-        val job =
-            underTest
-                .affordance(KeyguardQuickAffordancePosition.BOTTOM_START)
-                .onEach { latest = it }
-                .launchIn(this)
-
-        val state =
-            KeyguardQuickAffordanceConfig.State.Visible(
-                icon = mock(),
-                contentDescriptionResourceId = CONTENT_DESCRIPTION_RESOURCE_ID,
-            )
-        homeControls.setState(state)
-
-        assertThat(latest).isEqualTo(state.toModel(homeControls::class))
-        job.cancel()
-    }
-
-    @Test
-    fun `bottom end affordance - none`() = runBlockingTest {
-        // TODO(b/239834928): once coroutines.test is updated, switch to the approach described in
-        // https://developer.android.com/kotlin/flow/test#continuous-collection
-        var latest: KeyguardQuickAffordanceModel? = null
-        val job =
-            underTest
-                .affordance(KeyguardQuickAffordancePosition.BOTTOM_END)
-                .onEach { latest = it }
-                .launchIn(this)
-
-        assertThat(latest).isEqualTo(KeyguardQuickAffordanceModel.Hidden)
-        job.cancel()
-    }
-
-    @Test
-    fun `bottom end affordance - quick access wallet`() = runBlockingTest {
-        // TODO(b/239834928): once coroutines.test is updated, switch to the approach described in
-        // https://developer.android.com/kotlin/flow/test#continuous-collection
-        var latest: KeyguardQuickAffordanceModel? = null
-        val job =
-            underTest
-                .affordance(KeyguardQuickAffordancePosition.BOTTOM_END)
-                .onEach { latest = it }
-                .launchIn(this)
-
-        val quickAccessWalletState =
-            KeyguardQuickAffordanceConfig.State.Visible(
-                icon = mock(),
-                contentDescriptionResourceId = CONTENT_DESCRIPTION_RESOURCE_ID,
-            )
-        quickAccessWallet.setState(quickAccessWalletState)
-        val qrCodeScannerState =
-            KeyguardQuickAffordanceConfig.State.Visible(
-                icon = mock(),
-                contentDescriptionResourceId = CONTENT_DESCRIPTION_RESOURCE_ID,
-            )
-        qrCodeScanner.setState(qrCodeScannerState)
-
-        assertThat(latest).isEqualTo(quickAccessWalletState.toModel(quickAccessWallet::class))
-        job.cancel()
-    }
-
-    @Test
-    fun `bottom end affordance - qr code scanner`() = runBlockingTest {
-        // TODO(b/239834928): once coroutines.test is updated, switch to the approach described in
-        // https://developer.android.com/kotlin/flow/test#continuous-collection
-        var latest: KeyguardQuickAffordanceModel? = null
-        val job =
-            underTest
-                .affordance(KeyguardQuickAffordancePosition.BOTTOM_END)
-                .onEach { latest = it }
-                .launchIn(this)
-
-        val state =
-            KeyguardQuickAffordanceConfig.State.Visible(
-                icon = mock(),
-                contentDescriptionResourceId = CONTENT_DESCRIPTION_RESOURCE_ID,
-            )
-        qrCodeScanner.setState(state)
-
-        assertThat(latest).isEqualTo(state.toModel(qrCodeScanner::class))
-        job.cancel()
-    }
-
-    private fun KeyguardQuickAffordanceConfig.State?.toModel(
-        configKey: KClass<out KeyguardQuickAffordanceConfig>,
-    ): KeyguardQuickAffordanceModel? {
-        return when (this) {
-            is KeyguardQuickAffordanceConfig.State.Visible ->
-                KeyguardQuickAffordanceModel.Visible(
-                    configKey = configKey,
-                    icon = icon,
-                    contentDescriptionResourceId = CONTENT_DESCRIPTION_RESOURCE_ID,
-                )
-            is KeyguardQuickAffordanceConfig.State.Hidden -> KeyguardQuickAffordanceModel.Hidden
-            null -> null
-        }
-    }
-
-    companion object {
-        private const val CONTENT_DESCRIPTION_RESOURCE_ID = 1337
-    }
-}
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 3d2c51a..3aa2266 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
@@ -18,7 +18,7 @@
 
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.common.data.model.Position
+import com.android.systemui.common.shared.model.Position
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.mockito.argumentCaptor
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt
new file mode 100644
index 0000000..6ea1daa
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/FakeKeyguardQuickAffordanceConfig.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.keyguard.domain.quickaffordance
+
+import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceConfig.OnClickedResult
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.yield
+
+/**
+ * Fake implementation of a quick affordance data source.
+ *
+ * This class is abstract to force tests to provide extensions of it as the system that references
+ * these configs uses each implementation's class type to refer to them.
+ */
+abstract class FakeKeyguardQuickAffordanceConfig : KeyguardQuickAffordanceConfig {
+
+    var onClickedResult: OnClickedResult = OnClickedResult.Handled
+
+    private val _state =
+        MutableStateFlow<KeyguardQuickAffordanceConfig.State>(
+            KeyguardQuickAffordanceConfig.State.Hidden
+        )
+    override val state: Flow<KeyguardQuickAffordanceConfig.State> = _state
+
+    override fun onQuickAffordanceClicked(
+        animationController: ActivityLaunchAnimator.Controller?,
+    ): OnClickedResult {
+        return onClickedResult
+    }
+
+    suspend fun setState(state: KeyguardQuickAffordanceConfig.State) {
+        _state.value = state
+        // Yield to allow the test's collection coroutine to "catch up" and collect this value
+        // before the test continues to the next line.
+        // TODO(b/239834928): once coroutines.test is updated, switch to the approach described in
+        // https://developer.android.com/kotlin/flow/test#continuous-collection and remove this.
+        yield()
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/FakeKeyguardQuickAffordanceRegistry.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/FakeKeyguardQuickAffordanceRegistry.kt
new file mode 100644
index 0000000..e68c43f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/FakeKeyguardQuickAffordanceRegistry.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.keyguard.domain.quickaffordance
+
+import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordancePosition
+import kotlin.reflect.KClass
+
+/** Fake implementation of [FakeKeyguardQuickAffordanceRegistry], for tests. */
+class FakeKeyguardQuickAffordanceRegistry(
+    private val configsByPosition:
+        Map<KeyguardQuickAffordancePosition, List<FakeKeyguardQuickAffordanceConfig>>,
+) : KeyguardQuickAffordanceRegistry<FakeKeyguardQuickAffordanceConfig> {
+
+    override fun getAll(
+        position: KeyguardQuickAffordancePosition
+    ): List<FakeKeyguardQuickAffordanceConfig> {
+        return configsByPosition.getValue(position)
+    }
+
+    override fun get(
+        configClass: KClass<out FakeKeyguardQuickAffordanceConfig>
+    ): FakeKeyguardQuickAffordanceConfig {
+        return configsByPosition.values
+            .flatten()
+            .associateBy { config -> config::class }
+            .getValue(configClass)
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt
similarity index 69%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt
index bcc76ab..9acd21c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt
@@ -1,20 +1,21 @@
 /*
- * Copyright (C) 2022 The Android Open Source Project
+ *  Copyright (C) 2022 The Android Open Source Project
  *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *       http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
  */
 
-package com.android.systemui.keyguard.data.repository
+package com.android.systemui.keyguard.domain.quickaffordance
 
 import androidx.test.filters.SmallTest
 import com.android.systemui.R
@@ -22,11 +23,10 @@
 import com.android.systemui.controls.controller.ControlsController
 import com.android.systemui.controls.dagger.ControlsComponent
 import com.android.systemui.controls.management.ControlsListingController
-import com.android.systemui.keyguard.data.quickaffordance.HomeControlsKeyguardQuickAffordanceConfig
-import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig
 import com.android.systemui.util.mockito.mock
 import com.google.common.truth.Truth.assertThat
 import java.util.Optional
+import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.test.runBlockingTest
@@ -50,18 +50,19 @@
     companion object {
         @Parameters(
             name =
-                "feature enabled = {0}, has favorites = {1}, has service infos = {2} - expected" +
-                    " visible = {3}"
+                "feature enabled = {0}, has favorites = {1}, has service infos = {2}, can show" +
+                    " while locked = {3} - expected visible = {4}"
         )
         @JvmStatic
         fun data() =
-            (0 until 8)
+            (0 until 16)
                 .map { combination ->
                     arrayOf(
-                        /* isFeatureEnabled= */ combination and 0b100 != 0,
-                        /* hasFavorites= */ combination and 0b010 != 0,
-                        /* hasServiceInfos= */ combination and 0b001 != 0,
-                        /* isVisible= */ combination == 0b111,
+                        /* isFeatureEnabled= */ combination and 0b1000 != 0,
+                        /* hasFavorites= */ combination and 0b0100 != 0,
+                        /* hasServiceInfos= */ combination and 0b0010 != 0,
+                        /* canShowWhileLocked= */ combination and 0b0001 != 0,
+                        /* isVisible= */ combination == 0b1111,
                     )
                 }
                 .toList()
@@ -79,7 +80,8 @@
     @JvmField @Parameter(0) var isFeatureEnabled: Boolean = false
     @JvmField @Parameter(1) var hasFavorites: Boolean = false
     @JvmField @Parameter(2) var hasServiceInfos: Boolean = false
-    @JvmField @Parameter(3) var isVisible: Boolean = false
+    @JvmField @Parameter(3) var canShowWhileLocked: Boolean = false
+    @JvmField @Parameter(4) var isVisible: Boolean = false
 
     @Before
     fun setUp() {
@@ -89,6 +91,8 @@
         whenever(component.getControlsController()).thenReturn(Optional.of(controlsController))
         whenever(component.getControlsListingController())
             .thenReturn(Optional.of(controlsListingController))
+        whenever(component.canShowWhileLockedSetting)
+            .thenReturn(MutableStateFlow(canShowWhileLocked))
 
         underTest =
             HomeControlsKeyguardQuickAffordanceConfig(
@@ -111,14 +115,16 @@
         val values = mutableListOf<KeyguardQuickAffordanceConfig.State>()
         val job = underTest.state.onEach(values::add).launchIn(this)
 
-        verify(controlsListingController).addCallback(callbackCaptor.capture())
-        callbackCaptor.value.onServicesUpdated(
-            if (hasServiceInfos) {
-                listOf(mock())
-            } else {
-                emptyList()
-            }
-        )
+        if (canShowWhileLocked) {
+            verify(controlsListingController).addCallback(callbackCaptor.capture())
+            callbackCaptor.value.onServicesUpdated(
+                if (hasServiceInfos) {
+                    listOf(mock())
+                } else {
+                    emptyList()
+                }
+            )
+        }
 
         assertThat(values.last())
             .isInstanceOf(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
similarity index 73%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
index 592e80b..059487d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
@@ -15,7 +15,7 @@
  *
  */
 
-package com.android.systemui.keyguard.data.quickaffordance
+package com.android.systemui.keyguard.domain.quickaffordance
 
 import androidx.test.filters.SmallTest
 import com.android.systemui.R
@@ -23,7 +23,7 @@
 import com.android.systemui.animation.ActivityLaunchAnimator
 import com.android.systemui.controls.controller.ControlsController
 import com.android.systemui.controls.dagger.ControlsComponent
-import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.OnClickedResult
+import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceConfig.OnClickedResult
 import com.android.systemui.util.mockito.mock
 import com.google.common.truth.Truth.assertThat
 import java.util.Optional
@@ -51,6 +51,7 @@
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
+        whenever(component.canShowWhileLockedSetting).thenReturn(MutableStateFlow(true))
 
         underTest =
             HomeControlsKeyguardQuickAffordanceConfig(
@@ -60,7 +61,26 @@
     }
 
     @Test
-    fun `state - when listing controller is missing - returns None`() = runBlockingTest {
+    fun `state - when cannot show while locked - returns Hidden`() = runBlockingTest {
+        whenever(component.canShowWhileLockedSetting).thenReturn(MutableStateFlow(false))
+        whenever(component.isEnabled()).thenReturn(true)
+        whenever(component.getTileImageId()).thenReturn(R.drawable.controls_icon)
+        whenever(component.getTileTitleId()).thenReturn(R.string.quick_controls_title)
+        val controlsController = mock<ControlsController>()
+        whenever(component.getControlsController()).thenReturn(Optional.of(controlsController))
+        whenever(component.getControlsListingController()).thenReturn(Optional.empty())
+        whenever(controlsController.getFavorites()).thenReturn(listOf(mock()))
+
+        val values = mutableListOf<KeyguardQuickAffordanceConfig.State>()
+        val job = underTest.state.onEach(values::add).launchIn(this)
+
+        assertThat(values.last())
+            .isInstanceOf(KeyguardQuickAffordanceConfig.State.Hidden::class.java)
+        job.cancel()
+    }
+
+    @Test
+    fun `state - when listing controller is missing - returns Hidden`() = runBlockingTest {
         whenever(component.isEnabled()).thenReturn(true)
         whenever(component.getTileImageId()).thenReturn(R.drawable.controls_icon)
         whenever(component.getTileTitleId()).thenReturn(R.string.quick_controls_title)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt
similarity index 96%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt
index 6fd04de..d4fba41 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt
@@ -15,12 +15,12 @@
  *
  */
 
-package com.android.systemui.keyguard.data.quickaffordance
+package com.android.systemui.keyguard.domain.quickaffordance
 
 import android.content.Intent
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.OnClickedResult
+import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceConfig.OnClickedResult
 import com.android.systemui.qrcodescanner.controller.QRCodeScannerController
 import com.android.systemui.util.mockito.argumentCaptor
 import com.android.systemui.util.mockito.mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt
index 345c51f..5a3a78e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt
@@ -15,7 +15,7 @@
  *
  */
 
-package com.android.systemui.keyguard.data.quickaffordance
+package com.android.systemui.keyguard.domain.quickaffordance
 
 import android.graphics.drawable.Drawable
 import android.service.quickaccesswallet.GetWalletCardsResponse
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/FakeLaunchKeyguardQuickAffordanceUseCase.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/FakeLaunchKeyguardQuickAffordanceUseCase.kt
deleted file mode 100644
index ba0c31f..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/FakeLaunchKeyguardQuickAffordanceUseCase.kt
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.keyguard.domain.usecase
-
-import android.content.Intent
-import com.android.systemui.animation.ActivityLaunchAnimator
-
-/** Fake implementation of [LaunchKeyguardQuickAffordanceUseCase], for tests. */
-class FakeLaunchKeyguardQuickAffordanceUseCase : LaunchKeyguardQuickAffordanceUseCase {
-
-    data class Invocation(
-        val intent: Intent,
-        val canShowWhileLocked: Boolean,
-        val animationController: ActivityLaunchAnimator.Controller?
-    )
-
-    private val _invocations = mutableListOf<Invocation>()
-    val invocations: List<Invocation> = _invocations
-
-    override fun invoke(
-        intent: Intent,
-        canShowWhileLocked: Boolean,
-        animationController: ActivityLaunchAnimator.Controller?
-    ) {
-        _invocations.add(
-            Invocation(
-                intent = intent,
-                canShowWhileLocked = canShowWhileLocked,
-                animationController = animationController,
-            )
-        )
-    }
-}
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
new file mode 100644
index 0000000..c5e828e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/KeyguardQuickAffordanceInteractorParameterizedTest.kt
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.domain.usecase
+
+import android.content.Intent
+import androidx.test.filters.SmallTest
+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.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor
+import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordancePosition
+import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAffordanceConfig
+import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAffordanceRegistry
+import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceConfig
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.mock
+import kotlinx.coroutines.test.runBlockingTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import org.junit.runners.Parameterized.Parameter
+import org.junit.runners.Parameterized.Parameters
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.ArgumentMatchers.same
+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
+@RunWith(Parameterized::class)
+class KeyguardQuickAffordanceInteractorParameterizedTest : SysuiTestCase() {
+
+    companion object {
+        private val INTENT = Intent("some.intent.action")
+        private val DRAWABLE = mock<ContainedDrawable>()
+        private const val CONTENT_DESCRIPTION_RESOURCE_ID = 1337
+
+        @Parameters(
+            name =
+                "needStrongAuthAfterBoot={0}, canShowWhileLocked={1}," +
+                    " keyguardIsUnlocked={2}, needsToUnlockFirst={3}, startActivity={4}"
+        )
+        @JvmStatic
+        fun data() =
+            listOf(
+                arrayOf(
+                    /* needStrongAuthAfterBoot= */ false,
+                    /* canShowWhileLocked= */ false,
+                    /* keyguardIsUnlocked= */ false,
+                    /* needsToUnlockFirst= */ true,
+                    /* startActivity= */ false,
+                ),
+                arrayOf(
+                    /* needStrongAuthAfterBoot= */ false,
+                    /* canShowWhileLocked= */ false,
+                    /* keyguardIsUnlocked= */ true,
+                    /* needsToUnlockFirst= */ false,
+                    /* startActivity= */ false,
+                ),
+                arrayOf(
+                    /* needStrongAuthAfterBoot= */ false,
+                    /* canShowWhileLocked= */ true,
+                    /* keyguardIsUnlocked= */ false,
+                    /* needsToUnlockFirst= */ false,
+                    /* startActivity= */ false,
+                ),
+                arrayOf(
+                    /* needStrongAuthAfterBoot= */ false,
+                    /* canShowWhileLocked= */ true,
+                    /* keyguardIsUnlocked= */ true,
+                    /* needsToUnlockFirst= */ false,
+                    /* startActivity= */ false,
+                ),
+                arrayOf(
+                    /* needStrongAuthAfterBoot= */ true,
+                    /* canShowWhileLocked= */ false,
+                    /* keyguardIsUnlocked= */ false,
+                    /* needsToUnlockFirst= */ true,
+                    /* startActivity= */ false,
+                ),
+                arrayOf(
+                    /* needStrongAuthAfterBoot= */ true,
+                    /* canShowWhileLocked= */ false,
+                    /* keyguardIsUnlocked= */ true,
+                    /* needsToUnlockFirst= */ true,
+                    /* startActivity= */ false,
+                ),
+                arrayOf(
+                    /* needStrongAuthAfterBoot= */ true,
+                    /* canShowWhileLocked= */ true,
+                    /* keyguardIsUnlocked= */ false,
+                    /* needsToUnlockFirst= */ true,
+                    /* startActivity= */ false,
+                ),
+                arrayOf(
+                    /* needStrongAuthAfterBoot= */ true,
+                    /* canShowWhileLocked= */ true,
+                    /* keyguardIsUnlocked= */ true,
+                    /* needsToUnlockFirst= */ true,
+                    /* startActivity= */ false,
+                ),
+                arrayOf(
+                    /* needStrongAuthAfterBoot= */ false,
+                    /* canShowWhileLocked= */ false,
+                    /* keyguardIsUnlocked= */ false,
+                    /* needsToUnlockFirst= */ true,
+                    /* startActivity= */ true,
+                ),
+                arrayOf(
+                    /* needStrongAuthAfterBoot= */ false,
+                    /* canShowWhileLocked= */ false,
+                    /* keyguardIsUnlocked= */ true,
+                    /* needsToUnlockFirst= */ false,
+                    /* startActivity= */ true,
+                ),
+                arrayOf(
+                    /* needStrongAuthAfterBoot= */ false,
+                    /* canShowWhileLocked= */ true,
+                    /* keyguardIsUnlocked= */ false,
+                    /* needsToUnlockFirst= */ false,
+                    /* startActivity= */ true,
+                ),
+                arrayOf(
+                    /* needStrongAuthAfterBoot= */ false,
+                    /* canShowWhileLocked= */ true,
+                    /* keyguardIsUnlocked= */ true,
+                    /* needsToUnlockFirst= */ false,
+                    /* startActivity= */ true,
+                ),
+                arrayOf(
+                    /* needStrongAuthAfterBoot= */ true,
+                    /* canShowWhileLocked= */ false,
+                    /* keyguardIsUnlocked= */ false,
+                    /* needsToUnlockFirst= */ true,
+                    /* startActivity= */ true,
+                ),
+                arrayOf(
+                    /* needStrongAuthAfterBoot= */ true,
+                    /* canShowWhileLocked= */ false,
+                    /* keyguardIsUnlocked= */ true,
+                    /* needsToUnlockFirst= */ true,
+                    /* startActivity= */ true,
+                ),
+                arrayOf(
+                    /* needStrongAuthAfterBoot= */ true,
+                    /* canShowWhileLocked= */ true,
+                    /* keyguardIsUnlocked= */ false,
+                    /* needsToUnlockFirst= */ true,
+                    /* startActivity= */ true,
+                ),
+                arrayOf(
+                    /* needStrongAuthAfterBoot= */ true,
+                    /* canShowWhileLocked= */ true,
+                    /* keyguardIsUnlocked= */ true,
+                    /* needsToUnlockFirst= */ true,
+                    /* startActivity= */ true,
+                ),
+            )
+    }
+
+    @Mock private lateinit var lockPatternUtils: LockPatternUtils
+    @Mock private lateinit var keyguardStateController: KeyguardStateController
+    @Mock private lateinit var userTracker: UserTracker
+    @Mock private lateinit var activityStarter: ActivityStarter
+    @Mock private lateinit var animationController: ActivityLaunchAnimator.Controller
+
+    private lateinit var underTest: KeyguardQuickAffordanceInteractor
+
+    @JvmField @Parameter(0) var needStrongAuthAfterBoot: Boolean = false
+    @JvmField @Parameter(1) var canShowWhileLocked: Boolean = false
+    @JvmField @Parameter(2) var keyguardIsUnlocked: Boolean = false
+    @JvmField @Parameter(3) var needsToUnlockFirst: Boolean = false
+    @JvmField @Parameter(4) var startActivity: Boolean = false
+    private lateinit var homeControls: FakeKeyguardQuickAffordanceConfig
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        homeControls = object : FakeKeyguardQuickAffordanceConfig() {}
+        underTest =
+            KeyguardQuickAffordanceInteractor(
+                keyguardInteractor = KeyguardInteractor(repository = FakeKeyguardRepository()),
+                registry =
+                    FakeKeyguardQuickAffordanceRegistry(
+                        mapOf(
+                            KeyguardQuickAffordancePosition.BOTTOM_START to
+                                listOf(
+                                    homeControls,
+                                ),
+                            KeyguardQuickAffordancePosition.BOTTOM_END to
+                                listOf(
+                                    object : FakeKeyguardQuickAffordanceConfig() {},
+                                    object : FakeKeyguardQuickAffordanceConfig() {},
+                                ),
+                        ),
+                    ),
+                lockPatternUtils = lockPatternUtils,
+                keyguardStateController = keyguardStateController,
+                userTracker = userTracker,
+                activityStarter = activityStarter,
+            )
+    }
+
+    @Test
+    fun onQuickAffordanceClicked() = runBlockingTest {
+        setUpMocks(
+            needStrongAuthAfterBoot = needStrongAuthAfterBoot,
+            keyguardIsUnlocked = keyguardIsUnlocked,
+        )
+
+        homeControls.setState(
+            state =
+                KeyguardQuickAffordanceConfig.State.Visible(
+                    icon = DRAWABLE,
+                    contentDescriptionResourceId = CONTENT_DESCRIPTION_RESOURCE_ID,
+                )
+        )
+        homeControls.onClickedResult =
+            if (startActivity) {
+                KeyguardQuickAffordanceConfig.OnClickedResult.StartActivity(
+                    intent = INTENT,
+                    canShowWhileLocked = canShowWhileLocked,
+                )
+            } else {
+                KeyguardQuickAffordanceConfig.OnClickedResult.Handled
+            }
+
+        underTest.onQuickAffordanceClicked(
+            configKey = homeControls::class,
+            animationController = animationController,
+        )
+
+        if (startActivity) {
+            if (needsToUnlockFirst) {
+                verify(activityStarter)
+                    .postStartActivityDismissingKeyguard(
+                        any(),
+                        /* delay= */ eq(0),
+                        same(animationController),
+                    )
+            } else {
+                verify(activityStarter)
+                    .startActivity(
+                        any(),
+                        /* dismissShade= */ eq(true),
+                        same(animationController),
+                        /* showOverLockscreenWhenLocked= */ eq(true),
+                    )
+            }
+        } else {
+            verifyZeroInteractions(activityStarter)
+        }
+    }
+
+    private fun setUpMocks(
+        needStrongAuthAfterBoot: Boolean = true,
+        keyguardIsUnlocked: Boolean = false,
+    ) {
+        whenever(userTracker.userHandle).thenReturn(mock())
+        whenever(lockPatternUtils.getStrongAuthForUser(any()))
+            .thenReturn(
+                if (needStrongAuthAfterBoot) {
+                    LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT
+                } else {
+                    LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED
+                }
+            )
+        whenever(keyguardStateController.isUnlocked).thenReturn(keyguardIsUnlocked)
+    }
+}
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
new file mode 100644
index 0000000..d3fc29f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/KeyguardQuickAffordanceInteractorTest.kt
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.domain.usecase
+
+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.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor
+import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordanceModel
+import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordancePosition
+import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAffordanceConfig
+import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAffordanceRegistry
+import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceConfig
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.util.mockito.mock
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.runBlockingTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(JUnit4::class)
+class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() {
+
+    @Mock private lateinit var lockPatternUtils: LockPatternUtils
+    @Mock private lateinit var keyguardStateController: KeyguardStateController
+    @Mock private lateinit var userTracker: UserTracker
+    @Mock private lateinit var activityStarter: ActivityStarter
+
+    private lateinit var underTest: KeyguardQuickAffordanceInteractor
+
+    private lateinit var repository: FakeKeyguardRepository
+    private lateinit var homeControls: FakeKeyguardQuickAffordanceConfig
+    private lateinit var quickAccessWallet: FakeKeyguardQuickAffordanceConfig
+    private lateinit var qrCodeScanner: FakeKeyguardQuickAffordanceConfig
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        repository = FakeKeyguardRepository()
+        repository.setKeyguardShowing(true)
+
+        homeControls = object : FakeKeyguardQuickAffordanceConfig() {}
+        quickAccessWallet = object : FakeKeyguardQuickAffordanceConfig() {}
+        qrCodeScanner = object : FakeKeyguardQuickAffordanceConfig() {}
+
+        underTest =
+            KeyguardQuickAffordanceInteractor(
+                keyguardInteractor = KeyguardInteractor(repository = repository),
+                registry =
+                    FakeKeyguardQuickAffordanceRegistry(
+                        mapOf(
+                            KeyguardQuickAffordancePosition.BOTTOM_START to
+                                listOf(
+                                    homeControls,
+                                ),
+                            KeyguardQuickAffordancePosition.BOTTOM_END to
+                                listOf(
+                                    quickAccessWallet,
+                                    qrCodeScanner,
+                                ),
+                        ),
+                    ),
+                lockPatternUtils = lockPatternUtils,
+                keyguardStateController = keyguardStateController,
+                userTracker = userTracker,
+                activityStarter = activityStarter,
+            )
+    }
+
+    @Test
+    fun `quickAffordance - bottom start affordance is visible`() = runBlockingTest {
+        val configKey = homeControls::class
+        homeControls.setState(
+            KeyguardQuickAffordanceConfig.State.Visible(
+                icon = ICON,
+                contentDescriptionResourceId = CONTENT_DESCRIPTION_RESOURCE_ID,
+            )
+        )
+
+        var latest: KeyguardQuickAffordanceModel? = null
+        val job =
+            underTest
+                .quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_START)
+                .onEach { latest = it }
+                .launchIn(this)
+
+        assertThat(latest).isInstanceOf(KeyguardQuickAffordanceModel.Visible::class.java)
+        val visibleModel = latest as KeyguardQuickAffordanceModel.Visible
+        assertThat(visibleModel.configKey).isEqualTo(configKey)
+        assertThat(visibleModel.icon).isEqualTo(ICON)
+        assertThat(visibleModel.contentDescriptionResourceId)
+            .isEqualTo(CONTENT_DESCRIPTION_RESOURCE_ID)
+        job.cancel()
+    }
+
+    @Test
+    fun `quickAffordance - bottom end affordance is visible`() = runBlockingTest {
+        val configKey = quickAccessWallet::class
+        quickAccessWallet.setState(
+            KeyguardQuickAffordanceConfig.State.Visible(
+                icon = ICON,
+                contentDescriptionResourceId = CONTENT_DESCRIPTION_RESOURCE_ID,
+            )
+        )
+
+        var latest: KeyguardQuickAffordanceModel? = null
+        val job =
+            underTest
+                .quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_END)
+                .onEach { latest = it }
+                .launchIn(this)
+
+        assertThat(latest).isInstanceOf(KeyguardQuickAffordanceModel.Visible::class.java)
+        val visibleModel = latest as KeyguardQuickAffordanceModel.Visible
+        assertThat(visibleModel.configKey).isEqualTo(configKey)
+        assertThat(visibleModel.icon).isEqualTo(ICON)
+        assertThat(visibleModel.contentDescriptionResourceId)
+            .isEqualTo(CONTENT_DESCRIPTION_RESOURCE_ID)
+        job.cancel()
+    }
+
+    @Test
+    fun `quickAffordance - bottom start affordance hidden while dozing`() = runBlockingTest {
+        repository.setDozing(true)
+        homeControls.setState(
+            KeyguardQuickAffordanceConfig.State.Visible(
+                icon = ICON,
+                contentDescriptionResourceId = CONTENT_DESCRIPTION_RESOURCE_ID,
+            )
+        )
+
+        var latest: KeyguardQuickAffordanceModel? = null
+        val job =
+            underTest
+                .quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_START)
+                .onEach { latest = it }
+                .launchIn(this)
+        assertThat(latest).isEqualTo(KeyguardQuickAffordanceModel.Hidden)
+        job.cancel()
+    }
+
+    @Test
+    fun `quickAffordance - bottom start affordance hidden when lockscreen is not showing`() =
+        runBlockingTest {
+            repository.setKeyguardShowing(false)
+            homeControls.setState(
+                KeyguardQuickAffordanceConfig.State.Visible(
+                    icon = ICON,
+                    contentDescriptionResourceId = CONTENT_DESCRIPTION_RESOURCE_ID,
+                )
+            )
+
+            var latest: KeyguardQuickAffordanceModel? = null
+            val job =
+                underTest
+                    .quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_START)
+                    .onEach { latest = it }
+                    .launchIn(this)
+            assertThat(latest).isEqualTo(KeyguardQuickAffordanceModel.Hidden)
+            job.cancel()
+        }
+
+    companion object {
+        private val ICON: ContainedDrawable = mock()
+        private const val CONTENT_DESCRIPTION_RESOURCE_ID = 1337
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/LaunchKeyguardQuickAffordanceUseCaseImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/LaunchKeyguardQuickAffordanceUseCaseImplTest.kt
deleted file mode 100644
index b3c1ae0..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/LaunchKeyguardQuickAffordanceUseCaseImplTest.kt
+++ /dev/null
@@ -1,178 +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.keyguard.domain.usecase
-
-import android.content.Intent
-import androidx.test.filters.SmallTest
-import com.android.internal.widget.LockPatternUtils
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.animation.ActivityLaunchAnimator
-import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.settings.UserTracker
-import com.android.systemui.statusbar.policy.KeyguardStateController
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.mock
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.Parameterized
-import org.junit.runners.Parameterized.Parameter
-import org.junit.runners.Parameterized.Parameters
-import org.mockito.Mock
-import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
-import org.mockito.MockitoAnnotations
-
-@SmallTest
-@RunWith(Parameterized::class)
-class LaunchKeyguardQuickAffordanceUseCaseImplTest : SysuiTestCase() {
-
-    companion object {
-        private val INTENT = Intent("some.intent.action")
-
-        @Parameters(
-            name =
-                "needStrongAuthAfterBoot={0}, canShowWhileLocked={1}," +
-                    " keyguardIsUnlocked={2}, needsToUnlockFirst={3}"
-        )
-        @JvmStatic
-        fun data() =
-            listOf(
-                arrayOf(
-                    /* needStrongAuthAfterBoot= */ false,
-                    /* canShowWhileLocked= */ false,
-                    /* keyguardIsUnlocked= */ false,
-                    /* needsToUnlockFirst= */ true,
-                ),
-                arrayOf(
-                    /* needStrongAuthAfterBoot= */ false,
-                    /* canShowWhileLocked= */ false,
-                    /* keyguardIsUnlocked= */ true,
-                    /* needsToUnlockFirst= */ false,
-                ),
-                arrayOf(
-                    /* needStrongAuthAfterBoot= */ false,
-                    /* canShowWhileLocked= */ true,
-                    /* keyguardIsUnlocked= */ false,
-                    /* needsToUnlockFirst= */ false,
-                ),
-                arrayOf(
-                    /* needStrongAuthAfterBoot= */ false,
-                    /* canShowWhileLocked= */ true,
-                    /* keyguardIsUnlocked= */ true,
-                    /* needsToUnlockFirst= */ false,
-                ),
-                arrayOf(
-                    /* needStrongAuthAfterBoot= */ true,
-                    /* canShowWhileLocked= */ false,
-                    /* keyguardIsUnlocked= */ false,
-                    /* needsToUnlockFirst= */ true,
-                ),
-                arrayOf(
-                    /* needStrongAuthAfterBoot= */ true,
-                    /* canShowWhileLocked= */ false,
-                    /* keyguardIsUnlocked= */ true,
-                    /* needsToUnlockFirst= */ true,
-                ),
-                arrayOf(
-                    /* needStrongAuthAfterBoot= */ true,
-                    /* canShowWhileLocked= */ true,
-                    /* keyguardIsUnlocked= */ false,
-                    /* needsToUnlockFirst= */ true,
-                ),
-                arrayOf(
-                    /* needStrongAuthAfterBoot= */ true,
-                    /* canShowWhileLocked= */ true,
-                    /* keyguardIsUnlocked= */ true,
-                    /* needsToUnlockFirst= */ true,
-                ),
-            )
-    }
-
-    @Mock private lateinit var lockPatternUtils: LockPatternUtils
-    @Mock private lateinit var keyguardStateController: KeyguardStateController
-    @Mock private lateinit var userTracker: UserTracker
-    @Mock private lateinit var activityStarter: ActivityStarter
-    @Mock private lateinit var animationController: ActivityLaunchAnimator.Controller
-
-    private lateinit var underTest: LaunchKeyguardQuickAffordanceUseCase
-
-    @JvmField @Parameter(0) var needStrongAuthAfterBoot: Boolean = false
-    @JvmField @Parameter(1) var canShowWhileLocked: Boolean = false
-    @JvmField @Parameter(2) var keyguardIsUnlocked: Boolean = false
-    @JvmField @Parameter(3) var needsToUnlockFirst: Boolean = false
-
-    @Before
-    fun setUp() {
-        MockitoAnnotations.initMocks(this)
-
-        underTest =
-            LaunchKeyguardQuickAffordanceUseCaseImpl(
-                lockPatternUtils = lockPatternUtils,
-                keyguardStateController = keyguardStateController,
-                userTracker = userTracker,
-                activityStarter = activityStarter,
-            )
-    }
-
-    @Test
-    fun invoke() {
-        setUpMocks(
-            needStrongAuthAfterBoot = needStrongAuthAfterBoot,
-            keyguardIsUnlocked = keyguardIsUnlocked,
-        )
-
-        underTest(
-            intent = INTENT,
-            canShowWhileLocked = canShowWhileLocked,
-            animationController = animationController,
-        )
-
-        if (needsToUnlockFirst) {
-            verify(activityStarter)
-                .postStartActivityDismissingKeyguard(
-                    INTENT,
-                    /* delay= */ 0,
-                    animationController,
-                )
-        } else {
-            verify(activityStarter)
-                .startActivity(
-                    INTENT,
-                    /* dismissShade= */ true,
-                    animationController,
-                    /* showOverLockscreenWhenLocked= */ true,
-                )
-        }
-    }
-
-    private fun setUpMocks(
-        needStrongAuthAfterBoot: Boolean = true,
-        keyguardIsUnlocked: Boolean = false,
-    ) {
-        whenever(userTracker.userHandle).thenReturn(mock())
-        whenever(lockPatternUtils.getStrongAuthForUser(any()))
-            .thenReturn(
-                if (needStrongAuthAfterBoot) {
-                    LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT
-                } else {
-                    LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED
-                }
-            )
-        whenever(keyguardStateController.isUnlocked).thenReturn(keyguardIsUnlocked)
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/ObserveKeyguardQuickAffordanceUseCaseTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/ObserveKeyguardQuickAffordanceUseCaseTest.kt
deleted file mode 100644
index b90400be..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/ObserveKeyguardQuickAffordanceUseCaseTest.kt
+++ /dev/null
@@ -1,161 +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.keyguard.domain.usecase
-
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.containeddrawable.ContainedDrawable
-import com.android.systemui.keyguard.data.quickaffordance.HomeControlsKeyguardQuickAffordanceConfig
-import com.android.systemui.keyguard.data.repository.FakeKeyguardQuickAffordanceRepository
-import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
-import com.android.systemui.keyguard.shared.model.KeyguardQuickAffordanceModel
-import com.android.systemui.keyguard.shared.model.KeyguardQuickAffordancePosition
-import com.android.systemui.util.mockito.mock
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.test.runBlockingTest
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@SmallTest
-@RunWith(JUnit4::class)
-class ObserveKeyguardQuickAffordanceUseCaseTest : SysuiTestCase() {
-
-    private lateinit var underTest: ObserveKeyguardQuickAffordanceUseCase
-
-    private lateinit var repository: FakeKeyguardRepository
-    private lateinit var quickAffordanceRepository: FakeKeyguardQuickAffordanceRepository
-    private lateinit var isDozingUseCase: ObserveIsDozingUseCase
-    private lateinit var isKeyguardShowingUseCase: ObserveIsKeyguardShowingUseCase
-
-    @Before
-    fun setUp() {
-        repository = FakeKeyguardRepository()
-        repository.setKeyguardShowing(true)
-        isDozingUseCase = ObserveIsDozingUseCase(repository)
-        isKeyguardShowingUseCase = ObserveIsKeyguardShowingUseCase(repository)
-        quickAffordanceRepository = FakeKeyguardQuickAffordanceRepository()
-
-        underTest =
-            ObserveKeyguardQuickAffordanceUseCase(
-                repository = quickAffordanceRepository,
-                isDozingUseCase = isDozingUseCase,
-                isKeyguardShowingUseCase = isKeyguardShowingUseCase,
-            )
-    }
-
-    @Test
-    fun `invoke - affordance is visible`() = runBlockingTest {
-        val configKey = HomeControlsKeyguardQuickAffordanceConfig::class
-        val model =
-            KeyguardQuickAffordanceModel.Visible(
-                configKey = configKey,
-                icon = ICON,
-                contentDescriptionResourceId = CONTENT_DESCRIPTION_RESOURCE_ID,
-            )
-        quickAffordanceRepository.setModel(
-            KeyguardQuickAffordancePosition.BOTTOM_END,
-            model,
-        )
-
-        var latest: KeyguardQuickAffordanceModel? = null
-        val job =
-            underTest(KeyguardQuickAffordancePosition.BOTTOM_END)
-                .onEach { latest = it }
-                .launchIn(this)
-
-        assertThat(latest).isInstanceOf(KeyguardQuickAffordanceModel.Visible::class.java)
-        val visibleModel = latest as KeyguardQuickAffordanceModel.Visible
-        assertThat(visibleModel.configKey).isEqualTo(configKey)
-        assertThat(visibleModel.icon).isEqualTo(ICON)
-        assertThat(visibleModel.contentDescriptionResourceId)
-            .isEqualTo(CONTENT_DESCRIPTION_RESOURCE_ID)
-        job.cancel()
-    }
-
-    @Test
-    fun `invoke - affordance not visible while dozing`() = runBlockingTest {
-        repository.setDozing(true)
-        val configKey = HomeControlsKeyguardQuickAffordanceConfig::class
-        val model =
-            KeyguardQuickAffordanceModel.Visible(
-                configKey = configKey,
-                icon = ICON,
-                contentDescriptionResourceId = CONTENT_DESCRIPTION_RESOURCE_ID,
-            )
-        quickAffordanceRepository.setModel(
-            KeyguardQuickAffordancePosition.BOTTOM_END,
-            model,
-        )
-
-        var latest: KeyguardQuickAffordanceModel? = null
-        val job =
-            underTest(KeyguardQuickAffordancePosition.BOTTOM_END)
-                .onEach { latest = it }
-                .launchIn(this)
-        assertThat(latest).isEqualTo(KeyguardQuickAffordanceModel.Hidden)
-        job.cancel()
-    }
-
-    @Test
-    fun `invoke - affordance not visible when lockscreen is not showing`() = runBlockingTest {
-        repository.setKeyguardShowing(false)
-        val configKey = HomeControlsKeyguardQuickAffordanceConfig::class
-        val model =
-            KeyguardQuickAffordanceModel.Visible(
-                configKey = configKey,
-                icon = ICON,
-                contentDescriptionResourceId = CONTENT_DESCRIPTION_RESOURCE_ID,
-            )
-        quickAffordanceRepository.setModel(
-            KeyguardQuickAffordancePosition.BOTTOM_END,
-            model,
-        )
-
-        var latest: KeyguardQuickAffordanceModel? = null
-        val job =
-            underTest(KeyguardQuickAffordancePosition.BOTTOM_END)
-                .onEach { latest = it }
-                .launchIn(this)
-        assertThat(latest).isEqualTo(KeyguardQuickAffordanceModel.Hidden)
-        job.cancel()
-    }
-
-    @Test
-    fun `invoke - affordance is none`() = runBlockingTest {
-        quickAffordanceRepository.setModel(
-            KeyguardQuickAffordancePosition.BOTTOM_START,
-            KeyguardQuickAffordanceModel.Hidden,
-        )
-
-        var latest: KeyguardQuickAffordanceModel? = null
-        val job =
-            underTest(KeyguardQuickAffordancePosition.BOTTOM_START)
-                .onEach { latest = it }
-                .launchIn(this)
-        assertThat(latest).isEqualTo(KeyguardQuickAffordanceModel.Hidden)
-        job.cancel()
-    }
-
-    companion object {
-        private val ICON: ContainedDrawable = mock()
-        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 00dd58e..19491f4 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
@@ -18,26 +18,22 @@
 
 import android.content.Intent
 import androidx.test.filters.SmallTest
+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.doze.util.BurnInHelperWrapper
-import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig
-import com.android.systemui.keyguard.data.repository.FakeKeyguardQuickAffordanceConfig
-import com.android.systemui.keyguard.data.repository.FakeKeyguardQuickAffordanceConfigs
-import com.android.systemui.keyguard.data.repository.FakeKeyguardQuickAffordanceRepository
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
-import com.android.systemui.keyguard.domain.usecase.FakeLaunchKeyguardQuickAffordanceUseCase
-import com.android.systemui.keyguard.domain.usecase.ObserveAnimateBottomAreaTransitionsUseCase
-import com.android.systemui.keyguard.domain.usecase.ObserveBottomAreaAlphaUseCase
-import com.android.systemui.keyguard.domain.usecase.ObserveClockPositionUseCase
-import com.android.systemui.keyguard.domain.usecase.ObserveDozeAmountUseCase
-import com.android.systemui.keyguard.domain.usecase.ObserveIsDozingUseCase
-import com.android.systemui.keyguard.domain.usecase.ObserveIsKeyguardShowingUseCase
-import com.android.systemui.keyguard.domain.usecase.ObserveKeyguardQuickAffordanceUseCase
-import com.android.systemui.keyguard.domain.usecase.OnKeyguardQuickAffordanceClickedUseCase
-import com.android.systemui.keyguard.shared.model.KeyguardQuickAffordanceModel
-import com.android.systemui.keyguard.shared.model.KeyguardQuickAffordancePosition
+import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor
+import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordancePosition
+import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAffordanceConfig
+import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAffordanceRegistry
+import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceConfig
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.mock
 import com.google.common.truth.Truth.assertThat
@@ -45,12 +41,15 @@
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.test.runBlockingTest
+import kotlinx.coroutines.yield
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
 import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.verifyZeroInteractions
 import org.mockito.Mockito.`when` as whenever
 import org.mockito.MockitoAnnotations
 
@@ -60,14 +59,15 @@
 
     @Mock private lateinit var animationController: ActivityLaunchAnimator.Controller
     @Mock private lateinit var burnInHelperWrapper: BurnInHelperWrapper
+    @Mock private lateinit var lockPatternUtils: LockPatternUtils
+    @Mock private lateinit var keyguardStateController: KeyguardStateController
+    @Mock private lateinit var userTracker: UserTracker
+    @Mock private lateinit var activityStarter: ActivityStarter
 
     private lateinit var underTest: KeyguardBottomAreaViewModel
 
-    private lateinit var affordanceRepository: FakeKeyguardQuickAffordanceRepository
     private lateinit var repository: FakeKeyguardRepository
-    private lateinit var isDozingUseCase: ObserveIsDozingUseCase
-    private lateinit var isKeyguardShowingUseCase: ObserveIsKeyguardShowingUseCase
-    private lateinit var launchQuickAffordanceUseCase: FakeLaunchKeyguardQuickAffordanceUseCase
+    private lateinit var registry: FakeKeyguardQuickAffordanceRegistry
     private lateinit var homeControlsQuickAffordanceConfig: FakeKeyguardQuickAffordanceConfig
     private lateinit var quickAccessWalletAffordanceConfig: FakeKeyguardQuickAffordanceConfig
     private lateinit var qrCodeScannerAffordanceConfig: FakeKeyguardQuickAffordanceConfig
@@ -78,161 +78,53 @@
         whenever(burnInHelperWrapper.burnInOffset(anyInt(), any()))
             .thenReturn(RETURNED_BURN_IN_OFFSET)
 
-        affordanceRepository = FakeKeyguardQuickAffordanceRepository()
-        repository = FakeKeyguardRepository()
-        isDozingUseCase =
-            ObserveIsDozingUseCase(
-                repository = repository,
-            )
-        isKeyguardShowingUseCase =
-            ObserveIsKeyguardShowingUseCase(
-                repository = repository,
-            )
-        launchQuickAffordanceUseCase = FakeLaunchKeyguardQuickAffordanceUseCase()
         homeControlsQuickAffordanceConfig = object : FakeKeyguardQuickAffordanceConfig() {}
         quickAccessWalletAffordanceConfig = object : FakeKeyguardQuickAffordanceConfig() {}
         qrCodeScannerAffordanceConfig = object : FakeKeyguardQuickAffordanceConfig() {}
+        registry =
+            FakeKeyguardQuickAffordanceRegistry(
+                mapOf(
+                    KeyguardQuickAffordancePosition.BOTTOM_START to
+                        listOf(
+                            homeControlsQuickAffordanceConfig,
+                        ),
+                    KeyguardQuickAffordancePosition.BOTTOM_END to
+                        listOf(
+                            quickAccessWalletAffordanceConfig,
+                            qrCodeScannerAffordanceConfig,
+                        ),
+                ),
+            )
+        repository = FakeKeyguardRepository()
 
+        val keyguardInteractor = KeyguardInteractor(repository = repository)
+        whenever(userTracker.userHandle).thenReturn(mock())
+        whenever(lockPatternUtils.getStrongAuthForUser(anyInt()))
+            .thenReturn(LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED)
         underTest =
             KeyguardBottomAreaViewModel(
-                observeQuickAffordanceUseCase =
-                    ObserveKeyguardQuickAffordanceUseCase(
-                        repository = affordanceRepository,
-                        isDozingUseCase = isDozingUseCase,
-                        isKeyguardShowingUseCase = isKeyguardShowingUseCase,
+                keyguardInteractor = keyguardInteractor,
+                quickAffordanceInteractor =
+                    KeyguardQuickAffordanceInteractor(
+                        keyguardInteractor = keyguardInteractor,
+                        registry = registry,
+                        lockPatternUtils = lockPatternUtils,
+                        keyguardStateController = keyguardStateController,
+                        userTracker = userTracker,
+                        activityStarter = activityStarter,
                     ),
-                onQuickAffordanceClickedUseCase =
-                    OnKeyguardQuickAffordanceClickedUseCase(
-                        configs =
-                            FakeKeyguardQuickAffordanceConfigs(
-                                mapOf(
-                                    KeyguardQuickAffordancePosition.BOTTOM_START to
-                                        listOf(
-                                            homeControlsQuickAffordanceConfig,
-                                        ),
-                                    KeyguardQuickAffordancePosition.BOTTOM_END to
-                                        listOf(
-                                            quickAccessWalletAffordanceConfig,
-                                            qrCodeScannerAffordanceConfig,
-                                        ),
-                                ),
-                            ),
-                        launchAffordanceUseCase = launchQuickAffordanceUseCase,
-                    ),
-                observeBottomAreaAlphaUseCase =
-                    ObserveBottomAreaAlphaUseCase(
-                        repository = repository,
-                    ),
-                observeIsDozingUseCase = isDozingUseCase,
-                observeAnimateBottomAreaTransitionsUseCase =
-                    ObserveAnimateBottomAreaTransitionsUseCase(
-                        repository = repository,
-                    ),
-                observeDozeAmountUseCase =
-                    ObserveDozeAmountUseCase(
-                        repository = repository,
-                    ),
-                observeClockPositionUseCase =
-                    ObserveClockPositionUseCase(
-                        repository = repository,
-                    ),
+                bottomAreaInteractor = KeyguardBottomAreaInteractor(repository = repository),
                 burnInHelperWrapper = burnInHelperWrapper,
             )
     }
 
     @Test
-    fun `startButton - present - not dozing - lockscreen showing - visible model - starts activity on click`() = // ktlint-disable max-line-length
-        runBlockingTest {
-            var latest: KeyguardQuickAffordanceViewModel? = null
-            val job = underTest.startButton.onEach { latest = it }.launchIn(this)
-
-            repository.setDozing(false)
-            repository.setKeyguardShowing(true)
-            val testConfig =
-                TestConfig(
-                    isVisible = true,
-                    icon = mock(),
-                    canShowWhileLocked = false,
-                    intent = Intent("action"),
-                )
-            val configKey =
-                setUpQuickAffordanceModel(
-                    position = KeyguardQuickAffordancePosition.BOTTOM_START,
-                    testConfig = testConfig,
-                )
-
-            assertQuickAffordanceViewModel(
-                viewModel = latest,
-                testConfig = testConfig,
-                configKey = configKey,
-            )
-            job.cancel()
-        }
-
-    @Test
-    fun `endButton - present - not dozing - lockscreen showing - visible model - do nothing on click`() = // ktlint-disable max-line-length
-        runBlockingTest {
-            var latest: KeyguardQuickAffordanceViewModel? = null
-            val job = underTest.endButton.onEach { latest = it }.launchIn(this)
-
-            repository.setDozing(false)
-            repository.setKeyguardShowing(true)
-            val config =
-                TestConfig(
-                    isVisible = true,
-                    icon = mock(),
-                    canShowWhileLocked = false,
-                    intent =
-                        null, // This will cause it to tell the system that the click was handled.
-                )
-            val configKey =
-                setUpQuickAffordanceModel(
-                    position = KeyguardQuickAffordancePosition.BOTTOM_END,
-                    testConfig = config,
-                )
-
-            assertQuickAffordanceViewModel(
-                viewModel = latest,
-                testConfig = config,
-                configKey = configKey,
-            )
-            job.cancel()
-        }
-
-    @Test
-    fun `startButton - not present - not dozing - lockscreen showing - model is none`() =
-        runBlockingTest {
-            var latest: KeyguardQuickAffordanceViewModel? = null
-            val job = underTest.startButton.onEach { latest = it }.launchIn(this)
-
-            repository.setDozing(false)
-            repository.setKeyguardShowing(true)
-            val config =
-                TestConfig(
-                    isVisible = false,
-                )
-            val configKey =
-                setUpQuickAffordanceModel(
-                    position = KeyguardQuickAffordancePosition.BOTTOM_START,
-                    testConfig = config,
-                )
-
-            assertQuickAffordanceViewModel(
-                viewModel = latest,
-                testConfig = config,
-                configKey = configKey,
-            )
-            job.cancel()
-        }
-
-    @Test
-    fun `startButton - present - dozing - lockscreen showing - model is none`() = runBlockingTest {
+    fun `startButton - present - visible model - starts activity on click`() = runBlockingTest {
+        repository.setKeyguardShowing(true)
         var latest: KeyguardQuickAffordanceViewModel? = null
         val job = underTest.startButton.onEach { latest = it }.launchIn(this)
 
-        repository.setDozing(true)
-        repository.setKeyguardShowing(true)
-        val config =
+        val testConfig =
             TestConfig(
                 isVisible = true,
                 icon = mock(),
@@ -242,53 +134,90 @@
         val configKey =
             setUpQuickAffordanceModel(
                 position = KeyguardQuickAffordancePosition.BOTTOM_START,
-                testConfig = config,
+                testConfig = testConfig,
             )
 
         assertQuickAffordanceViewModel(
             viewModel = latest,
-            testConfig = TestConfig(isVisible = false),
+            testConfig = testConfig,
             configKey = configKey,
         )
         job.cancel()
     }
 
     @Test
-    fun `startButton - present - not dozing - lockscreen not showing - model is none`() =
-        runBlockingTest {
-            var latest: KeyguardQuickAffordanceViewModel? = null
-            val job = underTest.startButton.onEach { latest = it }.launchIn(this)
+    fun `endButton - present - visible model - do nothing on click`() = runBlockingTest {
+        repository.setKeyguardShowing(true)
+        var latest: KeyguardQuickAffordanceViewModel? = null
+        val job = underTest.endButton.onEach { latest = it }.launchIn(this)
 
-            repository.setDozing(false)
-            repository.setKeyguardShowing(false)
-            val config =
-                TestConfig(
-                    isVisible = true,
-                    icon = mock(),
-                    canShowWhileLocked = false,
-                    intent = Intent("action"),
-                )
-            val configKey =
-                setUpQuickAffordanceModel(
-                    position = KeyguardQuickAffordancePosition.BOTTOM_START,
-                    testConfig = config,
-                )
-
-            assertQuickAffordanceViewModel(
-                viewModel = latest,
-                testConfig = TestConfig(isVisible = false),
-                configKey = configKey,
+        val config =
+            TestConfig(
+                isVisible = true,
+                icon = mock(),
+                canShowWhileLocked = false,
+                intent = null, // This will cause it to tell the system that the click was handled.
             )
-            job.cancel()
-        }
+        val configKey =
+            setUpQuickAffordanceModel(
+                position = KeyguardQuickAffordancePosition.BOTTOM_END,
+                testConfig = config,
+            )
+
+        assertQuickAffordanceViewModel(
+            viewModel = latest,
+            testConfig = config,
+            configKey = configKey,
+        )
+        job.cancel()
+    }
+
+    @Test
+    fun `startButton - not present - model is hidden`() = runBlockingTest {
+        var latest: KeyguardQuickAffordanceViewModel? = null
+        val job = underTest.startButton.onEach { latest = it }.launchIn(this)
+
+        val config =
+            TestConfig(
+                isVisible = false,
+            )
+        val configKey =
+            setUpQuickAffordanceModel(
+                position = KeyguardQuickAffordancePosition.BOTTOM_START,
+                testConfig = config,
+            )
+
+        assertQuickAffordanceViewModel(
+            viewModel = latest,
+            testConfig = config,
+            configKey = configKey,
+        )
+        job.cancel()
+    }
 
     @Test
     fun animateButtonReveal() = runBlockingTest {
+        repository.setKeyguardShowing(true)
+        val testConfig =
+            TestConfig(
+                isVisible = true,
+                icon = mock(),
+                canShowWhileLocked = false,
+                intent = Intent("action"),
+            )
+
+        setUpQuickAffordanceModel(
+            position = KeyguardQuickAffordancePosition.BOTTOM_START,
+            testConfig = testConfig,
+        )
+
         val values = mutableListOf<Boolean>()
-        val job = underTest.animateButtonReveal.onEach(values::add).launchIn(this)
+        val job = underTest.startButton.onEach { values.add(it.animateReveal) }.launchIn(this)
 
         repository.setAnimateDozingTransitions(true)
+        yield()
         repository.setAnimateDozingTransitions(false)
+        yield()
 
         assertThat(values).isEqualTo(listOf(false, true, false))
         job.cancel()
@@ -413,7 +342,7 @@
         job.cancel()
     }
 
-    private fun setDozeAmountAndCalculateExpectedTranslationY(dozeAmount: Float): Float {
+    private suspend fun setDozeAmountAndCalculateExpectedTranslationY(dozeAmount: Float): Float {
         repository.setDozeAmount(dozeAmount)
         return dozeAmount * (RETURNED_BURN_IN_OFFSET - DEFAULT_BURN_IN_OFFSET)
     }
@@ -421,40 +350,37 @@
     private suspend fun setUpQuickAffordanceModel(
         position: KeyguardQuickAffordancePosition,
         testConfig: TestConfig,
-    ): KClass<*> {
+    ): KClass<out FakeKeyguardQuickAffordanceConfig> {
         val config =
             when (position) {
                 KeyguardQuickAffordancePosition.BOTTOM_START -> homeControlsQuickAffordanceConfig
                 KeyguardQuickAffordancePosition.BOTTOM_END -> quickAccessWalletAffordanceConfig
             }
 
-        affordanceRepository.setModel(
-            position = position,
-            model =
-                if (testConfig.isVisible) {
-                    if (testConfig.intent != null) {
-                        config.onClickedResult =
-                            KeyguardQuickAffordanceConfig.OnClickedResult.StartActivity(
-                                intent = testConfig.intent,
-                                canShowWhileLocked = testConfig.canShowWhileLocked,
-                            )
-                    }
-                    KeyguardQuickAffordanceModel.Visible(
-                        configKey = config::class,
-                        icon = testConfig.icon ?: error("Icon is unexpectedly null!"),
-                        contentDescriptionResourceId = CONTENT_DESCRIPTION_RESOURCE_ID,
-                    )
-                } else {
-                    KeyguardQuickAffordanceModel.Hidden
+        val state =
+            if (testConfig.isVisible) {
+                if (testConfig.intent != null) {
+                    config.onClickedResult =
+                        KeyguardQuickAffordanceConfig.OnClickedResult.StartActivity(
+                            intent = testConfig.intent,
+                            canShowWhileLocked = testConfig.canShowWhileLocked,
+                        )
                 }
-        )
+                KeyguardQuickAffordanceConfig.State.Visible(
+                    icon = testConfig.icon ?: error("Icon is unexpectedly null!"),
+                    contentDescriptionResourceId = CONTENT_DESCRIPTION_RESOURCE_ID,
+                )
+            } else {
+                KeyguardQuickAffordanceConfig.State.Hidden
+            }
+        config.setState(state)
         return config::class
     }
 
     private fun assertQuickAffordanceViewModel(
         viewModel: KeyguardQuickAffordanceViewModel?,
         testConfig: TestConfig,
-        configKey: KClass<*>,
+        configKey: KClass<out FakeKeyguardQuickAffordanceConfig>,
     ) {
         checkNotNull(viewModel)
         assertThat(viewModel.isVisible).isEqualTo(testConfig.isVisible)
@@ -466,19 +392,11 @@
                     animationController = animationController,
                 )
             )
-            testConfig.intent?.let { intent ->
-                assertThat(launchQuickAffordanceUseCase.invocations)
-                    .isEqualTo(
-                        listOf(
-                            FakeLaunchKeyguardQuickAffordanceUseCase.Invocation(
-                                intent = intent,
-                                canShowWhileLocked = testConfig.canShowWhileLocked,
-                                animationController = animationController,
-                            )
-                        )
-                    )
+            if (testConfig.intent != null) {
+                assertThat(Mockito.mockingDetails(activityStarter).invocations).hasSize(1)
+            } else {
+                verifyZeroInteractions(activityStarter)
             }
-                ?: run { assertThat(launchQuickAffordanceUseCase.invocations).isEmpty() }
         } else {
             assertThat(viewModel.isVisible).isFalse()
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataFilterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataFilterTest.kt
index 6a532d7..6468fe1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataFilterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataFilterTest.kt
@@ -17,9 +17,9 @@
 package com.android.systemui.media
 
 import android.app.smartspace.SmartspaceAction
-import androidx.test.filters.SmallTest
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
 import com.android.internal.logging.InstanceId
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.broadcast.BroadcastDispatcher
@@ -29,18 +29,18 @@
 import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.Executor
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.ArgumentMatchers.anyBoolean
 import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.Mock
-import org.mockito.Mockito.`when`
 import org.mockito.Mockito.never
 import org.mockito.Mockito.reset
 import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
 import org.mockito.MockitoAnnotations
-import java.util.concurrent.Executor
 
 private const val KEY = "TEST_KEY"
 private const val KEY_ALT = "TEST_KEY_2"
@@ -433,7 +433,7 @@
         val dataCurrentAndActive = dataCurrent.copy(active = true)
         verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY), eq(dataCurrentAndActive), eq(true),
                 eq(100), eq(true))
-        assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isFalse()
+        assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isTrue()
         // Smartspace update shouldn't be propagated for the empty rec list.
         verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean())
         verify(logger, never()).logRecommendationAdded(any(), any())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
index d414660..2aab9e8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
@@ -43,7 +43,6 @@
 import androidx.core.graphics.drawable.IconCompat;
 import androidx.test.filters.SmallTest;
 
-import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
 import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
@@ -54,7 +53,7 @@
 import com.android.systemui.broadcast.BroadcastSender;
 import com.android.systemui.media.nearby.NearbyMediaDevicesManager;
 import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -83,8 +82,7 @@
             LocalBluetoothLeBroadcast.class);
     private ActivityStarter mStarter = mock(ActivityStarter.class);
     private BroadcastSender mBroadcastSender = mock(BroadcastSender.class);
-    private NotificationEntryManager mNotificationEntryManager =
-            mock(NotificationEntryManager.class);
+    private final CommonNotifCollection mNotifCollection = mock(CommonNotifCollection.class);
     private NearbyMediaDevicesManager mNearbyMediaDevicesManager = mock(
             NearbyMediaDevicesManager.class);
     private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
@@ -120,7 +118,7 @@
 
         mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE,
                 mMediaSessionManager, mLocalBluetoothManager, mStarter,
-                mNotificationEntryManager, mDialogLaunchAnimator,
+                mNotifCollection, mDialogLaunchAnimator,
                 Optional.of(mNearbyMediaDevicesManager), mAudioManager, mPowerExemptionManager);
         mMediaOutputBaseDialogImpl = new MediaOutputBaseDialogImpl(mContext, mBroadcastSender,
                 mMediaOutputController);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
index 6afed1a..4779d32 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
@@ -47,7 +47,7 @@
 import com.android.systemui.broadcast.BroadcastSender;
 import com.android.systemui.media.nearby.NearbyMediaDevicesManager;
 import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
 
 import org.junit.After;
 import org.junit.Before;
@@ -78,8 +78,7 @@
     private final BroadcastSender mBroadcastSender = mock(BroadcastSender.class);
     private final LocalMediaManager mLocalMediaManager = mock(LocalMediaManager.class);
     private final MediaDevice mMediaDevice = mock(MediaDevice.class);
-    private final NotificationEntryManager mNotificationEntryManager =
-            mock(NotificationEntryManager.class);
+    private final CommonNotifCollection mNotifCollection = mock(CommonNotifCollection.class);
     private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
     private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
     private final NearbyMediaDevicesManager mNearbyMediaDevicesManager = mock(
@@ -104,7 +103,7 @@
 
         mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE,
                 mMediaSessionManager, mLocalBluetoothManager, mStarter,
-                mNotificationEntryManager, mDialogLaunchAnimator,
+                mNotifCollection, mDialogLaunchAnimator,
                 Optional.of(mNearbyMediaDevicesManager), mAudioManager, mPowerExemptionManager);
         mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
         mMediaOutputDialog = new MediaOutputDialog(mContext, false, mBroadcastSender,
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 dbc5f7c..171d893 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
@@ -241,5 +241,5 @@
 
 private val routeInfo = MediaRoute2Info.Builder("id", "Test route name")
     .addFeature("feature")
-    .setPackageName(PACKAGE_NAME)
+    .setClientPackageName(PACKAGE_NAME)
     .build()
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 cd8ee73..1061e3c 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
@@ -686,5 +686,5 @@
 
 private val routeInfo = MediaRoute2Info.Builder("id", OTHER_DEVICE_NAME)
     .addFeature("feature")
-    .setPackageName(PACKAGE_NAME)
+    .setClientPackageName(PACKAGE_NAME)
     .build()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java
index fba1986..bd913ba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java
@@ -63,7 +63,6 @@
 import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
 import com.android.systemui.people.widget.PeopleTileKey;
 import com.android.systemui.statusbar.NotificationListener;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 
@@ -196,8 +195,6 @@
     @Mock
     private PackageManager mPackageManager;
     @Mock
-    private NotificationEntryManager mNotificationEntryManager;
-    @Mock
     private PeopleSpaceWidgetManager mPeopleSpaceWidgetManager;
     @Mock
     private BackupManager mBackupManager;
@@ -234,8 +231,6 @@
         when(mMockContext.getString(R.string.over_two_weeks_timestamp)).thenReturn(
                 mContext.getString(R.string.over_two_weeks_timestamp));
         when(mPackageManager.getApplicationIcon(anyString())).thenReturn(null);
-        when(mNotificationEntryManager.getVisibleNotifications())
-                .thenReturn(List.of(mNotificationEntry1, mNotificationEntry2, mNotificationEntry3));
     }
 
     @After
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt
index 642e29b..2ba8782 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt
@@ -22,13 +22,17 @@
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.statusbar.phone.MultiUserSwitchController
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.statusbar.policy.FakeConfigurationController
 import com.android.systemui.statusbar.policy.UserInfoController
 import com.android.systemui.util.mockito.capture
 import com.android.systemui.util.settings.FakeSettings
 import com.android.systemui.utils.leaks.LeakCheckedTest
+import com.google.common.truth.Expect
 import com.google.common.truth.Truth.assertThat
+import javax.inject.Provider
 import org.junit.After
 import org.junit.Before
+import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.ArgumentCaptor
@@ -42,47 +46,38 @@
 import org.mockito.Mockito.never
 import org.mockito.Mockito.reset
 import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
-import javax.inject.Provider
 import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
 
 @SmallTest
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
 @RunWith(AndroidTestingRunner::class)
 class FooterActionsControllerTest : LeakCheckedTest() {
-    @Mock
-    private lateinit var userManager: UserManager
-    @Mock
-    private lateinit var userTracker: UserTracker
-    @Mock
-    private lateinit var activityStarter: ActivityStarter
-    @Mock
-    private lateinit var deviceProvisionedController: DeviceProvisionedController
-    @Mock
-    private lateinit var userInfoController: UserInfoController
-    @Mock
-    private lateinit var multiUserSwitchControllerFactory: MultiUserSwitchController.Factory
-    @Mock
-    private lateinit var multiUserSwitchController: MultiUserSwitchController
-    @Mock
-    private lateinit var globalActionsDialogProvider: Provider<GlobalActionsDialogLite>
-    @Mock
-    private lateinit var globalActionsDialog: GlobalActionsDialogLite
-    @Mock
-    private lateinit var uiEventLogger: UiEventLogger
-    @Mock
-    private lateinit var securityFooterController: QSSecurityFooter
-    @Mock
-    private lateinit var fgsManagerController: QSFgsManagerFooter
+
+    @get:Rule var expect: Expect = Expect.create()
+
+    @Mock private lateinit var userManager: UserManager
+    @Mock private lateinit var userTracker: UserTracker
+    @Mock private lateinit var activityStarter: ActivityStarter
+    @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController
+    @Mock private lateinit var userInfoController: UserInfoController
+    @Mock private lateinit var multiUserSwitchControllerFactory: MultiUserSwitchController.Factory
+    @Mock private lateinit var multiUserSwitchController: MultiUserSwitchController
+    @Mock private lateinit var globalActionsDialogProvider: Provider<GlobalActionsDialogLite>
+    @Mock private lateinit var globalActionsDialog: GlobalActionsDialogLite
+    @Mock private lateinit var uiEventLogger: UiEventLogger
+    @Mock private lateinit var securityFooterController: QSSecurityFooter
+    @Mock private lateinit var fgsManagerController: QSFgsManagerFooter
     @Captor
     private lateinit var visibilityChangedCaptor:
         ArgumentCaptor<VisibilityChangedDispatcher.OnVisibilityChangedListener>
 
     private lateinit var controller: FooterActionsController
 
+    private val configurationController = FakeConfigurationController()
     private val metricsLogger: MetricsLogger = FakeMetricsLogger()
-    private lateinit var view: FooterActionsView
     private val falsingManager: FalsingManagerFake = FalsingManagerFake()
+    private lateinit var view: FooterActionsView
     private lateinit var testableLooper: TestableLooper
     private lateinit var fakeSettings: FakeSettings
     private lateinit var securityFooter: View
@@ -90,12 +85,15 @@
 
     @Before
     fun setUp() {
+        // We want to make sure testable resources are always used
+        context.ensureTestableResources()
+
         MockitoAnnotations.initMocks(this)
         testableLooper = TestableLooper.get(this)
         fakeSettings = FakeSettings()
 
         whenever(multiUserSwitchControllerFactory.create(any()))
-                .thenReturn(multiUserSwitchController)
+            .thenReturn(multiUserSwitchController)
         whenever(globalActionsDialogProvider.get()).thenReturn(globalActionsDialog)
 
         securityFooter = View(mContext)
@@ -135,7 +133,7 @@
         view.findViewById<View>(R.id.pm_lite).performClick()
         // Verify clicks are logged
         verify(uiEventLogger, Mockito.times(1))
-                .log(GlobalActionsDialogLite.GlobalActionsEvent.GA_OPEN_QS)
+            .log(GlobalActionsDialogLite.GlobalActionsEvent.GA_OPEN_QS)
     }
 
     @Test
@@ -299,6 +297,86 @@
         assertThat(booleanCaptor.allValues.last()).isTrue()
     }
 
+    @Test
+    fun setExpansion_inSplitShade_alphaFollowsExpansion() {
+        enableSplitShade()
+
+        controller.setExpansion(0f)
+        expect.that(view.alpha).isEqualTo(0f)
+
+        controller.setExpansion(0.25f)
+        expect.that(view.alpha).isEqualTo(0.25f)
+
+        controller.setExpansion(0.5f)
+        expect.that(view.alpha).isEqualTo(0.5f)
+
+        controller.setExpansion(0.75f)
+        expect.that(view.alpha).isEqualTo(0.75f)
+
+        controller.setExpansion(1f)
+        expect.that(view.alpha).isEqualTo(1f)
+    }
+
+    @Test
+    fun setExpansion_inSplitShade_backgroundAlphaFollowsExpansion_with_0_9_delay() {
+        enableSplitShade()
+
+        controller.setExpansion(0f)
+        expect.that(view.backgroundAlphaFraction).isEqualTo(0f)
+
+        controller.setExpansion(0.5f)
+        expect.that(view.backgroundAlphaFraction).isEqualTo(0f)
+
+        controller.setExpansion(0.9f)
+        expect.that(view.backgroundAlphaFraction).isEqualTo(0f)
+
+        controller.setExpansion(0.91f)
+        expect.that(view.backgroundAlphaFraction).isWithin(FLOAT_TOLERANCE).of(0.1f)
+
+        controller.setExpansion(0.95f)
+        expect.that(view.backgroundAlphaFraction).isWithin(FLOAT_TOLERANCE).of(0.5f)
+
+        controller.setExpansion(1f)
+        expect.that(view.backgroundAlphaFraction).isEqualTo(1f)
+    }
+
+    @Test
+    fun setExpansion_inSingleShade_alphaFollowsExpansion_with_0_9_delay() {
+        disableSplitShade()
+
+        controller.setExpansion(0f)
+        expect.that(view.alpha).isEqualTo(0f)
+
+        controller.setExpansion(0.5f)
+        expect.that(view.alpha).isEqualTo(0f)
+
+        controller.setExpansion(0.9f)
+        expect.that(view.alpha).isEqualTo(0f)
+
+        controller.setExpansion(0.91f)
+        expect.that(view.alpha).isWithin(FLOAT_TOLERANCE).of(0.1f)
+
+        controller.setExpansion(0.95f)
+        expect.that(view.alpha).isWithin(FLOAT_TOLERANCE).of(0.5f)
+
+        controller.setExpansion(1f)
+        expect.that(view.alpha).isEqualTo(1f)
+    }
+
+    @Test
+    fun setExpansion_inSingleShade_backgroundAlphaAlways1() {
+        disableSplitShade()
+
+        controller.setExpansion(0f)
+        expect.that(view.backgroundAlphaFraction).isEqualTo(1f)
+
+        controller.setExpansion(0.5f)
+        expect.that(view.backgroundAlphaFraction).isEqualTo(1f)
+
+        controller.setExpansion(1f)
+        expect.that(view.backgroundAlphaFraction).isEqualTo(1f)
+    }
+
     private fun setVisibilities(
         securityFooterVisible: Boolean,
         fgsFooterVisible: Boolean,
@@ -311,15 +389,52 @@
     }
 
     private fun inflateView(): FooterActionsView {
-        return LayoutInflater.from(context)
-                .inflate(R.layout.footer_actions, null) as FooterActionsView
+        return LayoutInflater.from(context).inflate(R.layout.footer_actions, null)
+            as FooterActionsView
     }
 
     private fun constructFooterActionsController(view: FooterActionsView): FooterActionsController {
-        return FooterActionsController(view, multiUserSwitchControllerFactory,
-                activityStarter, userManager, userTracker, userInfoController,
-                deviceProvisionedController, securityFooterController, fgsManagerController,
-                falsingManager, metricsLogger, globalActionsDialogProvider, uiEventLogger,
-                showPMLiteButton = true, fakeSettings, Handler(testableLooper.looper))
+        return FooterActionsController(
+            view,
+            multiUserSwitchControllerFactory,
+            activityStarter,
+            userManager,
+            userTracker,
+            userInfoController,
+            deviceProvisionedController,
+            securityFooterController,
+            fgsManagerController,
+            falsingManager,
+            metricsLogger,
+            globalActionsDialogProvider,
+            uiEventLogger,
+            showPMLiteButton = true,
+            fakeSettings,
+            Handler(testableLooper.looper),
+            configurationController)
     }
-}
\ No newline at end of file
+
+    private fun enableSplitShade() {
+        setSplitShadeEnabled(true)
+    }
+
+    private fun disableSplitShade() {
+        setSplitShadeEnabled(false)
+    }
+
+    private fun setSplitShadeEnabled(enabled: Boolean) {
+        overrideResource(R.bool.config_use_split_notification_shade, enabled)
+        configurationController.notifyConfigurationChanged()
+    }
+}
+
+private const val FLOAT_TOLERANCE = 0.01f
+
+private val View.backgroundAlphaFraction: Float?
+    get() {
+        return if (background != null) {
+            background.alpha / 255f
+        } else {
+            null
+        }
+    }
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 32c66d2..10f6ce8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -205,6 +205,40 @@
     }
 
     @Test
+    public void setQsExpansion_inSplitShade_setsFooterActionsExpansion_basedOnPanelExpFraction() {
+        // Random test values without any meaning. They just have to be different from each other.
+        float expansion = 0.123f;
+        float panelExpansionFraction = 0.321f;
+        float proposedTranslation = 456f;
+        float squishinessFraction = 0.987f;
+
+        QSFragment fragment = resumeAndGetFragment();
+        enableSplitShade();
+
+        fragment.setQsExpansion(expansion, panelExpansionFraction, proposedTranslation,
+                squishinessFraction);
+
+        verify(mQSFooterActionController).setExpansion(panelExpansionFraction);
+    }
+
+    @Test
+    public void setQsExpansion_notInSplitShade_setsFooterActionsExpansion_basedOnExpansion() {
+        // Random test values without any meaning. They just have to be different from each other.
+        float expansion = 0.123f;
+        float panelExpansionFraction = 0.321f;
+        float proposedTranslation = 456f;
+        float squishinessFraction = 0.987f;
+
+        QSFragment fragment = resumeAndGetFragment();
+        disableSplitShade();
+
+        fragment.setQsExpansion(expansion, panelExpansionFraction, proposedTranslation,
+                squishinessFraction);
+
+        verify(mQSFooterActionController).setExpansion(expansion);
+    }
+
+    @Test
     public void getQsMinExpansionHeight_notInSplitShade_returnsHeaderHeight() {
         QSFragment fragment = resumeAndGetFragment();
         disableSplitShade();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
index 7dbc561..3c58b6fc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
@@ -22,6 +22,7 @@
 import static junit.framework.Assert.assertTrue;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.Mockito.mock;
@@ -32,11 +33,13 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.SharedPreferences;
 import android.database.ContentObserver;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.UserHandle;
 import android.testing.AndroidTestingRunner;
+import android.util.SparseArray;
 import android.view.View;
 
 import androidx.annotation.Nullable;
@@ -60,12 +63,14 @@
 import com.android.systemui.qs.external.TileServiceRequestController;
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.settings.UserFileManager;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.statusbar.phone.AutoTileManager;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.tuner.TunerService;
+import com.android.systemui.util.FakeSharedPreferences;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.settings.FakeSettings;
 import com.android.systemui.util.settings.SecureSettings;
@@ -76,6 +81,7 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.Answer;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
@@ -130,6 +136,10 @@
     private TileLifecycleManager.Factory mTileLifecycleManagerFactory;
     @Mock
     private TileLifecycleManager mTileLifecycleManager;
+    @Mock
+    private UserFileManager mUserFileManager;
+
+    private SparseArray<SharedPreferences> mSharedPreferencesByUser;
 
     private FakeExecutor mMainExecutor;
 
@@ -140,17 +150,29 @@
         MockitoAnnotations.initMocks(this);
         mMainExecutor = new FakeExecutor(new FakeSystemClock());
 
+        mSharedPreferencesByUser = new SparseArray<>();
+
         when(mTileServiceRequestControllerBuilder.create(any()))
                 .thenReturn(mTileServiceRequestController);
         when(mTileLifecycleManagerFactory.create(any(Intent.class), any(UserHandle.class)))
                 .thenReturn(mTileLifecycleManager);
+        when(mUserFileManager.getSharedPreferences(anyString(), anyInt(), anyInt()))
+                .thenAnswer((Answer<SharedPreferences>) invocation -> {
+                    assertEquals(QSTileHost.TILES, invocation.getArgument(0));
+                    int userId = invocation.getArgument(2);
+                    if (!mSharedPreferencesByUser.contains(userId)) {
+                        mSharedPreferencesByUser.put(userId, new FakeSharedPreferences());
+                    }
+                    return mSharedPreferencesByUser.get(userId);
+                });
 
         mSecureSettings = new FakeSettings();
         saveSetting("");
         mQSTileHost = new TestQSTileHost(mContext, mIconController, mDefaultFactory, mMainExecutor,
                 mPluginManager, mTunerService, mAutoTiles, mDumpManager, mCentralSurfaces,
                 mQSLogger, mUiEventLogger, mUserTracker, mSecureSettings, mCustomTileStatePersister,
-                mTileServiceRequestControllerBuilder, mTileLifecycleManagerFactory);
+                mTileServiceRequestControllerBuilder, mTileLifecycleManagerFactory,
+                mUserFileManager);
 
         mSecureSettings.registerContentObserverForUser(SETTING, new ContentObserver(null) {
             @Override
@@ -528,6 +550,118 @@
         assertEquals("spec1", getSetting());
     }
 
+    @Test
+    public void testIsTileAdded_true() {
+        int user = mUserTracker.getUserId();
+        getSharedPreferenecesForUser(user)
+                .edit()
+                .putBoolean(CUSTOM_TILE.flattenToString(), true)
+                .apply();
+
+        assertTrue(mQSTileHost.isTileAdded(CUSTOM_TILE, user));
+    }
+
+    @Test
+    public void testIsTileAdded_false() {
+        int user = mUserTracker.getUserId();
+        getSharedPreferenecesForUser(user)
+                .edit()
+                .putBoolean(CUSTOM_TILE.flattenToString(), false)
+                .apply();
+
+        assertFalse(mQSTileHost.isTileAdded(CUSTOM_TILE, user));
+    }
+
+    @Test
+    public void testIsTileAdded_notSet() {
+        int user = mUserTracker.getUserId();
+
+        assertFalse(mQSTileHost.isTileAdded(CUSTOM_TILE, user));
+    }
+
+    @Test
+    public void testIsTileAdded_differentUser() {
+        int user = mUserTracker.getUserId();
+        mUserFileManager.getSharedPreferences(QSTileHost.TILES, 0, user)
+                .edit()
+                .putBoolean(CUSTOM_TILE.flattenToString(), true)
+                .apply();
+
+        assertFalse(mQSTileHost.isTileAdded(CUSTOM_TILE, user + 1));
+    }
+
+    @Test
+    public void testSetTileAdded_true() {
+        int user = mUserTracker.getUserId();
+        mQSTileHost.setTileAdded(CUSTOM_TILE, user, true);
+
+        assertTrue(getSharedPreferenecesForUser(user)
+                .getBoolean(CUSTOM_TILE.flattenToString(), false));
+    }
+
+    @Test
+    public void testSetTileAdded_false() {
+        int user = mUserTracker.getUserId();
+        mQSTileHost.setTileAdded(CUSTOM_TILE, user, false);
+
+        assertFalse(getSharedPreferenecesForUser(user)
+                .getBoolean(CUSTOM_TILE.flattenToString(), false));
+    }
+
+    @Test
+    public void testSetTileAdded_differentUser() {
+        int user = mUserTracker.getUserId();
+        mQSTileHost.setTileAdded(CUSTOM_TILE, user, true);
+
+        assertFalse(getSharedPreferenecesForUser(user + 1)
+                .getBoolean(CUSTOM_TILE.flattenToString(), false));
+    }
+
+    @Test
+    public void testSetTileRemoved_afterCustomTileChangedByUser() {
+        int user = mUserTracker.getUserId();
+        saveSetting(CUSTOM_TILE_SPEC);
+
+        // This will be done by TileServiceManager
+        mQSTileHost.setTileAdded(CUSTOM_TILE, user, true);
+
+        mQSTileHost.changeTilesByUser(mQSTileHost.mTileSpecs, List.of("spec1"));
+        assertFalse(getSharedPreferenecesForUser(user)
+                .getBoolean(CUSTOM_TILE.flattenToString(), false));
+    }
+
+    @Test
+    public void testSetTileRemoved_removedByUser() {
+        int user = mUserTracker.getUserId();
+        saveSetting(CUSTOM_TILE_SPEC);
+
+        // This will be done by TileServiceManager
+        mQSTileHost.setTileAdded(CUSTOM_TILE, user, true);
+
+        mQSTileHost.removeTileByUser(CUSTOM_TILE);
+        mMainExecutor.runAllReady();
+        assertFalse(getSharedPreferenecesForUser(user)
+                .getBoolean(CUSTOM_TILE.flattenToString(), false));
+    }
+
+    @Test
+    public void testSetTileRemoved_removedBySystem() {
+        int user = mUserTracker.getUserId();
+        saveSetting("spec1" + CUSTOM_TILE_SPEC);
+
+        // This will be done by TileServiceManager
+        mQSTileHost.setTileAdded(CUSTOM_TILE, user, true);
+
+        mQSTileHost.removeTile(CUSTOM_TILE_SPEC);
+        mMainExecutor.runAllReady();
+        assertFalse(getSharedPreferenecesForUser(user)
+                .getBoolean(CUSTOM_TILE.flattenToString(), false));
+    }
+
+    private SharedPreferences getSharedPreferenecesForUser(int user) {
+        return mUserFileManager.getSharedPreferences(QSTileHost.TILES, 0, user);
+    }
+
     private class TestQSTileHost extends QSTileHost {
         TestQSTileHost(Context context, StatusBarIconController iconController,
                 QSFactory defaultFactory, Executor mainExecutor,
@@ -537,11 +671,13 @@
                 UserTracker userTracker, SecureSettings secureSettings,
                 CustomTileStatePersister customTileStatePersister,
                 TileServiceRequestController.Builder tileServiceRequestControllerBuilder,
-                TileLifecycleManager.Factory tileLifecycleManagerFactory) {
+                TileLifecycleManager.Factory tileLifecycleManagerFactory,
+                UserFileManager userFileManager) {
             super(context, iconController, defaultFactory, mainExecutor, pluginManager,
                     tunerService, autoTiles, dumpManager, Optional.of(centralSurfaces), qsLogger,
                     uiEventLogger, userTracker, secureSettings, customTileStatePersister,
-                    tileServiceRequestControllerBuilder, tileLifecycleManagerFactory);
+                    tileServiceRequestControllerBuilder, tileLifecycleManagerFactory,
+                    userFileManager);
         }
 
         @Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTest.java
index 573980d..8aa625a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTest.java
@@ -19,6 +19,14 @@
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.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;
@@ -31,6 +39,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.settings.UserTracker;
 
 import org.junit.After;
@@ -38,37 +47,45 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
-import org.mockito.Mockito;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class TileServiceManagerTest extends SysuiTestCase {
 
+    @Mock
     private TileServices mTileServices;
+    @Mock
     private TileLifecycleManager mTileLifecycle;
+    @Mock
+    private UserTracker mUserTracker;
+    @Mock
+    private QSTileHost mQSTileHost;
+    @Mock
+    private Context mMockContext;
+
     private HandlerThread mThread;
     private Handler mHandler;
     private TileServiceManager mTileServiceManager;
-    private UserTracker mUserTracker;
-    private Context mMockContext;
+    private ComponentName mComponentName;
 
     @Before
     public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
         mThread = new HandlerThread("TestThread");
         mThread.start();
         mHandler = Handler.createAsync(mThread.getLooper());
-        mTileServices = Mockito.mock(TileServices.class);
-        mUserTracker = Mockito.mock(UserTracker.class);
-        Mockito.when(mUserTracker.getUserId()).thenReturn(UserHandle.USER_SYSTEM);
-        Mockito.when(mUserTracker.getUserHandle()).thenReturn(UserHandle.SYSTEM);
+        when(mUserTracker.getUserId()).thenReturn(UserHandle.USER_SYSTEM);
+        when(mUserTracker.getUserHandle()).thenReturn(UserHandle.SYSTEM);
 
-        mMockContext = Mockito.mock(Context.class);
-        Mockito.when(mTileServices.getContext()).thenReturn(mMockContext);
-        mTileLifecycle = Mockito.mock(TileLifecycleManager.class);
-        Mockito.when(mTileLifecycle.isActiveTile()).thenReturn(false);
-        ComponentName componentName = new ComponentName(mContext,
-                TileServiceManagerTest.class);
-        Mockito.when(mTileLifecycle.getComponent()).thenReturn(componentName);
+        when(mTileServices.getContext()).thenReturn(mMockContext);
+        when(mTileServices.getHost()).thenReturn(mQSTileHost);
+        when(mTileLifecycle.getUserId()).thenAnswer(invocation -> mUserTracker.getUserId());
+        when(mTileLifecycle.isActiveTile()).thenReturn(false);
+
+        mComponentName = new ComponentName(mContext, TileServiceManagerTest.class);
+        when(mTileLifecycle.getComponent()).thenReturn(mComponentName);
         mTileServiceManager = new TileServiceManager(mTileServices, mHandler, mUserTracker,
                 mTileLifecycle);
     }
@@ -80,17 +97,44 @@
     }
 
     @Test
+    public void testSetTileAddedIfNotAdded() {
+        when(mQSTileHost.isTileAdded(eq(mComponentName), anyInt())).thenReturn(false);
+        mTileServiceManager.startLifecycleManagerAndAddTile();
+
+        verify(mQSTileHost).setTileAdded(mComponentName, mUserTracker.getUserId(), true);
+    }
+
+    @Test
+    public void testNotSetTileAddedIfAdded() {
+        when(mQSTileHost.isTileAdded(eq(mComponentName), anyInt())).thenReturn(true);
+        mTileServiceManager.startLifecycleManagerAndAddTile();
+
+        verify(mQSTileHost, never()).setTileAdded(eq(mComponentName), anyInt(), eq(true));
+    }
+
+    @Test
+    public void testSetTileAddedCorrectUser() {
+        int user = 10;
+        when(mUserTracker.getUserId()).thenReturn(user);
+        when(mQSTileHost.isTileAdded(eq(mComponentName), anyInt())).thenReturn(false);
+        mTileServiceManager.startLifecycleManagerAndAddTile();
+
+        verify(mQSTileHost).setTileAdded(mComponentName, user, true);
+    }
+
+    @Test
     public void testUninstallReceiverExported() {
+        mTileServiceManager.startLifecycleManagerAndAddTile();
         ArgumentCaptor<IntentFilter> intentFilterCaptor =
                 ArgumentCaptor.forClass(IntentFilter.class);
 
-        Mockito.verify(mMockContext).registerReceiverAsUser(
-                Mockito.any(),
-                Mockito.any(),
+        verify(mMockContext).registerReceiverAsUser(
+                any(),
+                any(),
                 intentFilterCaptor.capture(),
-                Mockito.any(),
-                Mockito.any(),
-                Mockito.eq(Context.RECEIVER_EXPORTED)
+                any(),
+                any(),
+                eq(Context.RECEIVER_EXPORTED)
         );
         IntentFilter filter = intentFilterCaptor.getValue();
         assertTrue(filter.hasAction(Intent.ACTION_PACKAGE_REMOVED));
@@ -99,38 +143,41 @@
 
     @Test
     public void testSetBindRequested() {
+        mTileServiceManager.startLifecycleManagerAndAddTile();
         // Request binding.
         mTileServiceManager.setBindRequested(true);
         mTileServiceManager.setLastUpdate(0);
         mTileServiceManager.calculateBindPriority(5);
-        Mockito.verify(mTileServices, Mockito.times(2)).recalculateBindAllowance();
+        verify(mTileServices, times(2)).recalculateBindAllowance();
         assertEquals(5, mTileServiceManager.getBindPriority());
 
         // Verify same state doesn't trigger recalculating for no reason.
         mTileServiceManager.setBindRequested(true);
-        Mockito.verify(mTileServices, Mockito.times(2)).recalculateBindAllowance();
+        verify(mTileServices, times(2)).recalculateBindAllowance();
 
         mTileServiceManager.setBindRequested(false);
         mTileServiceManager.calculateBindPriority(5);
-        Mockito.verify(mTileServices, Mockito.times(3)).recalculateBindAllowance();
+        verify(mTileServices, times(3)).recalculateBindAllowance();
         assertEquals(Integer.MIN_VALUE, mTileServiceManager.getBindPriority());
     }
 
     @Test
     public void testPendingClickPriority() {
-        Mockito.when(mTileLifecycle.hasPendingClick()).thenReturn(true);
+        mTileServiceManager.startLifecycleManagerAndAddTile();
+        when(mTileLifecycle.hasPendingClick()).thenReturn(true);
         mTileServiceManager.calculateBindPriority(0);
         assertEquals(Integer.MAX_VALUE, mTileServiceManager.getBindPriority());
     }
 
     @Test
     public void testBind() {
+        mTileServiceManager.startLifecycleManagerAndAddTile();
         // Trigger binding requested and allowed.
         mTileServiceManager.setBindRequested(true);
         mTileServiceManager.setBindAllowed(true);
 
         ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
-        Mockito.verify(mTileLifecycle, Mockito.times(1)).setBindService(captor.capture());
+        verify(mTileLifecycle, times(1)).setBindService(captor.capture());
         assertTrue((boolean) captor.getValue());
 
         mTileServiceManager.setBindRequested(false);
@@ -141,7 +188,7 @@
 
         mTileServiceManager.setBindAllowed(false);
         captor = ArgumentCaptor.forClass(Boolean.class);
-        Mockito.verify(mTileLifecycle, Mockito.times(2)).setBindService(captor.capture());
+        verify(mTileLifecycle, times(2)).setBindService(captor.capture());
         assertFalse((boolean) captor.getValue());
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
index 471ddfd..213eca8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
@@ -45,6 +45,7 @@
 import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSFactoryImpl;
+import com.android.systemui.settings.UserFileManager;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.statusbar.CommandQueue;
@@ -118,6 +119,8 @@
     private TileLifecycleManager.Factory mTileLifecycleManagerFactory;
     @Mock
     private TileLifecycleManager mTileLifecycleManager;
+    @Mock
+    private UserFileManager mUserFileManager;
 
     @Before
     public void setUp() throws Exception {
@@ -149,7 +152,8 @@
                 mSecureSettings,
                 mock(CustomTileStatePersister.class),
                 mTileServiceRequestControllerBuilder,
-                mTileLifecycleManagerFactory);
+                mTileLifecycleManagerFactory,
+                mUserFileManager);
         mTileService = new TestTileServices(host, provider, mBroadcastDispatcher,
                 mUserTracker, mKeyguardStateController, mCommandQueue);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
index 5336ef0..ba49f3f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
@@ -37,6 +37,7 @@
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Matchers.argThat;
+import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -78,6 +79,7 @@
 import org.mockito.ArgumentCaptor;
 import org.mockito.ArgumentMatcher;
 import org.mockito.Captor;
+import org.mockito.InOrder;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -144,7 +146,25 @@
         when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
 
         mTile.click(null /* view */);
-        verify(mQsLogger).logTileClick(SPEC, StatusBarState.SHADE, Tile.STATE_ACTIVE);
+        verify(mQsLogger).logTileClick(eq(SPEC), eq(StatusBarState.SHADE), eq(Tile.STATE_ACTIVE),
+                anyInt());
+    }
+
+    @Test
+    public void testHandleClick_log() {
+        mTile.click(null);
+        mTile.click(null);
+        mTestableLooper.processAllMessages();
+        mTile.click(null);
+        mTestableLooper.processAllMessages();
+
+        InOrder inOrder = inOrder(mQsLogger);
+        inOrder.verify(mQsLogger).logTileClick(eq(SPEC), anyInt(), anyInt(), eq(0));
+        inOrder.verify(mQsLogger).logTileClick(eq(SPEC), anyInt(), anyInt(), eq(1));
+        inOrder.verify(mQsLogger).logHandleClick(SPEC, 0);
+        inOrder.verify(mQsLogger).logHandleClick(SPEC, 1);
+        inOrder.verify(mQsLogger).logTileClick(eq(SPEC), anyInt(), anyInt(), eq(2));
+        inOrder.verify(mQsLogger).logHandleClick(SPEC, 2);
     }
 
     @Test
@@ -183,7 +203,25 @@
         when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
 
         mTile.secondaryClick(null /* view */);
-        verify(mQsLogger).logTileSecondaryClick(SPEC, StatusBarState.SHADE, Tile.STATE_ACTIVE);
+        verify(mQsLogger).logTileSecondaryClick(eq(SPEC), eq(StatusBarState.SHADE),
+                eq(Tile.STATE_ACTIVE), anyInt());
+    }
+
+    @Test
+    public void testHandleSecondaryClick_log() {
+        mTile.secondaryClick(null);
+        mTile.secondaryClick(null);
+        mTestableLooper.processAllMessages();
+        mTile.secondaryClick(null);
+        mTestableLooper.processAllMessages();
+
+        InOrder inOrder = inOrder(mQsLogger);
+        inOrder.verify(mQsLogger).logTileSecondaryClick(eq(SPEC), anyInt(), anyInt(), eq(0));
+        inOrder.verify(mQsLogger).logTileSecondaryClick(eq(SPEC), anyInt(), anyInt(), eq(1));
+        inOrder.verify(mQsLogger).logHandleSecondaryClick(SPEC, 0);
+        inOrder.verify(mQsLogger).logHandleSecondaryClick(SPEC, 1);
+        inOrder.verify(mQsLogger).logTileSecondaryClick(eq(SPEC), anyInt(), anyInt(), eq(2));
+        inOrder.verify(mQsLogger).logHandleSecondaryClick(SPEC, 2);
     }
 
     @Test
@@ -210,7 +248,25 @@
         when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
 
         mTile.longClick(null /* view */);
-        verify(mQsLogger).logTileLongClick(SPEC, StatusBarState.SHADE, Tile.STATE_ACTIVE);
+        verify(mQsLogger).logTileLongClick(eq(SPEC), eq(StatusBarState.SHADE),
+                eq(Tile.STATE_ACTIVE), anyInt());
+    }
+
+    @Test
+    public void testHandleLongClick_log() {
+        mTile.longClick(null);
+        mTile.longClick(null);
+        mTestableLooper.processAllMessages();
+        mTile.longClick(null);
+        mTestableLooper.processAllMessages();
+
+        InOrder inOrder = inOrder(mQsLogger);
+        inOrder.verify(mQsLogger).logTileLongClick(eq(SPEC), anyInt(), anyInt(), eq(0));
+        inOrder.verify(mQsLogger).logTileLongClick(eq(SPEC), anyInt(), anyInt(), eq(1));
+        inOrder.verify(mQsLogger).logHandleLongClick(SPEC, 0);
+        inOrder.verify(mQsLogger).logHandleLongClick(SPEC, 1);
+        inOrder.verify(mQsLogger).logTileLongClick(eq(SPEC), anyInt(), anyInt(), eq(2));
+        inOrder.verify(mQsLogger).logHandleLongClick(SPEC, 2);
     }
 
     @Test
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 002f23a..024d3bd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt
@@ -23,8 +23,12 @@
 import android.graphics.Rect
 import android.hardware.HardwareBuffer
 import android.net.Uri
-import android.view.WindowManager
-import android.view.WindowManager.ScreenshotSource
+import android.view.WindowManager.ScreenshotSource.SCREENSHOT_KEY_CHORD
+import android.view.WindowManager.ScreenshotSource.SCREENSHOT_OTHER
+import android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN
+import android.view.WindowManager.TAKE_SCREENSHOT_SELECTED_REGION
+import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE
+
 import com.android.internal.util.ScreenshotHelper.HardwareBitmapBundler
 import com.android.internal.util.ScreenshotHelper.ScreenshotRequest
 import com.android.systemui.screenshot.TakeScreenshotService.RequestCallback
@@ -43,13 +47,12 @@
 
     @Test
     fun testFullScreenshot() {
-        val request = ScreenshotRequest(ScreenshotSource.SCREENSHOT_KEY_CHORD)
+        val request = ScreenshotRequest(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD)
         val onSavedListener = mock<Consumer<Uri>>()
         val callback = mock<RequestCallback>()
         val processor = RequestProcessor(controller)
 
-        processor.processRequest(WindowManager.TAKE_SCREENSHOT_FULLSCREEN, onSavedListener,
-            request, callback)
+        processor.processRequest(request, onSavedListener, callback)
 
         verify(controller).takeScreenshotFullscreen(/* topComponent */ isNull(),
             eq(onSavedListener), eq(callback))
@@ -57,13 +60,12 @@
 
     @Test
     fun testSelectedRegionScreenshot() {
-        val request = ScreenshotRequest(ScreenshotSource.SCREENSHOT_KEY_CHORD)
+        val request = ScreenshotRequest(TAKE_SCREENSHOT_SELECTED_REGION, SCREENSHOT_KEY_CHORD)
         val onSavedListener = mock<Consumer<Uri>>()
         val callback = mock<RequestCallback>()
         val processor = RequestProcessor(controller)
 
-        processor.processRequest(WindowManager.TAKE_SCREENSHOT_SELECTED_REGION, onSavedListener,
-            request, callback)
+        processor.processRequest(request, onSavedListener, callback)
 
         verify(controller).takeScreenshotPartial(/* topComponent */ isNull(),
             eq(onSavedListener), eq(callback))
@@ -82,14 +84,13 @@
         val bitmap = Bitmap.wrapHardwareBuffer(buffer, ColorSpace.get(ColorSpace.Named.SRGB))!!
         val bitmapBundle = HardwareBitmapBundler.hardwareBitmapToBundle(bitmap)
 
-        val request = ScreenshotRequest(ScreenshotSource.SCREENSHOT_OTHER, bitmapBundle,
-            bounds, Insets.NONE, taskId, userId, topComponent)
+        val request = ScreenshotRequest(TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_OTHER,
+            bitmapBundle, bounds, Insets.NONE, taskId, userId, topComponent)
 
         val onSavedListener = mock<Consumer<Uri>>()
         val callback = mock<RequestCallback>()
 
-        processor.processRequest(WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE, onSavedListener,
-            request, callback)
+        processor.processRequest(request, onSavedListener, callback)
 
         verify(controller).handleImageAsScreenshot(
             bitmapCaptor.capture(), eq(bounds), eq(Insets.NONE), eq(taskId), eq(userId),
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 fc28349..3f4e2a9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -98,9 +98,7 @@
 import com.android.systemui.fragments.FragmentHostManager;
 import com.android.systemui.fragments.FragmentService;
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
-import com.android.systemui.keyguard.domain.usecase.SetClockPositionUseCase;
-import com.android.systemui.keyguard.domain.usecase.SetKeyguardBottomAreaAlphaUseCase;
-import com.android.systemui.keyguard.domain.usecase.SetKeyguardBottomAreaAnimateDozingTransitionsUseCase;
+import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor;
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel;
 import com.android.systemui.media.KeyguardMediaController;
 import com.android.systemui.media.MediaDataManager;
@@ -379,10 +377,7 @@
     @Mock
     private ViewTreeObserver mViewTreeObserver;
     @Mock private KeyguardBottomAreaViewModel mKeyguardBottomAreaViewModel;
-    @Mock private SetClockPositionUseCase mSetClockPositionUseCase;
-    @Mock private SetKeyguardBottomAreaAlphaUseCase mSetKeyguardBottomAreaAlphaUseCase;
-    @Mock private SetKeyguardBottomAreaAnimateDozingTransitionsUseCase
-            mSetKeyguardBottomAreaAnimateDozingTransitionsUseCase;
+    @Mock private KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor;
     private NotificationPanelViewController.PanelEventsEmitter mPanelEventsEmitter;
     private Optional<SysUIUnfoldComponent> mSysUIUnfoldComponent = Optional.empty();
     private SysuiStatusBarStateController mStatusBarStateController;
@@ -577,9 +572,7 @@
                 mSystemClock,
                 mock(CameraGestureHelper.class),
                 () -> mKeyguardBottomAreaViewModel,
-                () -> mSetClockPositionUseCase,
-                () -> mSetKeyguardBottomAreaAlphaUseCase,
-                () -> mSetKeyguardBottomAreaAnimateDozingTransitionsUseCase);
+                () -> mKeyguardBottomAreaInteractor);
         mNotificationPanelViewController.initDependencies(
                 mCentralSurfaces,
                 () -> {},
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/system/RemoteTransitionTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/system/RemoteTransitionTest.java
index 360eef9..cf5fa87 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/system/RemoteTransitionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/system/RemoteTransitionTest.java
@@ -19,12 +19,14 @@
 import static android.view.WindowManager.TRANSIT_CHANGE;
 import static android.view.WindowManager.TRANSIT_CLOSE;
 import static android.view.WindowManager.TRANSIT_OPEN;
+import static android.window.TransitionInfo.FLAG_FIRST_CUSTOM;
 import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
 import static android.window.TransitionInfo.FLAG_SHOW_WALLPAPER;
 import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;
+import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_STANDARD;
 import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CHANGING;
 import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
 import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
@@ -64,12 +66,15 @@
     @Test
     public void testLegacyTargetExtract() {
         TransitionInfo combined = new TransitionInfoBuilder(TRANSIT_CLOSE)
-                .addChange(TRANSIT_CHANGE, FLAG_SHOW_WALLPAPER)
-                .addChange(TRANSIT_CLOSE, 0 /* flags */)
-                .addChange(TRANSIT_OPEN, FLAG_IS_WALLPAPER).build();
-        // Check non-wallpaper extraction
-        RemoteAnimationTargetCompat[] wrapped = RemoteAnimationTargetCompat.wrap(combined,
-                false /* wallpapers */, mock(SurfaceControl.Transaction.class), null /* leashes */);
+                .addChange(TRANSIT_CHANGE, FLAG_SHOW_WALLPAPER,
+                        createTaskInfo(1 /* taskId */, ACTIVITY_TYPE_STANDARD))
+                .addChange(TRANSIT_CLOSE, 0 /* flags */,
+                        createTaskInfo(2 /* taskId */, ACTIVITY_TYPE_STANDARD))
+                .addChange(TRANSIT_OPEN, FLAG_IS_WALLPAPER, null /* taskInfo */)
+                .addChange(TRANSIT_CHANGE, FLAG_FIRST_CUSTOM, null /* taskInfo */).build();
+        // Check apps extraction
+        RemoteAnimationTargetCompat[] wrapped = RemoteAnimationTargetCompat.wrapApps(combined,
+                mock(SurfaceControl.Transaction.class), null /* leashes */);
         assertEquals(2, wrapped.length);
         int changeLayer = -1;
         int closeLayer = -1;
@@ -86,17 +91,25 @@
         assertTrue(closeLayer < changeLayer);
 
         // Check wallpaper extraction
-        RemoteAnimationTargetCompat[] wallps = RemoteAnimationTargetCompat.wrap(combined,
+        RemoteAnimationTargetCompat[] wallps = RemoteAnimationTargetCompat.wrapNonApps(combined,
                 true /* wallpapers */, mock(SurfaceControl.Transaction.class), null /* leashes */);
         assertEquals(1, wallps.length);
         assertTrue(wallps[0].prefixOrderIndex < closeLayer);
         assertEquals(MODE_OPENING, wallps[0].mode);
+
+        // Check non-apps extraction
+        RemoteAnimationTargetCompat[] nonApps = RemoteAnimationTargetCompat.wrapNonApps(combined,
+                false /* wallpapers */, mock(SurfaceControl.Transaction.class), null /* leashes */);
+        assertEquals(1, nonApps.length);
+        assertTrue(nonApps[0].prefixOrderIndex < closeLayer);
+        assertEquals(MODE_CHANGING, nonApps[0].mode);
     }
 
     @Test
     public void testLegacyTargetWrapper() {
         TransitionInfo tinfo = new TransitionInfoBuilder(TRANSIT_CLOSE)
-                .addChange(TRANSIT_CHANGE, FLAG_TRANSLUCENT).build();
+                .addChange(TRANSIT_CHANGE, FLAG_TRANSLUCENT,
+                        createTaskInfo(1 /* taskId */, ACTIVITY_TYPE_STANDARD)).build();
         final TransitionInfo.Change change = tinfo.getChanges().get(0);
         final Rect endBounds = new Rect(40, 60, 140, 200);
         change.setTaskInfo(createTaskInfo(1 /* taskId */, ACTIVITY_TYPE_HOME));
@@ -119,11 +132,12 @@
         }
 
         TransitionInfoBuilder addChange(@WindowManager.TransitionType int mode,
-                @TransitionInfo.ChangeFlags int flags) {
+                @TransitionInfo.ChangeFlags int flags, ActivityManager.RunningTaskInfo taskInfo) {
             final TransitionInfo.Change change =
                     new TransitionInfo.Change(null /* token */, createMockSurface(true));
             change.setMode(mode);
             change.setFlags(flags);
+            change.setTaskInfo(taskInfo);
             mInfo.addChange(change);
             return this;
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
index 8a38847..98de176 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
@@ -25,7 +25,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
 
 import android.app.ActivityManager;
 import android.app.Notification;
@@ -218,41 +217,4 @@
         // The entry has just been added so we should not remove immediately.
         assertFalse(mAlertingNotificationManager.canRemoveImmediately(mEntry.getKey()));
     }
-
-    @Test
-    public void testShouldExtendLifetime() {
-        mAlertingNotificationManager.showNotification(mEntry);
-
-        // While the entry is alerting, it should not be removable.
-        assertTrue(mAlertingNotificationManager.shouldExtendLifetime(mEntry));
-    }
-
-    @Test
-    public void testSetShouldManageLifetime_setShouldManage() {
-        mAlertingNotificationManager.showNotification(mEntry);
-
-        mAlertingNotificationManager.setShouldManageLifetime(mEntry, true /* shouldManage */);
-
-        assertTrue(mAlertingNotificationManager.mExtendedLifetimeAlertEntries.contains(mEntry));
-    }
-
-    @Test
-    public void testSetShouldManageLifetime_setShouldManageCallsRemoval() {
-        mAlertingNotificationManager.showNotification(mEntry);
-        mAlertingNotificationManager.setShouldManageLifetime(mEntry, true /* shouldManage */);
-        if (mAlertingNotificationManager instanceof TestableAlertingNotificationManager) {
-            TestableAlertingNotificationManager testableManager =
-                    (TestableAlertingNotificationManager) mAlertingNotificationManager;
-            verify(testableManager.mLastCreatedEntry).removeAsSoonAsPossible();
-        }
-    }
-
-    @Test
-    public void testSetShouldManageLifetime_setShouldNotManage() {
-        mAlertingNotificationManager.mExtendedLifetimeAlertEntries.add(mEntry);
-
-        mAlertingNotificationManager.setShouldManageLifetime(mEntry, false /* shouldManage */);
-
-        assertFalse(mAlertingNotificationManager.mExtendedLifetimeAlertEntries.contains(mEntry));
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index 9c25462..8473c37 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -23,6 +23,7 @@
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_ALIGNMENT;
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BATTERY;
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BIOMETRIC_MESSAGE;
+import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP;
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_DISCLOSURE;
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_LOGOUT;
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_OWNER_INFO;
@@ -50,7 +51,6 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.app.IActivityManager;
 import android.app.Instrumentation;
 import android.app.admin.DevicePolicyManager;
 import android.app.admin.DevicePolicyResourcesManager;
@@ -161,8 +161,6 @@
     @Mock
     private LockPatternUtils mLockPatternUtils;
     @Mock
-    private IActivityManager mIActivityManager;
-    @Mock
     private KeyguardBypassController mKeyguardBypassController;
     @Mock
     private AccessibilityManager mAccessibilityManager;
@@ -256,8 +254,7 @@
                 mKeyguardStateController, mStatusBarStateController, mKeyguardUpdateMonitor,
                 mDockManager, mBroadcastDispatcher, mDevicePolicyManager, mIBatteryStats,
                 mUserManager, mExecutor, mExecutor,  mFalsingManager, mLockPatternUtils,
-                mScreenLifecycle, mIActivityManager, mKeyguardBypassController,
-                mAccessibilityManager);
+                mScreenLifecycle, mKeyguardBypassController, mAccessibilityManager);
         mController.init();
         mController.setIndicationArea(mIndicationArea);
         verify(mStatusBarStateController).addCallback(mStatusBarStateListenerCaptor.capture());
@@ -971,11 +968,11 @@
         mController.getKeyguardCallback().onBiometricAuthenticated(0,
                 BiometricSourceType.FACE, false);
 
-        // THEN 'face unlocked. press unlock icon to open' message shows
-        String pressToOpen = mContext.getString(R.string.keyguard_face_successful_unlock_press);
-        verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, pressToOpen);
-
-        assertThat(mTextView.getText()).isNotEqualTo(pressToOpen);
+        // THEN 'face unlocked' then 'press unlock icon to open' message show
+        String unlockedByFace = mContext.getString(R.string.keyguard_face_successful_unlock);
+        verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, unlockedByFace);
+        String pressToOpen = mContext.getString(R.string.keyguard_unlock_press);
+        verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP, pressToOpen);
     }
 
 
@@ -996,10 +993,11 @@
         mController.getKeyguardCallback().onBiometricAuthenticated(0,
                 BiometricSourceType.FACE, false);
 
-        // THEN show 'face unlocked. swipe up to open' message
-        String faceUnlockedSwipeToOpen =
-                mContext.getString(R.string.keyguard_face_successful_unlock_swipe);
-        verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, faceUnlockedSwipeToOpen);
+        // THEN show 'face unlocked' and 'swipe up to open' messages
+        String unlockedByFace = mContext.getString(R.string.keyguard_face_successful_unlock);
+        verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, unlockedByFace);
+        String swipeUpToOpen = mContext.getString(R.string.keyguard_unlock);
+        verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP, swipeUpToOpen);
     }
 
     @Test
@@ -1018,10 +1016,11 @@
         mController.getKeyguardCallback().onBiometricAuthenticated(0,
                 BiometricSourceType.FACE, false);
 
-        // THEN show 'swipe up to open' message
-        String faceUnlockedSwipeToOpen =
-                mContext.getString(R.string.keyguard_face_successful_unlock_swipe);
-        verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, faceUnlockedSwipeToOpen);
+        // THEN show 'face unlocked' and 'swipe up to open' messages
+        String unlockedByFace = mContext.getString(R.string.keyguard_face_successful_unlock);
+        verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, unlockedByFace);
+        String swipeUpToOpen = mContext.getString(R.string.keyguard_unlock);
+        verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP, swipeUpToOpen);
     }
 
     @Test
@@ -1039,10 +1038,11 @@
         mController.getKeyguardCallback().onBiometricAuthenticated(0,
                 BiometricSourceType.FACE, false);
 
-        // THEN show 'swipe up to open' message
-        String faceUnlockedSwipeToOpen =
-                mContext.getString(R.string.keyguard_face_successful_unlock_swipe);
-        verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, faceUnlockedSwipeToOpen);
+        // THEN show 'face unlocked' and 'swipe up to open' messages
+        String unlockedByFace = mContext.getString(R.string.keyguard_face_successful_unlock);
+        verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, unlockedByFace);
+        String swipeUpToOpen = mContext.getString(R.string.keyguard_unlock);
+        verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP, swipeUpToOpen);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
index 34d13c7..6e29669 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
@@ -161,10 +161,8 @@
                     smartReplyController,
                     visibilityProvider,
                     notificationEntryManager,
-                    rebuilder,
                     centralSurfacesOptionalLazy,
                     statusBarStateController,
-                    mainHandler,
                     remoteInputUriController,
                     clickNotifier,
                     actionClickLogger,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
deleted file mode 100644
index 842f057..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ /dev/null
@@ -1,684 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar.notification;
-
-import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
-import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
-import static android.service.notification.NotificationListenerService.REASON_CANCEL;
-import static android.service.notification.NotificationStats.DISMISSAL_SHADE;
-import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
-
-import static com.android.systemui.statusbar.notification.NotificationEntryManager.UNDEFINED_DISMISS_REASON;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertNull;
-import static junit.framework.Assert.assertTrue;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.app.ActivityManager;
-import android.app.Notification;
-import android.app.NotificationChannel;
-import android.app.PendingIntent;
-import android.content.Intent;
-import android.graphics.drawable.Icon;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.service.notification.NotificationListenerService.Ranking;
-import android.service.notification.NotificationListenerService.RankingMap;
-import android.service.notification.StatusBarNotification;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.util.ArraySet;
-
-import androidx.annotation.NonNull;
-import androidx.test.filters.SmallTest;
-
-import com.android.internal.statusbar.IStatusBarService;
-import com.android.internal.statusbar.NotificationVisibility;
-import com.android.systemui.Dependency;
-import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.statusbar.NotificationLifetimeExtender;
-import com.android.systemui.statusbar.NotificationListener;
-import com.android.systemui.statusbar.NotificationMediaManager;
-import com.android.systemui.statusbar.NotificationPresenter;
-import com.android.systemui.statusbar.NotificationRemoteInputManager;
-import com.android.systemui.statusbar.NotificationRemoveInterceptor;
-import com.android.systemui.statusbar.SmartReplyController;
-import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
-import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
-import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
-import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
-import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
-import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
-import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.row.RowInflaterTask;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.util.concurrency.FakeExecutor;
-import com.android.systemui.util.leak.LeakDetector;
-import com.android.systemui.util.time.FakeSystemClock;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.ArgumentMatcher;
-import org.mockito.InOrder;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Unit tests for {@link NotificationEntryManager}.
- */
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper()
-public class NotificationEntryManagerTest extends SysuiTestCase {
-    private static final String TEST_PACKAGE_NAME = "test";
-    private static final int TEST_UID = 0;
-
-    @Mock private NotificationPresenter mPresenter;
-    @Mock private KeyguardEnvironment mEnvironment;
-    @Mock private ExpandableNotificationRow mRow;
-    @Mock private NotificationEntryListener mEntryListener;
-    @Mock private NotifCollectionListener mNotifCollectionListener;
-    @Mock private NotificationRemoveInterceptor mRemoveInterceptor;
-    @Mock private HeadsUpManager mHeadsUpManager;
-    @Mock private RankingMap mRankingMap;
-    @Mock private NotificationGroupManagerLegacy mGroupManager;
-    @Mock private NotificationRemoteInputManager mRemoteInputManager;
-    @Mock private DeviceProvisionedController mDeviceProvisionedController;
-    @Mock private RowInflaterTask mAsyncInflationTask;
-    @Mock private NotificationEntryManagerLogger mLogger;
-    @Mock private NotifPipelineFlags mNotifPipelineFlags;
-    @Mock private LeakDetector mLeakDetector;
-    @Mock private NotificationMediaManager mNotificationMediaManager;
-    @Mock private NotificationRowBinder mNotificationRowBinder;
-    @Mock private NotificationListener mNotificationListener;
-    @Mock private IStatusBarService mStatusBarService;
-
-    private FakeSystemClock mFakeSystemClock = new FakeSystemClock();
-    private FakeExecutor mBgExecutor = new FakeExecutor(mFakeSystemClock);
-
-    private int mId;
-    private NotificationEntry mEntry;
-    private DismissedByUserStats mStats;
-    private StatusBarNotification mSbn;
-    private NotificationEntryManager mEntryManager;
-
-    private void setUserSentiment(String key, int sentiment) {
-        doAnswer(invocationOnMock -> {
-            Ranking ranking = (Ranking)
-                    invocationOnMock.getArguments()[1];
-            ranking.populate(
-                    key,
-                    0,
-                    false,
-                    0,
-                    0,
-                    IMPORTANCE_DEFAULT,
-                    null, null,
-                    null, null, null, true, sentiment, false, -1, false, null, null, false, false,
-                    false, null, 0, false);
-            return true;
-        }).when(mRankingMap).getRanking(eq(key), any(Ranking.class));
-    }
-
-    private void setSmartActions(String key, ArrayList<Notification.Action> smartActions) {
-        doAnswer(invocationOnMock -> {
-            Ranking ranking = (Ranking)
-                    invocationOnMock.getArguments()[1];
-            ranking.populate(
-                    key,
-                    0,
-                    false,
-                    0,
-                    0,
-                    IMPORTANCE_DEFAULT,
-                    null, null,
-                    null, null, null, true,
-                    Ranking.USER_SENTIMENT_NEUTRAL, false, -1,
-                    false, smartActions, null, false, false, false, null, 0, false);
-            return true;
-        }).when(mRankingMap).getRanking(eq(key), any(Ranking.class));
-    }
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mDependency.injectMockDependency(SmartReplyController.class);
-
-        allowTestableLooperAsMainThread();
-        mDependency.injectTestDependency(Dependency.MAIN_HANDLER,
-                Handler.createAsync(TestableLooper.get(this).getLooper()));
-
-        mEntry = createNotification();
-        mStats = defaultStats(mEntry);
-        mSbn = mEntry.getSbn();
-
-        mEntryManager = new NotificationEntryManager(
-                mLogger,
-                mGroupManager,
-                mNotifPipelineFlags,
-                () -> mNotificationRowBinder,
-                () -> mRemoteInputManager,
-                mLeakDetector,
-                mStatusBarService,
-                mock(DumpManager.class),
-                mBgExecutor
-        );
-        mEntryManager.initialize(
-                mNotificationListener,
-                new NotificationRankingManager(
-                        () -> mNotificationMediaManager,
-                        mGroupManager,
-                        mHeadsUpManager,
-                        mock(NotificationFilter.class),
-                        mLogger,
-                        mock(NotificationSectionsFeatureManager.class),
-                        mock(PeopleNotificationIdentifier.class),
-                        mock(HighPriorityProvider.class),
-                        mEnvironment));
-        mEntryManager.addNotificationEntryListener(mEntryListener);
-        mEntryManager.addCollectionListener(mNotifCollectionListener);
-        mEntryManager.addNotificationRemoveInterceptor(mRemoveInterceptor);
-
-        setUserSentiment(mSbn.getKey(), Ranking.USER_SENTIMENT_NEUTRAL);
-    }
-
-    @Test
-    public void testAddNotification_noDuplicateEntriesCreated() {
-        // GIVEN a notification has been added
-        mEntryManager.addNotification(mSbn, mRankingMap);
-
-        // WHEN the same notification is added multiple times before the previous entry (with
-        // the same key) didn't finish inflating
-        mEntryManager.addNotification(mSbn, mRankingMap);
-        mEntryManager.addNotification(mSbn, mRankingMap);
-        mEntryManager.addNotification(mSbn, mRankingMap);
-
-        // THEN getAllNotifs() only contains exactly one notification with this key
-        int count = 0;
-        for (NotificationEntry entry : mEntryManager.getAllNotifs()) {
-            if (entry.getKey().equals(mSbn.getKey())) {
-                count++;
-            }
-        }
-        assertEquals("Should only be one entry with key=" + mSbn.getKey() + " in mAllNotifs. "
-                        + "Instead there are " + count, 1, count);
-    }
-
-    @Test
-    public void testAddNotification_setsUserSentiment() {
-        mEntryManager.addNotification(mSbn, mRankingMap);
-
-        ArgumentCaptor<NotificationEntry> entryCaptor = ArgumentCaptor.forClass(
-                NotificationEntry.class);
-        verify(mEntryListener).onPendingEntryAdded(entryCaptor.capture());
-        NotificationEntry entry = entryCaptor.getValue();
-
-        assertEquals(entry.getUserSentiment(), Ranking.USER_SENTIMENT_NEUTRAL);
-    }
-
-    @Test
-    public void testUpdateNotification_prePostEntryOrder() throws Exception {
-        TestableLooper.get(this).processAllMessages();
-
-        mEntryManager.addActiveNotificationForTest(mEntry);
-
-        mEntryManager.updateNotification(mSbn, mRankingMap);
-
-        // Ensure that update callbacks happen in correct order
-        InOrder order = inOrder(mEntryListener, mPresenter, mEntryListener);
-        order.verify(mEntryListener).onPreEntryUpdated(mEntry);
-        order.verify(mEntryListener).onPostEntryUpdated(mEntry);
-    }
-
-    @Test
-    public void testRemoveNotification() {
-        mEntry.setRow(mRow);
-        mEntryManager.addActiveNotificationForTest(mEntry);
-
-        mEntryManager.removeNotification(mSbn.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON);
-
-        verify(mEntryListener).onEntryRemoved(
-                argThat(matchEntryOnKey()), any(),
-                eq(false) /* removedByUser */, eq(UNDEFINED_DISMISS_REASON));
-        verify(mRow).setRemoved();
-
-        assertNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()));
-    }
-
-    @Test
-    public void testRemoveUninflatedNotification_removesNotificationFromAllNotifsList() {
-        // GIVEN an uninflated entry is added
-        mEntryManager.addNotification(mSbn, mRankingMap);
-        assertTrue(entriesContainKey(mEntryManager.getAllNotifs(), mSbn.getKey()));
-
-        // WHEN the uninflated entry is removed
-        mEntryManager.performRemoveNotification(mSbn, mock(DismissedByUserStats.class),
-                UNDEFINED_DISMISS_REASON);
-
-        // THEN the entry is still removed from the allNotifications list
-        assertFalse(entriesContainKey(mEntryManager.getAllNotifs(), mSbn.getKey()));
-    }
-
-    @Test
-    public void testPerformRemoveNotification_sendRemovalToServer() throws RemoteException {
-        // GIVEN an entry manager with a notification
-        mEntryManager.addActiveNotificationForTest(mEntry);
-
-        // GIVEN interceptor that doesn't intercept
-        when(mRemoveInterceptor.onNotificationRemoveRequested(
-                eq(mEntry.getKey()), argThat(matchEntryOnKey()), anyInt()))
-                .thenReturn(false);
-
-        // WHEN the notification entry is removed
-        mEntryManager.performRemoveNotification(mSbn, mStats, REASON_CANCEL);
-
-        // THEN notification removal is sent to the server
-        FakeExecutor.exhaustExecutors(mBgExecutor);
-        verify(mStatusBarService).onNotificationClear(
-                mSbn.getPackageName(),
-                mSbn.getUser().getIdentifier(),
-                mSbn.getKey(),
-                mStats.dismissalSurface,
-                mStats.dismissalSentiment,
-                mStats.notificationVisibility);
-        verifyNoMoreInteractions(mStatusBarService);
-    }
-
-    @Test
-    public void testRemoveNotification_onEntryRemoveNotFiredIfEntryDoesntExist() {
-
-        mEntryManager.removeNotification("not_a_real_key", mRankingMap, UNDEFINED_DISMISS_REASON);
-
-        verify(mEntryListener, never()).onEntryRemoved(argThat(matchEntryOnKey()), any(),
-                eq(false) /* removedByUser */, eq(UNDEFINED_DISMISS_REASON));
-    }
-
-    /** Regression test for b/201097913. */
-    @Test
-    public void testRemoveNotification_whilePending_onlyCollectionListenerNotified() {
-        // Add and then remove a pending entry (entry that hasn't been inflated).
-        mEntryManager.addNotification(mSbn, mRankingMap);
-        mEntryManager.removeNotification(mSbn.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON);
-
-        // Verify that only the listener for the NEW pipeline is notified.
-        // Old pipeline:
-        verify(mEntryListener, never()).onEntryRemoved(
-                argThat(matchEntryOnKey()), any(), anyBoolean(), anyInt());
-        // New pipeline:
-        verify(mNotifCollectionListener).onEntryRemoved(
-                argThat(matchEntryOnKey()), anyInt());
-    }
-
-    @Test
-    public void testUpdateNotificationRanking_noChange() {
-        when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
-        when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true);
-
-        mEntry.setRow(mRow);
-        mEntryManager.addActiveNotificationForTest(mEntry);
-        setSmartActions(mEntry.getKey(), null);
-
-        mEntryManager.updateNotificationRanking(mRankingMap);
-        assertThat(mEntry.getSmartActions()).isEmpty();
-    }
-
-    @Test
-    public void testUpdateNotificationRanking_pendingNotification() {
-        when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
-        when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true);
-
-        mEntry.setRow(null);
-        mEntryManager.mPendingNotifications.put(mEntry.getKey(), mEntry);
-        setSmartActions(mEntry.getKey(), new ArrayList<>(Arrays.asList(createAction())));
-
-        mEntryManager.updateNotificationRanking(mRankingMap);
-        assertEquals(1, mEntry.getSmartActions().size());
-        assertEquals("action", mEntry.getSmartActions().get(0).title);
-    }
-
-    @Test
-    public void testUpdatePendingNotification_rankingUpdated() {
-        // GIVEN a notification with ranking is pending
-        final Ranking originalRanking = mEntry.getRanking();
-        mEntryManager.mPendingNotifications.put(mEntry.getKey(), mEntry);
-
-        // WHEN the same notification has been updated with a new ranking
-        final int newRank = 2345;
-        doAnswer(invocationOnMock -> {
-            Ranking ranking = (Ranking)
-                    invocationOnMock.getArguments()[1];
-            ranking.populate(
-                    mEntry.getKey(),
-                    newRank, /* this changed!! */
-                    false,
-                    0,
-                    0,
-                    IMPORTANCE_DEFAULT,
-                    null, null,
-                    null, null, null, true,
-                    Ranking.USER_SENTIMENT_NEUTRAL, false, -1,
-                    false, null, null, false, false, false, null, 0, false);
-            return true;
-        }).when(mRankingMap).getRanking(eq(mEntry.getKey()), any(Ranking.class));
-        mEntryManager.addNotification(mSbn, mRankingMap);
-
-        // THEN ranking for the entry has been updated with new ranking
-        assertEquals(newRank, mEntry.getRanking().getRank());
-    }
-
-    @Test
-    public void testNotifyChannelModified_notifiesListeners() {
-        NotificationChannel channel = mock(NotificationChannel.class);
-        String pkg = "PKG";
-        mEntryManager.notifyChannelModified(pkg, UserHandle.CURRENT, channel,
-                NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
-        verify(mNotifCollectionListener).onNotificationChannelModified(eq(pkg),
-                eq(UserHandle.CURRENT), eq(channel), eq(NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
-        verify(mEntryListener).onNotificationChannelModified(eq(pkg),
-                eq(UserHandle.CURRENT), eq(channel), eq(NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
-    }
-
-    @Test
-    public void testLifetimeExtenders_ifNotificationIsRetainedItIsntRemoved() {
-        // GIVEN an entry manager with a notification
-        mEntryManager.addActiveNotificationForTest(mEntry);
-
-        // GIVEN a lifetime extender that always tries to extend lifetime
-        NotificationLifetimeExtender extender = mock(NotificationLifetimeExtender.class);
-        when(extender.shouldExtendLifetime(mEntry)).thenReturn(true);
-        mEntryManager.addNotificationLifetimeExtender(extender);
-
-        // WHEN the notification is removed
-        mEntryManager.removeNotification(mEntry.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON);
-
-        // THEN the extender is asked to manage the lifetime
-        verify(extender).setShouldManageLifetime(mEntry, true);
-        // THEN the notification is retained
-        assertNotNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()));
-        verify(mEntryListener, never()).onEntryRemoved(
-                argThat(matchEntryOnKey()), any(), eq(false), eq(UNDEFINED_DISMISS_REASON));
-    }
-
-    @Test
-    public void testLifetimeExtenders_whenRetentionEndsNotificationIsRemoved() {
-        // GIVEN an entry manager with a notification whose life has been extended
-        mEntryManager.addActiveNotificationForTest(mEntry);
-        final FakeNotificationLifetimeExtender extender = new FakeNotificationLifetimeExtender();
-        mEntryManager.addNotificationLifetimeExtender(extender);
-        mEntryManager.removeNotification(mEntry.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON);
-        assertTrue(extender.isManaging(mEntry.getKey()));
-
-        // WHEN the extender finishes its extension
-        extender.setExtendLifetimes(false);
-        extender.getCallback().onSafeToRemove(mEntry.getKey());
-
-        // THEN the notification is removed
-        assertNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()));
-        verify(mEntryListener).onEntryRemoved(
-                argThat(matchEntryOnKey()), any(), eq(false), eq(UNDEFINED_DISMISS_REASON));
-    }
-
-    @Test
-    public void testLifetimeExtenders_whenNotificationUpdatedRetainersAreCanceled() {
-        // GIVEN an entry manager with a notification whose life has been extended
-        mEntryManager.addActiveNotificationForTest(mEntry);
-        NotificationLifetimeExtender extender = mock(NotificationLifetimeExtender.class);
-        when(extender.shouldExtendLifetime(mEntry)).thenReturn(true);
-        mEntryManager.addNotificationLifetimeExtender(extender);
-        mEntryManager.removeNotification(mEntry.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON);
-
-        // WHEN the notification is updated
-        mEntryManager.updateNotification(mEntry.getSbn(), mRankingMap);
-
-        // THEN the lifetime extension is canceled
-        verify(extender).setShouldManageLifetime(mEntry, false);
-    }
-
-    @Test
-    public void testLifetimeExtenders_whenNewExtenderTakesPrecedenceOldExtenderIsCanceled() {
-        // GIVEN an entry manager with a notification
-        mEntryManager.addActiveNotificationForTest(mEntry);
-
-        // GIVEN two lifetime extenders, the first which never extends and the second which
-        // always extends
-        NotificationLifetimeExtender extender1 = mock(NotificationLifetimeExtender.class);
-        when(extender1.shouldExtendLifetime(mEntry)).thenReturn(false);
-        NotificationLifetimeExtender extender2 = mock(NotificationLifetimeExtender.class);
-        when(extender2.shouldExtendLifetime(mEntry)).thenReturn(true);
-        mEntryManager.addNotificationLifetimeExtender(extender1);
-        mEntryManager.addNotificationLifetimeExtender(extender2);
-
-        // GIVEN a notification was lifetime-extended and extender2 is managing it
-        mEntryManager.removeNotification(mEntry.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON);
-        verify(extender1, never()).setShouldManageLifetime(mEntry, true);
-        verify(extender2).setShouldManageLifetime(mEntry, true);
-
-        // WHEN the extender1 changes its mind and wants to extend the lifetime of the notif
-        when(extender1.shouldExtendLifetime(mEntry)).thenReturn(true);
-        mEntryManager.removeNotification(mEntry.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON);
-
-        // THEN extender2 stops managing the notif and extender1 starts managing it
-        verify(extender1).setShouldManageLifetime(mEntry, true);
-        verify(extender2).setShouldManageLifetime(mEntry, false);
-    }
-
-    /**
-     * Ensure that calling NotificationEntryManager.performRemoveNotification() doesn't crash when
-     * given a notification that has already been removed from NotificationData.
-     */
-    @Test
-    public void testPerformRemoveNotification_removedEntry() {
-        mEntryManager.removeNotification(mSbn.getKey(), null, 0);
-        mEntryManager.performRemoveNotification(mSbn, mock(DismissedByUserStats.class),
-                REASON_CANCEL);
-    }
-
-    @Test
-    public void testRemoveInterceptor_interceptsDontGetRemoved() throws InterruptedException {
-        // GIVEN an entry manager with a notification
-        mEntryManager.addActiveNotificationForTest(mEntry);
-
-        // GIVEN interceptor that intercepts that entry
-        when(mRemoveInterceptor.onNotificationRemoveRequested(
-                eq(mEntry.getKey()), argThat(matchEntryOnKey()), anyInt()))
-                .thenReturn(true);
-
-        // WHEN the notification is removed
-        mEntryManager.removeNotification(mEntry.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON);
-
-        // THEN the interceptor intercepts & the entry is not removed & no listeners are called
-        assertNotNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()));
-        verify(mEntryListener, never()).onEntryRemoved(argThat(matchEntryOnKey()),
-                any(NotificationVisibility.class), anyBoolean(), eq(UNDEFINED_DISMISS_REASON));
-    }
-
-    @Test
-    public void testRemoveInterceptor_notInterceptedGetsRemoved() {
-        // GIVEN an entry manager with a notification
-        mEntryManager.addActiveNotificationForTest(mEntry);
-
-        // GIVEN interceptor that doesn't intercept
-        when(mRemoveInterceptor.onNotificationRemoveRequested(
-                eq(mEntry.getKey()), argThat(matchEntryOnKey()), anyInt()))
-                .thenReturn(false);
-
-        // WHEN the notification is removed
-        mEntryManager.removeNotification(mEntry.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON);
-
-        // THEN the interceptor intercepts & the entry is not removed & no listeners are called
-        assertNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()));
-        verify(mEntryListener, atLeastOnce()).onEntryRemoved(argThat(matchEntryOnKey()),
-                any(NotificationVisibility.class), anyBoolean(), eq(UNDEFINED_DISMISS_REASON));
-    }
-
-    /* Tests annexed from NotificationDataTest go here */
-
-    @Test
-    public void testGetNotificationsForCurrentUser_shouldFilterNonCurrentUserNotifications() {
-        Notification.Builder n = new Notification.Builder(mContext, "di")
-                .setSmallIcon(R.drawable.ic_person)
-                .setContentTitle("Title")
-                .setContentText("Text");
-
-        NotificationEntry e2 = new NotificationEntryBuilder()
-                .setPkg(TEST_PACKAGE_NAME)
-                .setOpPkg(TEST_PACKAGE_NAME)
-                .setUid(TEST_UID)
-                .setId(mId++)
-                .setNotification(n.build())
-                .setUser(new UserHandle(ActivityManager.getCurrentUser()))
-                .setChannel(new NotificationChannel("id", "", IMPORTANCE_DEFAULT))
-                .build();
-
-        mEntryManager.addActiveNotificationForTest(mEntry);
-        mEntryManager.addActiveNotificationForTest(e2);
-
-        when(mEnvironment.isNotificationForCurrentProfiles(mEntry.getSbn())).thenReturn(false);
-        when(mEnvironment.isNotificationForCurrentProfiles(e2.getSbn())).thenReturn(true);
-
-        List<NotificationEntry> result = mEntryManager.getActiveNotificationsForCurrentUser();
-        assertEquals(result.size(), 1);
-        junit.framework.Assert.assertEquals(result.get(0), e2);
-    }
-
-    /* End annex */
-
-    private boolean entriesContainKey(Collection<NotificationEntry> entries, String key) {
-        for (NotificationEntry entry : entries) {
-            if (entry.getSbn().getKey().equals(key)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private Notification.Action createAction() {
-        return new Notification.Action.Builder(
-                Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon),
-                "action",
-                PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"),
-                    PendingIntent.FLAG_IMMUTABLE)).build();
-    }
-
-    private ArgumentMatcher<NotificationEntry> matchEntryOnKey() {
-        return e -> e.getKey().equals(mEntry.getKey());
-    }
-
-    private static class FakeNotificationLifetimeExtender implements NotificationLifetimeExtender {
-        private NotificationSafeToRemoveCallback mCallback;
-        private boolean mExtendLifetimes = true;
-        private Set<String> mManagedNotifs = new ArraySet<>();
-
-        @Override
-        public void setCallback(@NonNull NotificationSafeToRemoveCallback callback) {
-            mCallback = callback;
-        }
-
-        @Override
-        public boolean shouldExtendLifetime(@NonNull NotificationEntry entry) {
-            return mExtendLifetimes;
-        }
-
-        @Override
-        public void setShouldManageLifetime(
-                @NonNull NotificationEntry entry,
-                boolean shouldManage) {
-            final boolean hasEntry = mManagedNotifs.contains(entry.getKey());
-            if (shouldManage) {
-                if (hasEntry) {
-                    throw new RuntimeException("Already managing this entry: " + entry.getKey());
-                }
-                mManagedNotifs.add(entry.getKey());
-            } else {
-                if (!hasEntry) {
-                    throw new RuntimeException("Not managing this entry: " + entry.getKey());
-                }
-                mManagedNotifs.remove(entry.getKey());
-            }
-        }
-
-        public void setExtendLifetimes(boolean extendLifetimes) {
-            mExtendLifetimes = extendLifetimes;
-        }
-
-        public NotificationSafeToRemoveCallback getCallback() {
-            return mCallback;
-        }
-
-        public boolean isManaging(String notificationKey) {
-            return mManagedNotifs.contains(notificationKey);
-        }
-    }
-
-    private NotificationEntry createNotification() {
-        Notification.Builder n = new Notification.Builder(mContext, "id")
-                .setSmallIcon(R.drawable.ic_person)
-                .setContentTitle("Title")
-                .setContentText("Text");
-
-        return new NotificationEntryBuilder()
-                .setPkg(TEST_PACKAGE_NAME)
-                .setOpPkg(TEST_PACKAGE_NAME)
-                .setUid(TEST_UID)
-                .setId(mId++)
-                .setNotification(n.build())
-                .setChannel(new NotificationChannel("id", "", IMPORTANCE_DEFAULT))
-                .setUser(new UserHandle(ActivityManager.getCurrentUser()))
-                .build();
-    }
-
-    private static DismissedByUserStats defaultStats(NotificationEntry entry) {
-        return new DismissedByUserStats(
-                DISMISSAL_SHADE,
-                DISMISS_SENTIMENT_NEUTRAL,
-                NotificationVisibility.obtain(entry.getKey(), 7, 2, true));
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
deleted file mode 100644
index 2cacaf7..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import android.Manifest;
-import android.app.Notification;
-import android.app.Notification.MediaStyle;
-import android.content.pm.IPackageManager;
-import android.content.pm.PackageManager;
-import android.media.session.MediaSession;
-import android.os.Bundle;
-import android.service.notification.StatusBarNotification;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.testing.TestableLooper.RunWithLooper;
-
-import androidx.annotation.NonNull;
-import androidx.test.annotation.UiThreadTest;
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.ForegroundServiceController;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.media.MediaFeatureFlag;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.shade.ShadeController;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
-import com.android.systemui.statusbar.notification.collection.provider.DebugModeFilterProvider;
-import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
-import com.android.wm.shell.bubbles.Bubbles;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.Optional;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@RunWithLooper
-public class NotificationFilterTest extends SysuiTestCase {
-
-    private static final int UID_NORMAL = 123;
-    private static final int UID_ALLOW_DURING_SETUP = 456;
-    private static final String TEST_HIDDEN_NOTIFICATION_KEY = "testHiddenNotificationKey";
-
-    private final StatusBarNotification mMockStatusBarNotification =
-            mock(StatusBarNotification.class);
-
-    @Mock
-    DebugModeFilterProvider mDebugModeFilterProvider;
-    @Mock
-    StatusBarStateController mStatusBarStateController;
-    @Mock
-    KeyguardEnvironment mEnvironment;
-    @Mock
-    ForegroundServiceController mFsc;
-    @Mock
-    NotificationLockscreenUserManager mUserManager;
-    @Mock
-    MediaFeatureFlag mMediaFeatureFlag;
-
-    private final IPackageManager mMockPackageManager = mock(IPackageManager.class);
-
-    private NotificationFilter mNotificationFilter;
-    private ExpandableNotificationRow mRow;
-    private NotificationEntry mMediaEntry;
-    private MediaSession mMediaSession;
-
-    @Before
-    public void setUp() throws Exception {
-        allowTestableLooperAsMainThread();
-        MockitoAnnotations.initMocks(this);
-        when(mMockStatusBarNotification.getUid()).thenReturn(UID_NORMAL);
-
-        mMediaSession = new MediaSession(mContext, "TEST_MEDIA_SESSION");
-        NotificationEntryBuilder builder = new NotificationEntryBuilder();
-        builder.modifyNotification(mContext).setStyle(
-                new MediaStyle().setMediaSession(mMediaSession.getSessionToken()));
-        mMediaEntry = builder.build();
-
-        when(mMockPackageManager.checkUidPermission(
-                eq(Manifest.permission.NOTIFICATION_DURING_SETUP),
-                eq(UID_NORMAL)))
-                .thenReturn(PackageManager.PERMISSION_DENIED);
-        when(mMockPackageManager.checkUidPermission(
-                eq(Manifest.permission.NOTIFICATION_DURING_SETUP),
-                eq(UID_ALLOW_DURING_SETUP)))
-                .thenReturn(PackageManager.PERMISSION_GRANTED);
-        mDependency.injectTestDependency(ForegroundServiceController.class, mFsc);
-        mDependency.injectTestDependency(NotificationGroupManagerLegacy.class,
-                new NotificationGroupManagerLegacy(
-                        mock(StatusBarStateController.class),
-                        () -> mock(PeopleNotificationIdentifier.class),
-                        Optional.of(mock(Bubbles.class)),
-                        mock(DumpManager.class)));
-        mDependency.injectMockDependency(ShadeController.class);
-        mDependency.injectMockDependency(NotificationLockscreenUserManager.class);
-        mDependency.injectTestDependency(KeyguardEnvironment.class, mEnvironment);
-        when(mEnvironment.isDeviceProvisioned()).thenReturn(true);
-        when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true);
-        NotificationTestHelper testHelper = new NotificationTestHelper(
-                mContext,
-                mDependency,
-                TestableLooper.get(this));
-        mRow = testHelper.createRow();
-        mNotificationFilter = newNotificationFilter();
-    }
-
-    @NonNull
-    private NotificationFilter newNotificationFilter() {
-        return new NotificationFilter(
-                mDebugModeFilterProvider,
-                mStatusBarStateController,
-                mEnvironment,
-                mFsc,
-                mUserManager,
-                mMediaFeatureFlag);
-    }
-
-    @After
-    public void tearDown() {
-        mMediaSession.release();
-    }
-
-    @Test
-    @UiThreadTest
-    public void testShowNotificationEvenIfUnprovisioned_FalseIfNoExtra() {
-        initStatusBarNotification(false);
-        when(mMockStatusBarNotification.getUid()).thenReturn(UID_ALLOW_DURING_SETUP);
-
-        assertFalse(
-                NotificationFilter.showNotificationEvenIfUnprovisioned(
-                        mMockPackageManager,
-                        mMockStatusBarNotification));
-    }
-
-    @Test
-    @UiThreadTest
-    public void testShowNotificationEvenIfUnprovisioned_FalseIfNoPermission() {
-        initStatusBarNotification(true);
-
-        assertFalse(
-                NotificationFilter.showNotificationEvenIfUnprovisioned(
-                        mMockPackageManager,
-                        mMockStatusBarNotification));
-    }
-
-    @Test
-    @UiThreadTest
-    public void testShowNotificationEvenIfUnprovisioned_TrueIfHasPermissionAndExtra() {
-        initStatusBarNotification(true);
-        when(mMockStatusBarNotification.getUid()).thenReturn(UID_ALLOW_DURING_SETUP);
-
-        assertTrue(
-                NotificationFilter.showNotificationEvenIfUnprovisioned(
-                        mMockPackageManager,
-                        mMockStatusBarNotification));
-    }
-
-    @Test
-    public void testShouldFilterHiddenNotifications() {
-        initStatusBarNotification(false);
-        // setup
-        when(mFsc.isSystemAlertWarningNeeded(anyInt(), anyString())).thenReturn(false);
-
-        // test should filter out hidden notifications:
-        // hidden
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setSuspended(true)
-                .build();
-
-        assertTrue(mNotificationFilter.shouldFilterOut(entry));
-
-        // not hidden
-        entry = new NotificationEntryBuilder()
-                .setSuspended(false)
-                .build();
-        assertFalse(mNotificationFilter.shouldFilterOut(entry));
-    }
-
-    @Test
-    public void shouldFilterOtherNotificationWhenDisabled() {
-        // GIVEN that the media feature is disabled
-        when(mMediaFeatureFlag.getEnabled()).thenReturn(false);
-        NotificationFilter filter = newNotificationFilter();
-        // WHEN the media filter is asked about an entry
-        NotificationEntry otherEntry = new NotificationEntryBuilder().build();
-        final boolean shouldFilter = filter.shouldFilterOut(otherEntry);
-        // THEN it shouldn't be filtered
-        assertFalse(shouldFilter);
-    }
-
-    @Test
-    public void shouldFilterOtherNotificationWhenEnabled() {
-        // GIVEN that the media feature is enabled
-        when(mMediaFeatureFlag.getEnabled()).thenReturn(true);
-        NotificationFilter filter = newNotificationFilter();
-        // WHEN the media filter is asked about an entry
-        NotificationEntry otherEntry = new NotificationEntryBuilder().build();
-        final boolean shouldFilter = filter.shouldFilterOut(otherEntry);
-        // THEN it shouldn't be filtered
-        assertFalse(shouldFilter);
-    }
-
-    @Test
-    public void shouldFilterMediaNotificationWhenDisabled() {
-        // GIVEN that the media feature is disabled
-        when(mMediaFeatureFlag.getEnabled()).thenReturn(false);
-        NotificationFilter filter = newNotificationFilter();
-        // WHEN the media filter is asked about a media entry
-        final boolean shouldFilter = filter.shouldFilterOut(mMediaEntry);
-        // THEN it shouldn't be filtered
-        assertFalse(shouldFilter);
-    }
-
-    @Test
-    public void shouldFilterMediaNotificationWhenEnabled() {
-        // GIVEN that the media feature is enabled
-        when(mMediaFeatureFlag.getEnabled()).thenReturn(true);
-        NotificationFilter filter = newNotificationFilter();
-        // WHEN the media filter is asked about a media entry
-        final boolean shouldFilter = filter.shouldFilterOut(mMediaEntry);
-        // THEN it should be filtered
-        assertTrue(shouldFilter);
-    }
-
-    private void initStatusBarNotification(boolean allowDuringSetup) {
-        Bundle bundle = new Bundle();
-        bundle.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, allowDuringSetup);
-        Notification notification = new Notification.Builder(mContext, "test")
-                .addExtras(bundle)
-                .build();
-        when(mMockStatusBarNotification.getNotification()).thenReturn(notification);
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java
deleted file mode 100644
index 58abbf2..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar.notification;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
-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.os.Handler;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.keyguard.WakefulnessLifecycle;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
-import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
-import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper()
-public class VisualStabilityManagerTest extends SysuiTestCase {
-
-    private TestableLooper mTestableLooper;
-
-    private VisualStabilityManager mVisualStabilityManager;
-    private VisualStabilityProvider mVisualStabilityProvider = mock(VisualStabilityProvider.class);
-    private VisualStabilityManager.Callback mCallback = mock(VisualStabilityManager.Callback.class);
-    private VisibilityLocationProvider mLocationProvider = mock(VisibilityLocationProvider.class);
-    private ExpandableNotificationRow mRow = mock(ExpandableNotificationRow.class);
-    private NotificationEntry mEntry;
-
-    private StatusBarStateController.StateListener mStatusBarStateListener;
-    private WakefulnessLifecycle.Observer mWakefulnessObserver;
-
-    @Before
-    public void setUp() {
-        StatusBarStateController statusBarStateController = mock(StatusBarStateController.class);
-        WakefulnessLifecycle wakefulnessLifecycle = mock(WakefulnessLifecycle.class);
-
-        mTestableLooper = TestableLooper.get(this);
-        mVisualStabilityManager = new VisualStabilityManager(
-                mock(NotificationEntryManager.class),
-                mVisualStabilityProvider,
-                new Handler(mTestableLooper.getLooper()),
-                statusBarStateController,
-                wakefulnessLifecycle,
-                mock(DumpManager.class));
-
-        mVisualStabilityManager.setVisibilityLocationProvider(mLocationProvider);
-        mEntry = new NotificationEntryBuilder().build();
-        mEntry.setRow(mRow);
-
-        when(mRow.getEntry()).thenReturn(mEntry);
-
-        ArgumentCaptor<StatusBarStateController.StateListener> stateListenerCaptor =
-                ArgumentCaptor.forClass(StatusBarStateController.StateListener.class);
-        verify(statusBarStateController).addCallback(stateListenerCaptor.capture());
-        mStatusBarStateListener = stateListenerCaptor.getValue();
-
-        ArgumentCaptor<WakefulnessLifecycle.Observer> wakefulnessObserverCaptor =
-                ArgumentCaptor.forClass(WakefulnessLifecycle.Observer.class);
-        verify(wakefulnessLifecycle).addObserver(wakefulnessObserverCaptor.capture());
-        mWakefulnessObserver = wakefulnessObserverCaptor.getValue();
-    }
-
-    @Test
-    public void testPanelExpansion() {
-        setPanelExpanded(true);
-        setScreenOn(true);
-        assertFalse(mVisualStabilityManager.canReorderNotification(mRow));
-        setPanelExpanded(false);
-        assertTrue(mVisualStabilityManager.canReorderNotification(mRow));
-    }
-
-    @Test
-    public void testScreenOn() {
-        setPanelExpanded(true);
-        setScreenOn(true);
-        assertFalse(mVisualStabilityManager.canReorderNotification(mRow));
-        setScreenOn(false);
-        assertTrue(mVisualStabilityManager.canReorderNotification(mRow));
-    }
-
-    @Test
-    public void testReorderingAllowedChangesScreenOn() {
-        setPanelExpanded(true);
-        setScreenOn(true);
-        assertFalse(mVisualStabilityManager.isReorderingAllowed());
-        setScreenOn(false);
-        assertTrue(mVisualStabilityManager.isReorderingAllowed());
-    }
-
-    @Test
-    public void testReorderingAllowedChangesPanel() {
-        setPanelExpanded(true);
-        setScreenOn(true);
-        assertFalse(mVisualStabilityManager.isReorderingAllowed());
-        setPanelExpanded(false);
-        assertTrue(mVisualStabilityManager.isReorderingAllowed());
-    }
-
-    @Test
-    public void testCallBackCalledScreenOn() {
-        setPanelExpanded(true);
-        setScreenOn(true);
-        mVisualStabilityManager.addReorderingAllowedCallback(mCallback, false  /* persistent */);
-        setScreenOn(false);
-        verify(mCallback).onChangeAllowed();
-    }
-
-    @Test
-    public void testCallBackCalledPanelExpanded() {
-        setPanelExpanded(true);
-        setScreenOn(true);
-        mVisualStabilityManager.addReorderingAllowedCallback(mCallback, false  /* persistent */);
-        setPanelExpanded(false);
-        verify(mCallback).onChangeAllowed();
-    }
-
-    @Test
-    public void testCallBackExactlyOnce() {
-        setPanelExpanded(true);
-        setScreenOn(true);
-        mVisualStabilityManager.addReorderingAllowedCallback(mCallback, false  /* persistent */);
-        setScreenOn(false);
-        setScreenOn(true);
-        setScreenOn(false);
-        verify(mCallback).onChangeAllowed();
-    }
-
-    @Test
-    public void testCallBackCalledContinuouslyWhenRequested() {
-        setPanelExpanded(true);
-        setScreenOn(true);
-        mVisualStabilityManager.addReorderingAllowedCallback(mCallback, true  /* persistent */);
-        setScreenOn(false);
-        setScreenOn(true);
-        setScreenOn(false);
-        verify(mCallback, times(2)).onChangeAllowed();
-    }
-
-    @Test
-    public void testAddedCanReorder() {
-        setPanelExpanded(true);
-        setScreenOn(true);
-        mVisualStabilityManager.notifyViewAddition(mRow);
-        assertTrue(mVisualStabilityManager.canReorderNotification(mRow));
-    }
-
-    @Test
-    public void testReorderingVisibleHeadsUpNotAllowed() {
-        setPanelExpanded(true);
-        setScreenOn(true);
-        when(mLocationProvider.isInVisibleLocation(any(NotificationEntry.class))).thenReturn(true);
-        mVisualStabilityManager.onHeadsUpStateChanged(mEntry, true);
-        assertFalse(mVisualStabilityManager.canReorderNotification(mRow));
-    }
-
-    @Test
-    public void testReorderingVisibleHeadsUpAllowed() {
-        setPanelExpanded(true);
-        setScreenOn(true);
-        when(mLocationProvider.isInVisibleLocation(any(NotificationEntry.class))).thenReturn(false);
-        mVisualStabilityManager.onHeadsUpStateChanged(mEntry, true);
-        assertTrue(mVisualStabilityManager.canReorderNotification(mRow));
-    }
-
-    @Test
-    public void testReorderingVisibleHeadsUpAllowedOnce() {
-        setPanelExpanded(true);
-        setScreenOn(true);
-        when(mLocationProvider.isInVisibleLocation(any(NotificationEntry.class))).thenReturn(false);
-        mVisualStabilityManager.onHeadsUpStateChanged(mEntry, true);
-        mVisualStabilityManager.onReorderingFinished();
-        assertFalse(mVisualStabilityManager.canReorderNotification(mRow));
-    }
-
-    @Test
-    public void testPulsing() {
-        setPulsing(true);
-        assertFalse(mVisualStabilityManager.canReorderNotification(mRow));
-        setPulsing(false);
-        assertTrue(mVisualStabilityManager.canReorderNotification(mRow));
-    }
-
-    @Test
-    public void testReorderingAllowedChanges_Pulsing() {
-        setPulsing(true);
-        assertFalse(mVisualStabilityManager.isReorderingAllowed());
-        setPulsing(false);
-        assertTrue(mVisualStabilityManager.isReorderingAllowed());
-    }
-
-    @Test
-    public void testCallBackCalled_Pulsing() {
-        setPulsing(true);
-        mVisualStabilityManager.addReorderingAllowedCallback(mCallback, false  /* persistent */);
-        setPulsing(false);
-        verify(mCallback).onChangeAllowed();
-    }
-
-    @Test
-    public void testTemporarilyAllowReorderingNotifiesCallbacks() {
-        // GIVEN having the panel open (which would block reordering)
-        setScreenOn(true);
-        setPanelExpanded(true);
-        mVisualStabilityManager.addReorderingAllowedCallback(mCallback, false  /* persistent */);
-
-        // WHEN we temprarily allow reordering
-        mVisualStabilityManager.temporarilyAllowReordering();
-
-        // THEN callbacks are notified that reordering is allowed
-        verify(mCallback).onChangeAllowed();
-        assertTrue(mVisualStabilityManager.isReorderingAllowed());
-    }
-
-    @Test
-    public void testTemporarilyAllowReorderingDoesntOverridePulsing() {
-        // GIVEN we are in a pulsing state
-        setPulsing(true);
-        mVisualStabilityManager.addReorderingAllowedCallback(mCallback, false  /* persistent */);
-
-        // WHEN we temprarily allow reordering
-        mVisualStabilityManager.temporarilyAllowReordering();
-
-        // THEN reordering is still not allowed
-        verify(mCallback, never()).onChangeAllowed();
-        assertFalse(mVisualStabilityManager.isReorderingAllowed());
-    }
-
-    @Test
-    public void testTemporarilyAllowReorderingExpires() {
-        // GIVEN having the panel open (which would block reordering)
-        setScreenOn(true);
-        setPanelExpanded(true);
-        mVisualStabilityManager.addReorderingAllowedCallback(mCallback, false  /* persistent */);
-
-        // WHEN we temprarily allow reordering and then wait until the window expires
-        mVisualStabilityManager.temporarilyAllowReordering();
-        assertTrue(mVisualStabilityManager.isReorderingAllowed());
-        mTestableLooper.processMessages(1);
-
-        // THEN reordering is no longer allowed
-        assertFalse(mVisualStabilityManager.isReorderingAllowed());
-    }
-
-    private void setPanelExpanded(boolean expanded) {
-        mStatusBarStateListener.onExpandedChanged(expanded);
-    }
-
-    private void setPulsing(boolean pulsing) {
-        mStatusBarStateListener.onPulsingChanged(pulsing);
-    }
-
-    private void setScreenOn(boolean screenOn) {
-        if (screenOn) {
-            mWakefulnessObserver.onStartedWakingUp();
-        } else {
-            mWakefulnessObserver.onFinishedGoingToSleep();
-        }
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
deleted file mode 100644
index c51c628..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
+++ /dev/null
@@ -1,509 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification.collection
-
-import android.app.Notification
-import android.app.NotificationChannel
-import android.app.NotificationManager.IMPORTANCE_DEFAULT
-import android.app.NotificationManager.IMPORTANCE_HIGH
-import android.app.NotificationManager.IMPORTANCE_LOW
-import android.app.PendingIntent
-import android.app.Person
-import android.os.SystemClock
-import android.service.notification.NotificationListenerService.RankingMap
-import android.testing.AndroidTestingRunner
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking
-import com.android.systemui.statusbar.NotificationMediaManager
-import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment
-import com.android.systemui.statusbar.notification.NotificationEntryManagerLogger
-import com.android.systemui.statusbar.notification.NotificationFilter
-import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy
-import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
-import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
-import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_FULL_PERSON
-import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_IMPORTANT_PERSON
-import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_PERSON
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
-import com.android.systemui.statusbar.notification.stack.BUCKET_ALERTING
-import com.android.systemui.statusbar.notification.stack.BUCKET_FOREGROUND_SERVICE
-import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT
-import com.android.systemui.statusbar.policy.HeadsUpManager
-import com.google.common.truth.Truth.assertThat
-import dagger.Lazy
-import junit.framework.Assert.assertEquals
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mockito.mock
-import org.mockito.Mockito.`when` as whenever
-
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-class NotificationRankingManagerTest : SysuiTestCase() {
-
-    private val lazyMedia: Lazy<NotificationMediaManager> = Lazy {
-        mock(NotificationMediaManager::class.java)
-    }
-    private lateinit var personNotificationIdentifier: PeopleNotificationIdentifier
-    private lateinit var rankingManager: TestableNotificationRankingManager
-    private lateinit var sectionsManager: NotificationSectionsFeatureManager
-    private lateinit var notificationFilter: NotificationFilter
-
-    @Before
-    fun setup() {
-        personNotificationIdentifier =
-                mock(PeopleNotificationIdentifier::class.java)
-        sectionsManager = mock(NotificationSectionsFeatureManager::class.java)
-        notificationFilter = mock(NotificationFilter::class.java)
-        rankingManager = TestableNotificationRankingManager(
-                lazyMedia,
-                mock(NotificationGroupManagerLegacy::class.java),
-                mock(HeadsUpManager::class.java),
-                notificationFilter,
-                mock(NotificationEntryManagerLogger::class.java),
-                sectionsManager,
-                personNotificationIdentifier,
-                HighPriorityProvider(
-                        personNotificationIdentifier,
-                        mock(NotificationGroupManagerLegacy::class.java)),
-                mock(KeyguardEnvironment::class.java)
-                )
-    }
-
-    @Test
-    fun testSort_highPriorityTrumpsNMSRank() {
-        // NMS rank says A and then B. But A is not high priority and B is, so B should sort in
-        // front
-        val a = NotificationEntryBuilder()
-                .setImportance(IMPORTANCE_LOW) // low priority
-                .setRank(1) // NMS says rank first
-                .setPkg("pkg")
-                .setOpPkg("pkg")
-                .setTag("tag")
-                .setNotification(
-                        Notification.Builder(mContext, "test")
-                                .build())
-                .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
-                .setUser(mContext.getUser())
-                .setOverrideGroupKey("")
-                .build()
-
-        val b = NotificationEntryBuilder()
-                .setImportance(IMPORTANCE_HIGH) // high priority
-                .setRank(2) // NMS says rank second
-                .setPkg("pkg2")
-                .setOpPkg("pkg2")
-                .setTag("tag")
-                .setNotification(
-                        Notification.Builder(mContext, "test")
-                                .build())
-                .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
-                .setUser(mContext.getUser())
-                .setOverrideGroupKey("")
-                .build()
-
-        assertEquals(
-                listOf(b, a),
-                rankingManager.updateRanking(null, listOf(a, b), "test"))
-    }
-
-    @Test
-    fun testSort_samePriorityUsesNMSRank() {
-        // NMS rank says A and then B, and they are the same priority so use that rank
-        val aN = Notification.Builder(mContext, "test")
-                .setStyle(Notification.MessagingStyle(""))
-                .build()
-        val a = NotificationEntryBuilder()
-                .setRank(1)
-                .setImportance(IMPORTANCE_HIGH)
-                .setPkg("pkg")
-                .setOpPkg("pkg")
-                .setTag("tag")
-                .setNotification(aN)
-                .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
-                .setUser(mContext.getUser())
-                .setOverrideGroupKey("")
-                .build()
-
-        val bN = Notification.Builder(mContext, "test")
-                .setStyle(Notification.MessagingStyle(""))
-                .build()
-        val b = NotificationEntryBuilder()
-                .setRank(2)
-                .setImportance(IMPORTANCE_HIGH)
-                .setPkg("pkg2")
-                .setOpPkg("pkg2")
-                .setTag("tag")
-                .setNotification(bN)
-                .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
-                .setUser(mContext.getUser())
-                .setOverrideGroupKey("")
-                .build()
-
-        assertEquals(
-                listOf(a, b),
-                rankingManager.updateRanking(null, listOf(a, b), "test"))
-    }
-
-    @Test
-    fun testSort_headsUp_trumpsPeople() {
-        whenever(sectionsManager.isFilteringEnabled()).thenReturn(true)
-        val aN = Notification.Builder(mContext, "test")
-                .setStyle(Notification.MessagingStyle(""))
-                .build()
-        val a = NotificationEntryBuilder()
-                .setImportance(IMPORTANCE_HIGH)
-                .setPkg("pkg")
-                .setOpPkg("pkg")
-                .setTag("tag")
-                .setNotification(aN)
-                .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
-                .setUser(mContext.getUser())
-                .setOverrideGroupKey("")
-                .build()
-
-        whenever(personNotificationIdentifier.getPeopleNotificationType(a))
-                .thenReturn(TYPE_IMPORTANT_PERSON)
-
-        val bN = Notification.Builder(mContext, "test")
-                .setStyle(Notification.MessagingStyle(""))
-                .build()
-        val b = NotificationEntryBuilder()
-                .setImportance(IMPORTANCE_HIGH)
-                .setPkg("pkg2")
-                .setOpPkg("pkg2")
-                .setTag("tag")
-                .setNotification(bN)
-                .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
-                .setUser(mContext.getUser())
-                .setOverrideGroupKey("")
-                .build()
-        b.row = mock(ExpandableNotificationRow::class.java).also {
-            whenever(it.isHeadsUp).thenReturn(true)
-        }
-
-        whenever(personNotificationIdentifier.getPeopleNotificationType(a))
-                .thenReturn(TYPE_PERSON)
-
-        assertEquals(listOf(b, a), rankingManager.updateRanking(null, listOf(a, b), "test"))
-    }
-
-    @Test
-    fun testSort_importantPeople() {
-        whenever(sectionsManager.isFilteringEnabled()).thenReturn(true)
-        val aN = Notification.Builder(mContext, "test")
-                .setStyle(Notification.MessagingStyle(""))
-                .build()
-        val a = NotificationEntryBuilder()
-                .setImportance(IMPORTANCE_HIGH)
-                .setPkg("pkg")
-                .setOpPkg("pkg")
-                .setTag("tag")
-                .setNotification(aN)
-                .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
-                .setUser(mContext.user)
-                .setOverrideGroupKey("")
-                .build()
-        whenever(personNotificationIdentifier.getPeopleNotificationType(a))
-                .thenReturn(TYPE_PERSON)
-
-        val bN = Notification.Builder(mContext, "test")
-                .setStyle(Notification.MessagingStyle(""))
-                .build()
-        val b = NotificationEntryBuilder()
-                .setImportance(IMPORTANCE_HIGH)
-                .setPkg("pkg2")
-                .setOpPkg("pkg2")
-                .setTag("tag")
-                .setNotification(bN)
-                .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
-                .setUser(mContext.user)
-                .setOverrideGroupKey("")
-                .build()
-        whenever(personNotificationIdentifier.getPeopleNotificationType(b))
-                .thenReturn(TYPE_IMPORTANT_PERSON)
-
-        whenever(personNotificationIdentifier.compareTo(TYPE_PERSON, TYPE_IMPORTANT_PERSON))
-                .thenReturn(TYPE_IMPORTANT_PERSON.compareTo(TYPE_PERSON))
-        whenever(personNotificationIdentifier.compareTo(TYPE_IMPORTANT_PERSON, TYPE_PERSON))
-                .thenReturn(TYPE_PERSON.compareTo(TYPE_IMPORTANT_PERSON))
-
-        assertEquals(
-                listOf(b, a),
-                rankingManager.updateRanking(null, listOf(a, b), "test"))
-    }
-
-    @Test
-    fun testSort_fullPeople() {
-        whenever(sectionsManager.isFilteringEnabled()).thenReturn(true)
-        val aN = Notification.Builder(mContext, "test")
-                .setStyle(Notification.MessagingStyle(""))
-                .build()
-        val a = NotificationEntryBuilder()
-                .setImportance(IMPORTANCE_HIGH)
-                .setPkg("pkg")
-                .setOpPkg("pkg")
-                .setTag("tag")
-                .setNotification(aN)
-                .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
-                .setUser(mContext.user)
-                .setOverrideGroupKey("")
-                .build()
-        whenever(personNotificationIdentifier.getPeopleNotificationType(a))
-                .thenReturn(TYPE_PERSON)
-
-        val bN = Notification.Builder(mContext, "test")
-                .setStyle(Notification.MessagingStyle(""))
-                .build()
-        val b = NotificationEntryBuilder()
-                .setImportance(IMPORTANCE_HIGH)
-                .setPkg("pkg2")
-                .setOpPkg("pkg2")
-                .setTag("tag")
-                .setNotification(bN)
-                .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
-                .setUser(mContext.user)
-                .setOverrideGroupKey("")
-                .build()
-        whenever(personNotificationIdentifier.getPeopleNotificationType(b))
-                .thenReturn(TYPE_FULL_PERSON)
-
-        whenever(personNotificationIdentifier.compareTo(TYPE_PERSON, TYPE_FULL_PERSON))
-                .thenReturn(TYPE_FULL_PERSON.compareTo(TYPE_PERSON))
-        whenever(personNotificationIdentifier.compareTo(TYPE_FULL_PERSON, TYPE_PERSON))
-                .thenReturn(TYPE_PERSON.compareTo(TYPE_FULL_PERSON))
-
-        assertEquals(
-                listOf(b, a),
-                rankingManager.updateRanking(null, listOf(a, b), "test"))
-    }
-
-    @Test
-    fun testSort_properlySetsAlertingBucket() {
-        val notif = Notification.Builder(mContext, "test") .build()
-
-        val e = NotificationEntryBuilder()
-                .setPkg("pkg")
-                .setOpPkg("pkg")
-                .setTag("tag")
-                .setNotification(notif)
-                .setUser(mContext.user)
-                .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
-                .setOverrideGroupKey("")
-                .build()
-
-        modifyRanking(e).setImportance(IMPORTANCE_DEFAULT).build()
-
-        rankingManager.updateRanking(RankingMap(arrayOf(e.ranking)), listOf(e), "test")
-        assertEquals(e.bucket, BUCKET_ALERTING)
-    }
-
-    @Test
-    fun testSort_properlySetsSilentBucket() {
-        val notif = Notification.Builder(mContext, "test") .build()
-
-        val e = NotificationEntryBuilder()
-                .setPkg("pkg")
-                .setOpPkg("pkg")
-                .setTag("tag")
-                .setNotification(notif)
-                .setUser(mContext.user)
-                .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
-                .setOverrideGroupKey("")
-                .build()
-
-        modifyRanking(e).setImportance(IMPORTANCE_LOW).build()
-
-        rankingManager.updateRanking(RankingMap(arrayOf(e.ranking)), listOf(e), "test")
-        assertEquals(e.bucket, BUCKET_SILENT)
-    }
-
-    @Test
-    fun testFilter_resetsInitalizationTime() {
-        // GIVEN an entry that was initialized 1 second ago
-        val notif = Notification.Builder(mContext, "test") .build()
-
-        val e = NotificationEntryBuilder()
-            .setPkg("pkg")
-            .setOpPkg("pkg")
-            .setTag("tag")
-            .setNotification(notif)
-            .setUser(mContext.user)
-            .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
-            .setOverrideGroupKey("")
-            .build()
-
-        e.setInitializationTime(SystemClock.elapsedRealtime() - 1000)
-        assertEquals(true, e.hasFinishedInitialization())
-
-        // WHEN we update ranking and filter out the notification entry
-        whenever(notificationFilter.shouldFilterOut(e)).thenReturn(true)
-        rankingManager.updateRanking(RankingMap(arrayOf(e.ranking)), listOf(e), "test")
-
-        // THEN the initialization time for the entry is reset
-        assertEquals(false, e.hasFinishedInitialization())
-    }
-
-    @Test
-    fun testSort_colorizedForegroundService() {
-        whenever(sectionsManager.isFilteringEnabled()).thenReturn(true)
-
-        val a = NotificationEntryBuilder()
-                .setImportance(IMPORTANCE_HIGH)
-                .setPkg("pkg")
-                .setOpPkg("pkg")
-                .setTag("tag")
-                .setNotification(
-                        Notification.Builder(mContext, "test")
-                                .build())
-                .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
-                .setUser(mContext.getUser())
-                .setOverrideGroupKey("")
-                .build()
-
-        val b = NotificationEntryBuilder()
-                .setImportance(IMPORTANCE_DEFAULT) // high priority
-                .setPkg("pkg2")
-                .setOpPkg("pkg2")
-                .setTag("tag")
-                .setNotification(mock(Notification::class.java).also { notif ->
-                    whenever(notif.isForegroundService).thenReturn(true)
-                    whenever(notif.isColorized).thenReturn(true)
-                })
-                .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
-                .setUser(mContext.getUser())
-                .setOverrideGroupKey("")
-                .build()
-
-        val cN = Notification.Builder(mContext, "test")
-                .setStyle(Notification.MessagingStyle(""))
-                .build()
-        val c = NotificationEntryBuilder()
-                .setImportance(IMPORTANCE_HIGH)
-                .setPkg("pkg")
-                .setOpPkg("pkg")
-                .setTag("tag")
-                .setNotification(cN)
-                .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
-                .setUser(mContext.user)
-                .setOverrideGroupKey("")
-                .build()
-        whenever(personNotificationIdentifier.getPeopleNotificationType(a))
-                .thenReturn(TYPE_IMPORTANT_PERSON)
-
-        assertThat(rankingManager.updateRanking(null, listOf(a, b, c), "test"))
-                .containsExactly(b, c, a)
-        assertThat(b.bucket).isEqualTo(BUCKET_FOREGROUND_SERVICE)
-    }
-
-    @Test
-    fun testSort_importantCall() {
-        whenever(sectionsManager.isFilteringEnabled()).thenReturn(true)
-
-        val a = NotificationEntryBuilder()
-                .setImportance(IMPORTANCE_HIGH)
-                .setPkg("pkg")
-                .setOpPkg("pkg")
-                .setTag("tag")
-                .setNotification(
-                        Notification.Builder(mContext, "test")
-                                .build())
-                .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
-                .setUser(mContext.getUser())
-                .setOverrideGroupKey("")
-                .build()
-
-        val b = NotificationEntryBuilder()
-                .setImportance(IMPORTANCE_DEFAULT) // high priority
-                .setPkg("pkg2")
-                .setOpPkg("pkg2")
-                .setTag("tag")
-                .setNotification(mock(Notification::class.java).also { notif ->
-                    whenever(notif.isForegroundService).thenReturn(true)
-                    whenever(notif.isColorized).thenReturn(true)
-                })
-                .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
-                .setUser(mContext.getUser())
-                .setOverrideGroupKey("")
-                .build()
-
-        val cN = Notification.Builder(mContext, "test")
-                .setStyle(Notification.MessagingStyle(""))
-                .build()
-        val c = NotificationEntryBuilder()
-                .setImportance(IMPORTANCE_HIGH)
-                .setPkg("pkg")
-                .setOpPkg("pkg")
-                .setTag("tag")
-                .setNotification(cN)
-                .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
-                .setUser(mContext.user)
-                .setOverrideGroupKey("")
-                .build()
-
-        val dN = Notification.Builder(mContext, "test")
-                .setStyle(Notification.CallStyle.forOngoingCall(
-                        Person.Builder().setName("caller").build(),
-                        mock(PendingIntent::class.java)))
-                .build()
-        val d = NotificationEntryBuilder()
-                .setImportance(IMPORTANCE_DEFAULT) // high priority
-                .setPkg("pkg2")
-                .setOpPkg("pkg2")
-                .setTag("tag")
-                .setNotification(dN)
-                .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
-                .setUser(mContext.user)
-                .setOverrideGroupKey("")
-                .build()
-        whenever(personNotificationIdentifier.getPeopleNotificationType(a))
-                .thenReturn(TYPE_IMPORTANT_PERSON)
-
-        assertThat(rankingManager.updateRanking(null, listOf(a, b, c, d), "test"))
-                .containsExactly(b, d, c, a)
-        assertThat(d.bucket).isEqualTo(BUCKET_FOREGROUND_SERVICE)
-    }
-
-    internal class TestableNotificationRankingManager(
-        mediaManager: Lazy<NotificationMediaManager>,
-        groupManager: NotificationGroupManagerLegacy,
-        headsUpManager: HeadsUpManager,
-        filter: NotificationFilter,
-        logger: NotificationEntryManagerLogger,
-        sectionsFeatureManager: NotificationSectionsFeatureManager,
-        peopleNotificationIdentifier: PeopleNotificationIdentifier,
-        highPriorityProvider: HighPriorityProvider,
-        keyguardEnvironment: KeyguardEnvironment
-    ) : NotificationRankingManager(
-        mediaManager,
-        groupManager,
-        headsUpManager,
-        filter,
-        logger,
-        sectionsFeatureManager,
-        peopleNotificationIdentifier,
-        highPriorityProvider,
-        keyguardEnvironment
-    ) {
-        fun applyTestRankingMap(r: RankingMap) {
-            rankingMap = r
-        }
-    }
-}
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 dfa38ab..9f21409 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
@@ -68,6 +68,7 @@
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifStabilityManager;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable;
 import com.android.systemui.statusbar.notification.collection.notifcollection.CollectionReadyForBuildListener;
 import com.android.systemui.util.time.FakeSystemClock;
 
@@ -1715,66 +1716,201 @@
         assertEquals(GroupEntry.ROOT_ENTRY, group.getPreviousParent());
     }
 
-    @Test(expected = IllegalStateException.class)
-    public void testOutOfOrderPreGroupFilterInvalidationThrows() {
-        // GIVEN a PreGroupNotifFilter that gets invalidated during the grouping stage
-        NotifFilter filter = new PackageFilter(PACKAGE_5);
-        OnBeforeTransformGroupsListener listener = (list) -> filter.invalidateList(null);
+    static class CountingInvalidator {
+        CountingInvalidator(Pluggable pluggableToInvalidate) {
+            mPluggableToInvalidate = pluggableToInvalidate;
+            mInvalidationCount = 0;
+        }
+
+        public void setInvalidationCount(int invalidationCount) {
+            mInvalidationCount = invalidationCount;
+        }
+
+        public void maybeInvalidate() {
+            if (mInvalidationCount > 0) {
+                mPluggableToInvalidate.invalidateList("test invalidation");
+                mInvalidationCount--;
+            }
+        }
+
+        private Pluggable mPluggableToInvalidate;
+        private int mInvalidationCount;
+
+        private static final String TAG = "ShadeListBuilderTestCountingInvalidator";
+    }
+
+    @Test
+    public void testOutOfOrderPreGroupFilterInvalidationDoesNotThrowBeforeTooManyRuns() {
+        // GIVEN a PreGroupNotifFilter that gets invalidated during the grouping stage,
+        NotifFilter filter = new PackageFilter(PACKAGE_1);
+        CountingInvalidator invalidator = new CountingInvalidator(filter);
+        OnBeforeTransformGroupsListener listener = (list) -> invalidator.maybeInvalidate();
         mListBuilder.addPreGroupFilter(filter);
         mListBuilder.addOnBeforeTransformGroupsListener(listener);
 
-        // WHEN we try to run the pipeline and the filter is invalidated
-        addNotif(0, PACKAGE_1);
+        // 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);
         dispatchBuild();
+        runWhileScheduledUpTo(ShadeListBuilder.MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
 
-        // THEN an exception is thrown
+        // THEN an exception is NOT thrown.
     }
 
     @Test(expected = IllegalStateException.class)
-    public void testOutOfOrderPrompterInvalidationThrows() {
-        // GIVEN a NotifPromoter that gets invalidated during the sorting stage
+    public void testOutOfOrderPreGroupFilterInvalidationThrowsAfterTooManyRuns() {
+        // GIVEN a PreGroupNotifFilter that gets invalidated during the grouping stage,
+        NotifFilter filter = new PackageFilter(PACKAGE_1);
+        CountingInvalidator invalidator = new CountingInvalidator(filter);
+        OnBeforeTransformGroupsListener listener = (list) -> invalidator.maybeInvalidate();
+        mListBuilder.addPreGroupFilter(filter);
+        mListBuilder.addOnBeforeTransformGroupsListener(listener);
+
+        // 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);
+        dispatchBuild();
+        runWhileScheduledUpTo(ShadeListBuilder.MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+
+        // THEN an exception IS thrown.
+    }
+
+    @Test
+    public void testNonConsecutiveOutOfOrderInvalidationDontThrowAfterTooManyRuns() {
+        // GIVEN a PreGroupNotifFilter that gets invalidated during the grouping stage,
+        NotifFilter filter = new PackageFilter(PACKAGE_1);
+        CountingInvalidator invalidator = new CountingInvalidator(filter);
+        OnBeforeTransformGroupsListener listener = (list) -> invalidator.maybeInvalidate();
+        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);
+
+        // THEN an exception is NOT thrown.
+    }
+
+    @Test
+    public void testOutOfOrderPrompterInvalidationDoesNotThrowBeforeTooManyRuns() {
+        // GIVEN a NotifPromoter that gets invalidated during the sorting stage,
         NotifPromoter promoter = new IdPromoter(47);
-        OnBeforeSortListener listener =
-                (list) -> promoter.invalidateList(null);
+        CountingInvalidator invalidator = new CountingInvalidator(promoter);
+        OnBeforeSortListener listener = (list) -> invalidator.maybeInvalidate();
         mListBuilder.addPromoter(promoter);
         mListBuilder.addOnBeforeSortListener(listener);
 
-        // WHEN we try to run the pipeline and the promoter is invalidated
+        // 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);
         dispatchBuild();
+        runWhileScheduledUpTo(ShadeListBuilder.MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
 
-        // THEN an exception is thrown
+        // THEN an exception is NOT thrown.
     }
 
     @Test(expected = IllegalStateException.class)
-    public void testOutOfOrderComparatorInvalidationThrows() {
-        // GIVEN a NotifComparator that gets invalidated during the finalizing stage
-        NotifComparator comparator = new HypeComparator(PACKAGE_5);
-        OnBeforeRenderListListener listener =
-                (list) -> comparator.invalidateList(null);
+    public void testOutOfOrderPrompterInvalidationThrowsAfterTooManyRuns() {
+        // GIVEN a NotifPromoter that gets invalidated during the sorting stage,
+        NotifPromoter promoter = new IdPromoter(47);
+        CountingInvalidator invalidator = new CountingInvalidator(promoter);
+        OnBeforeSortListener listener = (list) -> invalidator.maybeInvalidate();
+        mListBuilder.addPromoter(promoter);
+        mListBuilder.addOnBeforeSortListener(listener);
+
+        // 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);
+        dispatchBuild();
+        runWhileScheduledUpTo(ShadeListBuilder.MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+
+        // THEN an exception IS thrown.
+    }
+
+    @Test
+    public void testOutOfOrderComparatorInvalidationDoesNotThrowBeforeTooManyRuns() {
+        // GIVEN a NotifComparator that gets invalidated during the finalizing stage,
+        NotifComparator comparator = new HypeComparator(PACKAGE_1);
+        CountingInvalidator invalidator = new CountingInvalidator(comparator);
+        OnBeforeRenderListListener listener = (list) -> invalidator.maybeInvalidate();
         mListBuilder.setComparators(singletonList(comparator));
         mListBuilder.addOnBeforeRenderListListener(listener);
 
-        // WHEN we try to run the pipeline and the comparator is invalidated
-        addNotif(0, PACKAGE_1);
+        // 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);
         dispatchBuild();
+        runWhileScheduledUpTo(ShadeListBuilder.MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
 
-        // THEN an exception is thrown
+        // THEN an exception is NOT thrown.
     }
 
     @Test(expected = IllegalStateException.class)
-    public void testOutOfOrderPreRenderFilterInvalidationThrows() {
-        // GIVEN a PreRenderNotifFilter that gets invalidated during the finalizing stage
-        NotifFilter filter = new PackageFilter(PACKAGE_5);
-        OnBeforeRenderListListener listener = (list) -> filter.invalidateList(null);
+    public void testOutOfOrderComparatorInvalidationThrowsAfterTooManyRuns() {
+        // GIVEN a NotifComparator that gets invalidated during the finalizing stage,
+        NotifComparator comparator = new HypeComparator(PACKAGE_1);
+        CountingInvalidator invalidator = new CountingInvalidator(comparator);
+        OnBeforeRenderListListener listener = (list) -> invalidator.maybeInvalidate();
+        mListBuilder.setComparators(singletonList(comparator));
+        mListBuilder.addOnBeforeRenderListListener(listener);
+
+        // 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);
+        dispatchBuild();
+        runWhileScheduledUpTo(ShadeListBuilder.MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+
+        // THEN an exception IS thrown.
+    }
+
+    @Test
+    public void testOutOfOrderPreRenderFilterInvalidationDoesNotThrowBeforeTooManyRuns() {
+        // GIVEN a PreRenderNotifFilter that gets invalidated during the finalizing stage,
+        NotifFilter filter = new PackageFilter(PACKAGE_1);
+        CountingInvalidator invalidator = new CountingInvalidator(filter);
+        OnBeforeRenderListListener listener = (list) -> invalidator.maybeInvalidate();
         mListBuilder.addFinalizeFilter(filter);
         mListBuilder.addOnBeforeRenderListListener(listener);
 
-        // WHEN we try to run the pipeline and the PreRenderFilter is invalidated
-        addNotif(0, PACKAGE_1);
+        // 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);
         dispatchBuild();
+        runWhileScheduledUpTo(ShadeListBuilder.MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
 
-        // THEN an exception is thrown
+        // THEN an exception is NOT thrown.
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testOutOfOrderPreRenderFilterInvalidationThrowsAfterTooManyRuns() {
+        // GIVEN a PreRenderNotifFilter that gets invalidated during the finalizing stage,
+        NotifFilter filter = new PackageFilter(PACKAGE_1);
+        CountingInvalidator invalidator = new CountingInvalidator(filter);
+        OnBeforeRenderListListener listener = (list) -> invalidator.maybeInvalidate();
+        mListBuilder.addFinalizeFilter(filter);
+        mListBuilder.addOnBeforeRenderListListener(listener);
+
+        // 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);
+        dispatchBuild();
+        runWhileScheduledUpTo(ShadeListBuilder.MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+
+        // THEN an exception IS thrown.
     }
 
     @Test
@@ -2096,6 +2232,18 @@
         mPipelineChoreographer.runIfScheduled();
     }
 
+    private void runWhileScheduledUpTo(int maxRuns) {
+        int runs = 0;
+        while (mPipelineChoreographer.isScheduled()) {
+            if (runs > maxRuns) {
+                throw new IndexOutOfBoundsException(
+                        "Pipeline scheduled itself more than " + maxRuns + "times");
+            }
+            runs++;
+            mPipelineChoreographer.runIfScheduled();
+        }
+    }
+
     private void verifyBuiltList(ExpectedEntry ...expectedEntries) {
         try {
             assertEquals(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java
index 541749b4..d59cc54 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.notification.interruption;
 
+import static android.app.Notification.VISIBILITY_PRIVATE;
 import static android.app.Notification.VISIBILITY_PUBLIC;
 import static android.app.Notification.VISIBILITY_SECRET;
 import static android.app.NotificationManager.IMPORTANCE_HIGH;
@@ -449,6 +450,54 @@
     }
 
     @Test
+    public void notificationVisibilityPublic() {
+        // GIVEN a VISIBILITY_PUBLIC notification
+        NotificationEntryBuilder entryBuilder = new NotificationEntryBuilder()
+                .setUser(new UserHandle(NOTIF_USER_ID));
+        entryBuilder.modifyNotification(mContext)
+                .setVisibility(VISIBILITY_PUBLIC);
+        mEntry = entryBuilder.build();
+
+        // WHEN we're in an 'unfiltered-keyguard-showing' state
+        setupUnfilteredState(mEntry);
+
+        // THEN don't hide the entry based on visibility.
+        assertFalse(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
+    }
+
+    @Test
+    public void notificationVisibilityPrivate() {
+        // GIVEN a VISIBILITY_PRIVATE notification
+        NotificationEntryBuilder entryBuilder = new NotificationEntryBuilder()
+                .setUser(new UserHandle(NOTIF_USER_ID));
+        entryBuilder.modifyNotification(mContext)
+                .setVisibility(VISIBILITY_PRIVATE);
+        mEntry = entryBuilder.build();
+
+        // WHEN we're in an 'unfiltered-keyguard-showing' state
+        setupUnfilteredState(mEntry);
+
+        // THEN don't hide the entry based on visibility. (Redaction is handled elsewhere.)
+        assertFalse(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
+    }
+
+    @Test
+    public void notificationVisibilitySecret() {
+        // GIVEN a VISIBILITY_SECRET notification
+        NotificationEntryBuilder entryBuilder = new NotificationEntryBuilder()
+                .setUser(new UserHandle(NOTIF_USER_ID));
+        entryBuilder.modifyNotification(mContext)
+                .setVisibility(VISIBILITY_SECRET);
+        mEntry = entryBuilder.build();
+
+        // WHEN we're in an 'unfiltered-keyguard-showing' state
+        setupUnfilteredState(mEntry);
+
+        // THEN hide the entry based on visibility.
+        assertTrue(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
+    }
+
+    @Test
     public void summaryExceedsThresholdToShow() {
         // GIVEN the notification doesn't exceed the threshold to show on the lockscreen
         // but it's part of a group (has a parent)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
index e00e20f..46f630b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
@@ -33,9 +33,7 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -57,7 +55,6 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.NotifPipelineFlags;
-import com.android.systemui.statusbar.notification.NotificationFilter;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.policy.BatteryController;
@@ -85,8 +82,6 @@
     @Mock
     AmbientDisplayConfiguration mAmbientDisplayConfiguration;
     @Mock
-    NotificationFilter mNotificationFilter;
-    @Mock
     StatusBarStateController mStatusBarStateController;
     @Mock
     KeyguardStateController mKeyguardStateController;
@@ -131,20 +126,10 @@
 
     /**
      * Sets up the state such that any requests to
-     * {@link NotificationInterruptStateProviderImpl#canAlertCommon(NotificationEntry)} will
-     * pass as long its provided NotificationEntry fulfills group suppression check.
-     */
-    private void ensureStateForAlertCommon() {
-        when(mNotificationFilter.shouldFilterOut(any())).thenReturn(false);
-    }
-
-    /**
-     * Sets up the state such that any requests to
      * {@link NotificationInterruptStateProviderImpl#shouldHeadsUp(NotificationEntry)} will
      * pass as long its provided NotificationEntry fulfills importance & DND checks.
      */
     private void ensureStateForHeadsUpWhenAwake() throws RemoteException {
-        ensureStateForAlertCommon();
         when(mHeadsUpManager.isSnoozed(any())).thenReturn(false);
 
         when(mStatusBarStateController.isDozing()).thenReturn(false);
@@ -158,21 +143,10 @@
      * pass as long its provided NotificationEntry fulfills importance & DND checks.
      */
     private void ensureStateForHeadsUpWhenDozing() {
-        ensureStateForAlertCommon();
-
         when(mStatusBarStateController.isDozing()).thenReturn(true);
         when(mAmbientDisplayConfiguration.pulseOnNotificationEnabled(anyInt())).thenReturn(true);
     }
 
-    /**
-     * Sets up the state such that any requests to
-     * {@link NotificationInterruptStateProviderImpl#shouldBubbleUp(NotificationEntry)} will
-     * pass as long its provided NotificationEntry fulfills importance & bubble checks.
-     */
-    private void ensureStateForBubbleUp() {
-        ensureStateForAlertCommon();
-    }
-
     @Test
     public void testDefaultSuppressorDoesNotSuppress() {
         // GIVEN a suppressor without any overrides
@@ -201,27 +175,6 @@
     }
 
     @Test
-    public void testShouldNotHeadsUpAwake_flteredOut() throws RemoteException {
-        // GIVEN state for "heads up when awake" is true
-        ensureStateForHeadsUpWhenAwake();
-
-        // WHEN this entry should be filtered out
-        NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
-        when(mNotificationFilter.shouldFilterOut(entry)).thenReturn(true);
-
-        // THEN we shouldn't heads up this entry
-        assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
-    }
-
-    @Test
-    public void testDoNotRunFilterOnNewPipeline() {
-        // WHEN this entry should be filtered out
-        NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
-        mNotifInterruptionStateProvider.shouldHeadsUp(entry);
-        verify(mNotificationFilter, times(0)).shouldFilterOut(eq(entry));
-    }
-
-    @Test
     public void testShouldNotHeadsUp_suppressedForGroups() throws RemoteException {
         // GIVEN state for "heads up when awake" is true
         ensureStateForHeadsUpWhenAwake();
@@ -654,7 +607,6 @@
      */
     @Test
     public void testShouldBubbleUp() {
-        ensureStateForBubbleUp();
         assertThat(mNotifInterruptionStateProvider.shouldBubbleUp(createBubble())).isTrue();
     }
 
@@ -664,7 +616,6 @@
      */
     @Test
     public void testShouldBubbleUp_notifInGroupWithOnlySummaryAlerts() {
-        ensureStateForBubbleUp();
         NotificationEntry bubble = createBubble("testgroup", GROUP_ALERT_SUMMARY);
         assertThat(mNotifInterruptionStateProvider.shouldBubbleUp(bubble)).isTrue();
     }
@@ -674,8 +625,6 @@
      */
     @Test
     public void shouldNotBubbleUp_notAllowedToBubble() {
-        ensureStateForBubbleUp();
-
         NotificationEntry entry = createBubble();
         modifyRanking(entry)
                 .setCanBubble(false)
@@ -689,8 +638,6 @@
      */
     @Test
     public void shouldNotBubbleUp_notABubble() {
-        ensureStateForBubbleUp();
-
         NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
         modifyRanking(entry)
                 .setCanBubble(true)
@@ -704,8 +651,6 @@
      */
     @Test
     public void shouldNotBubbleUp_invalidMetadata() {
-        ensureStateForBubbleUp();
-
         NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
         modifyRanking(entry)
                 .setCanBubble(true)
@@ -717,8 +662,6 @@
 
     @Test
     public void shouldNotBubbleUp_suppressedInterruptions() {
-        ensureStateForBubbleUp();
-
         // If the notification can't heads up in general, it shouldn't bubble.
         mNotifInterruptionStateProvider.addSuppressor(mSuppressInterruptions);
 
@@ -727,8 +670,6 @@
 
     @Test
     public void shouldNotBubbleUp_filteredOut() {
-        ensureStateForBubbleUp();
-
         // Make canAlertCommon false by saying it's filtered out
         when(mKeyguardNotificationVisibilityProvider.shouldHideNotification(any()))
                 .thenReturn(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
index 381d72f..90adabf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
@@ -236,7 +236,6 @@
     @Test
     public void testBindNotification_SetsShortcutIcon() {
         mNotificationInfo.bindNotification(
-                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mPeopleSpaceWidgetManager,
@@ -261,7 +260,6 @@
     public void testBindNotification_SetsTextApplicationName() {
         when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name");
         mNotificationInfo.bindNotification(
-                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mPeopleSpaceWidgetManager,
@@ -314,7 +312,6 @@
         mConversationChannel.setGroup(group.getId());
 
         mNotificationInfo.bindNotification(
-                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mPeopleSpaceWidgetManager,
@@ -340,7 +337,6 @@
     @Test
     public void testBindNotification_GroupNameHiddenIfNoGroup() {
         mNotificationInfo.bindNotification(
-                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mPeopleSpaceWidgetManager,
@@ -365,7 +361,6 @@
     @Test
     public void testBindNotification_noDelegate() {
         mNotificationInfo.bindNotification(
-                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mPeopleSpaceWidgetManager,
@@ -401,7 +396,6 @@
                 .setShortcutInfo(mShortcutInfo)
                 .build();
         mNotificationInfo.bindNotification(
-                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mPeopleSpaceWidgetManager,
@@ -427,7 +421,6 @@
     public void testBindNotification_SetsOnClickListenerForSettings() {
         final CountDownLatch latch = new CountDownLatch(1);
         mNotificationInfo.bindNotification(
-                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mPeopleSpaceWidgetManager,
@@ -457,7 +450,6 @@
     @Test
     public void testBindNotification_SettingsButtonInvisibleWhenNoClickListener() {
         mNotificationInfo.bindNotification(
-                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mPeopleSpaceWidgetManager,
@@ -482,7 +474,6 @@
     public void testBindNotification_SettingsButtonInvisibleWhenDeviceUnprovisioned() {
         final CountDownLatch latch = new CountDownLatch(1);
         mNotificationInfo.bindNotification(
-                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mPeopleSpaceWidgetManager,
@@ -511,7 +502,6 @@
         mConversationChannel.setImportance(IMPORTANCE_LOW);
         mConversationChannel.setImportantConversation(true);
         mNotificationInfo.bindNotification(
-                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mPeopleSpaceWidgetManager,
@@ -540,7 +530,6 @@
         mConversationChannel.setImportantConversation(false);
         mConversationChannel.setAllowBubbles(true);
         mNotificationInfo.bindNotification(
-                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mPeopleSpaceWidgetManager,
@@ -572,7 +561,6 @@
         mConversationChannel.setImportantConversation(false);
         mConversationChannel.setAllowBubbles(true);
         mNotificationInfo.bindNotification(
-                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mPeopleSpaceWidgetManager,
@@ -610,7 +598,6 @@
         mConversationChannel.setImportantConversation(false);
         mConversationChannel.setAllowBubbles(false);
         mNotificationInfo.bindNotification(
-                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mPeopleSpaceWidgetManager,
@@ -639,7 +626,6 @@
         mConversationChannel.setImportantConversation(false);
         mConversationChannel.setAllowBubbles(false);
         mNotificationInfo.bindNotification(
-                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mPeopleSpaceWidgetManager,
@@ -675,7 +661,6 @@
         mConversationChannel.setImportantConversation(false);
         mConversationChannel.setAllowBubbles(true);
         mNotificationInfo.bindNotification(
-                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mPeopleSpaceWidgetManager,
@@ -704,7 +689,6 @@
         mConversationChannel.setImportantConversation(false);
 
         mNotificationInfo.bindNotification(
-                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mPeopleSpaceWidgetManager,
@@ -735,7 +719,7 @@
                 .isEqualTo(GONE);
 
         // no changes until hit done
-        assertFalse(mNotificationInfo.shouldBeSaved());
+        assertFalse(mNotificationInfo.shouldBeSavedOnClose());
         verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
                 anyString(), anyInt(), any());
         assertFalse(mConversationChannel.isImportantConversation());
@@ -749,7 +733,6 @@
         mConversationChannel.setImportance(IMPORTANCE_LOW);
         mConversationChannel.setImportantConversation(false);
         mNotificationInfo.bindNotification(
-                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mPeopleSpaceWidgetManager,
@@ -779,7 +762,7 @@
                 .isEqualTo(GONE);
 
         // no changes until hit done
-        assertFalse(mNotificationInfo.shouldBeSaved());
+        assertFalse(mNotificationInfo.shouldBeSavedOnClose());
         verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
                 anyString(), anyInt(), any());
         assertFalse(mConversationChannel.isImportantConversation());
@@ -793,7 +776,6 @@
         mConversationChannel.setImportantConversation(false);
 
         mNotificationInfo.bindNotification(
-                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mPeopleSpaceWidgetManager,
@@ -825,7 +807,7 @@
                 .isEqualTo(VISIBLE);
 
         // no changes until save
-        assertFalse(mNotificationInfo.shouldBeSaved());
+        assertFalse(mNotificationInfo.shouldBeSavedOnClose());
         verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
                 anyString(), anyInt(), any());
         assertEquals(IMPORTANCE_DEFAULT, mConversationChannel.getImportance());
@@ -838,7 +820,6 @@
         mConversationChannel.setImportantConversation(false);
 
         mNotificationInfo.bindNotification(
-                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mPeopleSpaceWidgetManager,
@@ -868,6 +849,7 @@
         assertTrue(captor.getValue().isImportantConversation());
         assertTrue(captor.getValue().canBubble());
         assertEquals(IMPORTANCE_DEFAULT, captor.getValue().getImportance());
+        assertFalse(mNotificationInfo.shouldBeSavedOnClose());
     }
 
     @Test
@@ -876,7 +858,6 @@
         mConversationChannel.setImportance(9);
 
         mNotificationInfo.bindNotification(
-                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mPeopleSpaceWidgetManager,
@@ -913,7 +894,6 @@
         mConversationChannel.setImportantConversation(true);
 
         mNotificationInfo.bindNotification(
-                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mPeopleSpaceWidgetManager,
@@ -954,7 +934,6 @@
 
         // WHEN we indicate no selected action
         mNotificationInfo.bindNotification(
-                -1, // no action selected by default
                 mShortcutManager,
                 mMockPackageManager,
                 mPeopleSpaceWidgetManager,
@@ -984,8 +963,8 @@
         mConversationChannel.setImportantConversation(false);
 
         // WHEN we indicate the selected action should be "Favorite"
+        mNotificationInfo.setSelectedAction(NotificationConversationInfo.ACTION_FAVORITE);
         mNotificationInfo.bindNotification(
-                NotificationConversationInfo.ACTION_FAVORITE, // "Favorite" selected by default
                 mShortcutManager,
                 mMockPackageManager,
                 mPeopleSpaceWidgetManager,
@@ -1015,7 +994,6 @@
         mConversationChannel.setOriginalImportance(IMPORTANCE_HIGH);
         mConversationChannel.setImportantConversation(true);
         mNotificationInfo.bindNotification(
-                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mPeopleSpaceWidgetManager,
@@ -1044,6 +1022,7 @@
         assertFalse(captor.getValue().isImportantConversation());
         assertFalse(captor.getValue().canBubble());
         assertEquals(IMPORTANCE_HIGH, captor.getValue().getImportance());
+        assertFalse(mNotificationInfo.shouldBeSavedOnClose());
     }
 
     @Test
@@ -1052,7 +1031,6 @@
         mConversationChannel.setOriginalImportance(IMPORTANCE_HIGH);
         mConversationChannel.setImportantConversation(false);
         mNotificationInfo.bindNotification(
-                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mPeopleSpaceWidgetManager,
@@ -1089,7 +1067,6 @@
         mConversationChannel.setOriginalImportance(IMPORTANCE_HIGH);
 
         mNotificationInfo.bindNotification(
-                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mPeopleSpaceWidgetManager,
@@ -1125,7 +1102,6 @@
         mConversationChannel.setAllowBubbles(true);
 
         mNotificationInfo.bindNotification(
-                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mPeopleSpaceWidgetManager,
@@ -1155,12 +1131,46 @@
         assertFalse(captor.getValue().isImportantConversation());
         assertFalse(captor.getValue().canBubble());
         assertEquals(IMPORTANCE_LOW, captor.getValue().getImportance());
+        assertFalse(mNotificationInfo.shouldBeSavedOnClose());
+    }
+
+    @Test
+    public void testSilence_closeGutsThenTryToSave() {
+        mConversationChannel.setImportance(IMPORTANCE_DEFAULT);
+        mConversationChannel.setImportantConversation(true);
+        mConversationChannel.setAllowBubbles(true);
+
+        mNotificationInfo.bindNotification(
+                mShortcutManager,
+                mMockPackageManager,
+                mPeopleSpaceWidgetManager,
+                mMockINotificationManager,
+                mOnUserInteractionCallback,
+                TEST_PACKAGE_NAME,
+                mNotificationChannel,
+                mEntry,
+                mBubbleMetadata,
+                null,
+                mIconFactory,
+                mContext,
+                true,
+                mTestHandler,
+                mTestHandler, null, Optional.of(mBubblesManager),
+                mShadeController);
+
+        mNotificationInfo.findViewById(R.id.silence).performClick();
+        mNotificationInfo.handleCloseControls(false, false);
+        mNotificationInfo.findViewById(R.id.done).performClick();
+
+        mTestableLooper.processAllMessages();
+
+        assertEquals(IMPORTANCE_DEFAULT, mConversationChannel.getImportance());
+        assertFalse(mNotificationInfo.shouldBeSavedOnClose());
     }
 
     @Test
     public void testBindNotification_createsNewChannel() throws Exception {
         mNotificationInfo.bindNotification(
-                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mPeopleSpaceWidgetManager,
@@ -1186,7 +1196,6 @@
     public void testBindNotification_doesNotCreateNewChannelIfExists() throws Exception {
         mNotificationChannel.setConversationId("", CONVERSATION_ID);
         mNotificationInfo.bindNotification(
-                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mPeopleSpaceWidgetManager,
@@ -1213,7 +1222,6 @@
         //WHEN channel is default importance
         mNotificationChannel.setImportantConversation(false);
         mNotificationInfo.bindNotification(
-                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mPeopleSpaceWidgetManager,
@@ -1244,7 +1252,6 @@
     @Test
     public void testSelectDefaultDoesNotRequestPinPeopleTile() {
         mNotificationInfo.bindNotification(
-                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mPeopleSpaceWidgetManager,
@@ -1279,7 +1286,6 @@
         mConversationChannel.setImportantConversation(true);
 
         mNotificationInfo.bindNotification(
-                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mPeopleSpaceWidgetManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
index f57c409..b6a1bb3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
@@ -26,7 +26,6 @@
 import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking;
 
 import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.assertTrue;
 
 import static org.junit.Assert.assertEquals;
@@ -37,7 +36,6 @@
 import static org.mockito.ArgumentMatchers.anySet;
 import static org.mockito.ArgumentMatchers.eq;
 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.times;
@@ -77,7 +75,6 @@
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.notification.AssistantFeedbackController;
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
@@ -88,7 +85,6 @@
 import com.android.systemui.wmshell.BubblesManager;
 
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -128,7 +124,6 @@
     @Mock private AccessibilityManager mAccessibilityManager;
     @Mock private HighPriorityProvider mHighPriorityProvider;
     @Mock private INotificationManager mINotificationManager;
-    @Mock private NotificationEntryManager mNotificationEntryManager;
     @Mock private LauncherApps mLauncherApps;
     @Mock private ShortcutManager mShortcutManager;
     @Mock private ChannelEditorDialogController mChannelEditorDialogController;
@@ -160,7 +155,7 @@
                 mPeopleSpaceWidgetManager, mLauncherApps, mShortcutManager,
                 mChannelEditorDialogController, mContextTracker, mAssistantFeedbackController,
                 Optional.of(mBubblesManager), new UiEventLoggerFake(), mOnUserInteractionCallback,
-                mShadeController, mock(DumpManager.class));
+                mShadeController);
         mGutsManager.setUpWithPresenter(mPresenter, mNotificationListContainer,
                 mOnSettingsClickListener);
         mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter);
@@ -446,36 +441,6 @@
                 eq(mAssistantFeedbackController));
     }
 
-    @Test
-    public void testShouldExtendLifetime() {
-        NotificationGuts guts = new NotificationGuts(mContext);
-        ExpandableNotificationRow row = spy(createTestNotificationRow());
-        doReturn(guts).when(row).getGuts();
-        NotificationEntry entry = row.getEntry();
-        entry.setRow(row);
-        mGutsManager.setExposedGuts(guts);
-
-        assertTrue(mGutsManager.shouldExtendLifetime(entry));
-    }
-
-    @Test
-    @Ignore
-    public void testSetShouldManageLifetime_setShouldManage() {
-        NotificationEntry entry = createTestNotificationRow().getEntry();
-        mGutsManager.setShouldManageLifetime(entry, true /* shouldManage */);
-
-        assertTrue(entry.getKey().equals(mGutsManager.mKeyToRemoveOnGutsClosed));
-    }
-
-    @Test
-    public void testSetShouldManageLifetime_setShouldNotManage() {
-        NotificationEntry entry = createTestNotificationRow().getEntry();
-        mGutsManager.mKeyToRemoveOnGutsClosed = entry.getKey();
-        mGutsManager.setShouldManageLifetime(entry, false /* shouldManage */);
-
-        assertNull(mGutsManager.mKeyToRemoveOnGutsClosed);
-    }
-
     ////////////////////////////////////////////////////////////////////////////////////////////////
     // Utility methods:
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsTest.kt
new file mode 100644
index 0000000..e696c87
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsTest.kt
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.row
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
+import android.testing.ViewUtils
+import android.view.LayoutInflater
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper
+class NotificationGutsTest : SysuiTestCase() {
+
+    private lateinit var guts: NotificationGuts
+    private lateinit var gutsContentView: View
+
+    @Mock
+    private lateinit var gutsContent: NotificationGuts.GutsContent
+
+    @Mock
+    private lateinit var gutsClosedListener: NotificationGuts.OnGutsClosedListener
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        val layoutInflater = LayoutInflater.from(mContext)
+        guts = layoutInflater.inflate(R.layout.notification_guts, null) as NotificationGuts
+        gutsContentView = View(mContext)
+
+        whenever(gutsContent.contentView).thenReturn(gutsContentView)
+
+        ViewUtils.attachView(guts)
+    }
+
+    @After
+    fun tearDown() {
+        ViewUtils.detachView(guts)
+    }
+
+    @Test
+    fun setGutsContent() {
+        guts.gutsContent = gutsContent
+
+        verify(gutsContent).setGutsParent(guts)
+    }
+
+    @Test
+    fun openControls() {
+        guts.gutsContent = gutsContent
+
+        guts.openControls(true, 0, 0, false, null)
+    }
+
+    @Test
+    fun closeControlsWithSave() {
+        guts.gutsContent = gutsContent
+        guts.setClosedListener(gutsClosedListener)
+
+        guts.closeControls(gutsContentView, true)
+
+        verify(gutsContent).handleCloseControls(true, false)
+        verify(gutsClosedListener).onGutsClosed(guts)
+    }
+
+    @Test
+    fun closeControlsWithoutSave() {
+        guts.gutsContent = gutsContent
+        guts.setClosedListener(gutsClosedListener)
+
+        guts.closeControls(gutsContentView, false)
+
+        verify(gutsContent).handleCloseControls(false, false)
+        verify(gutsClosedListener).onGutsClosed(guts)
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
index b1f1075..80a81a5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
@@ -50,6 +50,7 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.graphics.drawable.Drawable;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
 import android.telecom.TelecomManager;
@@ -1090,6 +1091,7 @@
                 mUiEventLogger.eventId(0));
         assertEquals(NotificationControlsEvent.NOTIFICATION_CONTROLS_SAVE_IMPORTANCE.getId(),
                 mUiEventLogger.eventId(1));
+        assertFalse(mNotificationInfo.shouldBeSavedOnClose());
     }
 
     @Test
@@ -1124,6 +1126,7 @@
         assertTrue((updated.getValue().getUserLockedFields()
                 & USER_LOCKED_IMPORTANCE) != 0);
         assertEquals(IMPORTANCE_DEFAULT, updated.getValue().getImportance());
+        assertFalse(mNotificationInfo.shouldBeSavedOnClose());
     }
 
     @Test
@@ -1156,6 +1159,7 @@
         verify(mMockINotificationManager, times(1)).unlockNotificationChannel(
                 anyString(), eq(TEST_UID), any());
         assertEquals(IMPORTANCE_DEFAULT, mNotificationChannel.getImportance());
+        assertFalse(mNotificationInfo.shouldBeSavedOnClose());
     }
 
     @Test
@@ -1191,6 +1195,7 @@
         assertTrue((updated.getValue().getUserLockedFields()
                 & USER_LOCKED_IMPORTANCE) != 0);
         assertEquals(IMPORTANCE_LOW, updated.getValue().getImportance());
+        assertFalse(mNotificationInfo.shouldBeSavedOnClose());
     }
 
     @Test
@@ -1229,6 +1234,37 @@
                 anyString(), eq(TEST_UID), updated.capture());
         assertTrue((updated.getValue().getUserLockedFields() & USER_LOCKED_IMPORTANCE) != 0);
         assertEquals(IMPORTANCE_MIN, updated.getValue().getImportance());
+        assertFalse(mNotificationInfo.shouldBeSavedOnClose());
+    }
+
+    @Test
+    public void testSilence_closeGutsThenTryToSave() throws RemoteException {
+        mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
+        mNotificationInfo.bindNotification(
+                mMockPackageManager,
+                mMockINotificationManager,
+                mOnUserInteractionCallback,
+                mChannelEditorDialogController,
+                TEST_PACKAGE_NAME,
+                mNotificationChannel,
+                mNotificationChannelSet,
+                mEntry,
+                null,
+                null,
+                mUiEventLogger,
+                true,
+                false,
+                false,
+                mAssistantFeedbackController);
+
+        mNotificationInfo.findViewById(R.id.silence).performClick();
+        mNotificationInfo.handleCloseControls(false, false);
+        mNotificationInfo.handleCloseControls(true, false);
+
+        mTestableLooper.processAllMessages();
+
+        assertEquals(IMPORTANCE_DEFAULT, mNotificationChannel.getImportance());
+        assertFalse(mNotificationInfo.shouldBeSavedOnClose());
     }
 
     @Test
@@ -1267,6 +1303,7 @@
                 anyString(), eq(TEST_UID), updated.capture());
         assertTrue((updated.getValue().getUserLockedFields() & USER_LOCKED_IMPORTANCE) != 0);
         assertEquals(IMPORTANCE_DEFAULT, updated.getValue().getImportance());
+        assertFalse(mNotificationInfo.shouldBeSavedOnClose());
     }
 
     @Test
@@ -1294,6 +1331,7 @@
         mNotificationInfo.handleCloseControls(true, false);
 
         verify(mOnUserInteractionCallback).onImportanceChanged(mEntry);
+        assertFalse(mNotificationInfo.shouldBeSavedOnClose());
     }
 
     @Test
@@ -1360,6 +1398,7 @@
         assertTrue((updated.getValue().getUserLockedFields()
                 & USER_LOCKED_IMPORTANCE) != 0);
         assertEquals(IMPORTANCE_DEFAULT, updated.getValue().getImportance());
+        assertFalse(mNotificationInfo.shouldBeSavedOnClose());
     }
 
     @Test
@@ -1450,7 +1489,7 @@
 
         mNotificationInfo.findViewById(R.id.alert).performClick();
 
-        assertFalse(mNotificationInfo.shouldBeSaved());
+        assertFalse(mNotificationInfo.shouldBeSavedOnClose());
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index 38bd078..66821dd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -51,7 +51,6 @@
 import com.android.systemui.TestableDependency;
 import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.classifier.FalsingManagerFake;
-import com.android.systemui.dump.DumpManager;
 import com.android.systemui.media.MediaFeatureFlag;
 import com.android.systemui.media.dialog.MediaOutputDialogFactory;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -62,10 +61,11 @@
 import com.android.systemui.statusbar.notification.ConversationNotificationProcessor;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
 import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
 import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
+import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
+import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
 import com.android.systemui.statusbar.notification.icon.IconBuilder;
 import com.android.systemui.statusbar.notification.icon.IconManager;
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
@@ -84,7 +84,6 @@
 import com.android.systemui.tests.R;
 import com.android.systemui.wmshell.BubblesManager;
 import com.android.systemui.wmshell.BubblesTestActivity;
-import com.android.wm.shell.bubbles.Bubbles;
 
 import org.mockito.ArgumentCaptor;
 
@@ -112,8 +111,8 @@
     private final Context mContext;
     private final TestableLooper mTestLooper;
     private int mId;
-    private final NotificationGroupManagerLegacy mGroupMembershipManager;
-    private final NotificationGroupManagerLegacy mGroupExpansionManager;
+    private final GroupMembershipManager mGroupMembershipManager;
+    private final GroupExpansionManager mGroupExpansionManager;
     private ExpandableNotificationRow mRow;
     private HeadsUpManagerPhone mHeadsUpManager;
     private final NotifBindPipeline mBindPipeline;
@@ -136,24 +135,19 @@
         dependency.injectMockDependency(NotificationShadeWindowController.class);
         dependency.injectMockDependency(MediaOutputDialogFactory.class);
         mStatusBarStateController = mock(StatusBarStateController.class);
-        mGroupMembershipManager = new NotificationGroupManagerLegacy(
-                mStatusBarStateController,
-                () -> mock(PeopleNotificationIdentifier.class),
-                Optional.of((mock(Bubbles.class))),
-                mock(DumpManager.class));
-        mGroupExpansionManager = mGroupMembershipManager;
+        mGroupMembershipManager = mock(GroupMembershipManager.class);
+        mGroupExpansionManager = mock(GroupExpansionManager.class);
         mHeadsUpManager = new HeadsUpManagerPhone(
                 mContext,
                 mock(HeadsUpManagerLogger.class),
                 mStatusBarStateController,
                 mock(KeyguardBypassController.class),
-                mock(NotificationGroupManagerLegacy.class),
+                mock(GroupMembershipManager.class),
                 mock(VisualStabilityProvider.class),
                 mock(ConfigurationControllerImpl.class)
         );
         mHeadsUpManager.mHandler.removeCallbacksAndMessages(null);
         mHeadsUpManager.mHandler = new Handler(mTestLooper.getLooper());
-        mGroupMembershipManager.setHeadsUpManager(mHeadsUpManager);
         mIconManager = new IconManager(
                 mock(CommonNotifCollection.class),
                 mock(LauncherApps.class),
@@ -529,10 +523,6 @@
         mBindStage.getStageParams(entry).requireContentViews(extraInflationFlags);
         inflateAndWait(entry);
 
-        // This would be done as part of onAsyncInflationFinished, but we skip large amounts of
-        // the callback chain, so we need to make up for not adding it to the group manager
-        // here.
-        mGroupMembershipManager.onEntryAdded(entry);
         return row;
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
index 43aa8fe..12c8fd5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.statusbar.notification.row;
 
-import static android.app.Notification.EXTRA_IS_GROUP_CONVERSATION;
 import static android.app.NotificationManager.IMPORTANCE_LOW;
 import static android.print.PrintManager.PRINT_SPOOLER_PACKAGE_NAME;
 import static android.view.View.GONE;
@@ -25,7 +24,6 @@
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertTrue;
 
-import static org.mockito.ArgumentMatchers.anyObject;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyBoolean;
 import static org.mockito.Mockito.anyInt;
@@ -36,8 +34,6 @@
 import android.app.INotificationManager;
 import android.app.Notification;
 import android.app.NotificationChannel;
-import android.app.NotificationChannelGroup;
-import android.app.Person;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
index ac9fcc0..9d848e8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
@@ -18,24 +18,7 @@
 
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 
-import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_ALERTING;
-import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_FOREGROUND_SERVICE;
-import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_HEADS_UP;
-import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_PEOPLE;
-import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_SILENT;
-
-import static com.google.common.truth.Truth.assertThat;
-
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
-import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.testing.AndroidTestingRunner;
@@ -50,28 +33,19 @@
 import com.android.systemui.media.KeyguardMediaController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.render.MediaContainerController;
 import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController;
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationViewController;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.InOrder;
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
-import java.util.ArrayList;
-import java.util.List;
-
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
@@ -84,15 +58,11 @@
     @Mock private ConfigurationController mConfigurationController;
     @Mock private KeyguardMediaController mKeyguardMediaController;
     @Mock private NotificationSectionsFeatureManager mSectionsFeatureManager;
-    @Mock private NotificationRowComponent mNotificationRowComponent;
-    @Mock private ActivatableNotificationViewController mActivatableNotificationViewController;
-    @Mock private NotificationSectionsLogger mLogger;
     @Mock private MediaContainerController mMediaContainerController;
     @Mock private SectionHeaderController mIncomingHeaderController;
     @Mock private SectionHeaderController mPeopleHeaderController;
     @Mock private SectionHeaderController mAlertingHeaderController;
     @Mock private SectionHeaderController mSilentHeaderController;
-    @Mock private NotifPipelineFlags mNotifPipelineFlags;
 
     private NotificationSectionsManager mSectionsManager;
 
@@ -113,22 +83,11 @@
                     }
                     return count;
                 });
-        when(mNotificationRowComponent.getActivatableNotificationViewController())
-                .thenReturn(mActivatableNotificationViewController);
-        when(mMediaContainerController.getMediaContainerView())
-                .thenReturn(mock(MediaContainerView.class));
-        when(mIncomingHeaderController.getHeaderView()).thenReturn(mock(SectionHeaderView.class));
-        when(mPeopleHeaderController.getHeaderView()).thenReturn(mock(SectionHeaderView.class));
-        when(mAlertingHeaderController.getHeaderView()).thenReturn(mock(SectionHeaderView.class));
-        when(mSilentHeaderController.getHeaderView()).thenReturn(mock(SectionHeaderView.class));
         mSectionsManager =
                 new NotificationSectionsManager(
-                        mStatusBarStateController,
                         mConfigurationController,
                         mKeyguardMediaController,
                         mSectionsFeatureManager,
-                        mLogger,
-                        mNotifPipelineFlags,
                         mMediaContainerController,
                         mIncomingHeaderController,
                         mPeopleHeaderController,
@@ -141,7 +100,6 @@
         mSectionsManager.initialize(mNssl);
         when(mNssl.indexOfChild(any(View.class))).thenReturn(-1);
         when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
-
     }
 
     @Test(expected =  IllegalStateException.class)
@@ -149,641 +107,4 @@
         mSectionsManager.initialize(mNssl);
     }
 
-    @Test
-    public void testInsertHeader() {
-        // GIVEN a stack with HI and LO rows but no section headers
-        setStackState(
-                ALERTING,
-                ALERTING,
-                ALERTING,
-                GENTLE);
-
-        // WHEN we update the section headers
-        mSectionsManager.updateSectionBoundaries();
-
-        // THEN a LO section header is added
-        verify(mNssl).addView(mSectionsManager.getSilentHeaderView(), 3);
-    }
-
-    @Test
-    public void testRemoveHeader() {
-        // GIVEN a stack that originally had a header between the HI and LO sections
-        setStackState(
-                ALERTING,
-                ALERTING,
-                GENTLE);
-        mSectionsManager.updateSectionBoundaries();
-
-        // WHEN the last LO row is replaced with a HI row
-        setStackState(
-                ALERTING,
-                ALERTING,
-                GENTLE_HEADER,
-                ALERTING);
-        clearInvocations(mNssl);
-        mSectionsManager.updateSectionBoundaries();
-
-        // THEN the LO section header is removed
-        verify(mNssl).removeView(mSectionsManager.getSilentHeaderView());
-    }
-
-    @Test
-    public void testDoNothingIfHeaderAlreadyRemoved() {
-        // GIVEN a stack with only HI rows
-        setStackState(
-                ALERTING,
-                ALERTING,
-                ALERTING);
-
-        // WHEN we update the sections headers
-        mSectionsManager.updateSectionBoundaries();
-
-        // THEN we don't add any section headers
-        verify(mNssl, never()).addView(eq(mSectionsManager.getSilentHeaderView()), anyInt());
-    }
-
-    @Test
-    public void testMoveHeaderForward() {
-        // GIVEN a stack that originally had a header between the HI and LO sections
-        setStackState(
-                ALERTING,
-                ALERTING,
-                ALERTING,
-                GENTLE);
-        mSectionsManager.updateSectionBoundaries();
-
-        // WHEN the LO section moves forward
-        setStackState(
-                ALERTING,
-                ALERTING,
-                GENTLE,
-                GENTLE_HEADER,
-                GENTLE);
-        mSectionsManager.updateSectionBoundaries();
-
-        // THEN the LO section header is also moved forward
-        verify(mNssl).changeViewPosition(mSectionsManager.getSilentHeaderView(), 2);
-    }
-
-    @Test
-    public void testMoveHeaderBackward() {
-        // GIVEN a stack that originally had a header between the HI and LO sections
-        setStackState(
-                ALERTING,
-                GENTLE,
-                GENTLE,
-                GENTLE);
-        mSectionsManager.updateSectionBoundaries();
-
-        // WHEN the LO section moves backward
-        setStackState(
-                ALERTING,
-                GENTLE_HEADER,
-                ALERTING,
-                ALERTING,
-                GENTLE);
-        mSectionsManager.updateSectionBoundaries();
-
-        // THEN the LO section header is also moved backward (with appropriate index shifting)
-        verify(mNssl).changeViewPosition(mSectionsManager.getSilentHeaderView(), 3);
-    }
-
-    @Test
-    public void testHeaderRemovedFromTransientParent() {
-        // GIVEN a stack where the header is animating away
-        setStackState(
-                ALERTING,
-                GENTLE_HEADER);
-        mSectionsManager.updateSectionBoundaries();
-        clearInvocations(mNssl);
-
-        SectionHeaderView silentHeaderView = mSectionsManager.getSilentHeaderView();
-        ViewGroup transientParent = mock(ViewGroup.class);
-        when(silentHeaderView.getTransientContainer()).thenReturn(transientParent);
-
-        // WHEN the LO section reappears
-        setStackState(
-                ALERTING,
-                GENTLE);
-        mSectionsManager.updateSectionBoundaries();
-
-        // THEN the header is first removed from the transient parent before being added to the
-        // NSSL.
-        final InOrder inOrder = inOrder(silentHeaderView, mNssl);
-        inOrder.verify(silentHeaderView).removeFromTransientContainer();
-        inOrder.verify(mNssl).addView(eq(silentHeaderView), eq(1));
-    }
-
-    @Test
-    public void testHeaderNotShownOnLockscreen() {
-        // GIVEN a stack of HI and LO notifs on the lockscreen
-        when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
-        setStackState(
-                ALERTING,
-                ALERTING,
-                ALERTING,
-                GENTLE);
-
-        // WHEN we update the section headers
-        mSectionsManager.updateSectionBoundaries();
-
-        // Then the section header is not added
-        verify(mNssl, never()).addView(eq(mSectionsManager.getSilentHeaderView()), anyInt());
-    }
-
-    @Test
-    public void testHeaderShownWhenEnterLockscreen() {
-        // GIVEN a stack of HI and LO notifs on the lockscreen
-        when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
-        setStackState(
-                ALERTING,
-                ALERTING,
-                ALERTING,
-                GENTLE);
-        mSectionsManager.updateSectionBoundaries();
-
-        // WHEN we unlock
-        when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
-        mSectionsManager.updateSectionBoundaries();
-
-        // Then the section header is added
-        verify(mNssl).addView(mSectionsManager.getSilentHeaderView(), 3);
-    }
-
-    @Test
-    public void testHeaderHiddenWhenEnterLockscreen() {
-        // GIVEN a stack of HI and LO notifs on the shade
-        setStackState(
-                ALERTING,
-                GENTLE_HEADER,
-                GENTLE);
-
-        // WHEN we go back to the keyguard
-        when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
-        mSectionsManager.updateSectionBoundaries();
-
-        // Then the section header is removed
-        verify(mNssl).removeView(mSectionsManager.getSilentHeaderView());
-    }
-
-    @Test
-    public void testPeopleFiltering_onlyAddSilentHeader() {
-        enablePeopleFiltering();
-
-        setStackState(
-                PERSON,
-                ALERTING,
-                GENTLE);
-        mSectionsManager.updateSectionBoundaries();
-
-        verify(mNssl).addView(mSectionsManager.getSilentHeaderView(), 2);
-    }
-
-    @Test
-    public void testPeopleFiltering_AlertingHunWhilePeopleVisible() {
-        enablePeopleFiltering();
-
-        setupMockStack(
-                PEOPLE_HEADER,
-                ALERTING,
-                PERSON,
-                ALERTING_HEADER,
-                GENTLE_HEADER,
-                GENTLE
-        );
-        mSectionsManager.updateSectionBoundaries();
-
-        verifyMockStack(
-                ChildType.HEADS_UP,
-                ChildType.PERSON,
-                ChildType.GENTLE_HEADER,
-                ChildType.GENTLE
-        );
-    }
-
-    @Test
-    public void testPeopleFiltering_PersonHunWhileAlertingHunVisible() {
-        enablePeopleFiltering();
-
-        setupMockStack(
-                PERSON,
-                INCOMING_HEADER,
-                ALERTING,
-                PEOPLE_HEADER,
-                PERSON
-        );
-        mSectionsManager.updateSectionBoundaries();
-
-        verifyMockStack(
-                ChildType.HEADS_UP,
-                ChildType.HEADS_UP,
-                ChildType.PERSON
-        );
-    }
-
-    @Test
-    public void testPeopleFiltering_PersonHun() {
-        enablePeopleFiltering();
-
-        setupMockStack(
-                PERSON,
-                PEOPLE_HEADER,
-                PERSON
-        );
-        mSectionsManager.updateSectionBoundaries();
-
-        verifyMockStack(
-                ChildType.PERSON,
-                ChildType.PERSON
-        );
-    }
-
-    @Test
-    public void testPeopleFiltering_AlertingHunWhilePersonHunning() {
-        enablePeopleFiltering();
-
-        setupMockStack(
-                ALERTING,
-                PERSON
-        );
-        mSectionsManager.updateSectionBoundaries();
-        verifyMockStack(
-                ChildType.HEADS_UP,
-                ChildType.PERSON
-        );
-    }
-
-    @Test
-    public void testPeopleFiltering_Fsn() {
-        enablePeopleFiltering();
-
-        setupMockStack(
-                INCOMING_HEADER,
-                ALERTING,
-                PEOPLE_HEADER,
-                FSN,
-                PERSON,
-                ALERTING,
-                GENTLE
-        );
-        mSectionsManager.updateSectionBoundaries();
-
-        verifyMockStack(
-                ChildType.HEADS_UP,
-                ChildType.FSN,
-                ChildType.PERSON,
-                ChildType.ALERTING,
-                ChildType.GENTLE_HEADER,
-                ChildType.GENTLE
-        );
-    }
-
-    @Test
-    public void testMediaControls_AddWhenEnterKeyguard() {
-        enableMediaControls();
-
-        // GIVEN a stack that doesn't include media controls
-        setStackState(ALERTING, GENTLE_HEADER, GENTLE);
-
-        // WHEN we go back to the keyguard
-        when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
-        mSectionsManager.updateSectionBoundaries();
-
-        // Then the media controls are added
-        verify(mNssl).addView(mSectionsManager.getMediaControlsView(), 0);
-    }
-
-    @Test
-    public void testMediaControls_AddWhenEnterKeyguardWithHeadsUp() {
-        enableMediaControls();
-
-        // GIVEN a stack that doesn't include media
-        setupMockStack(
-                ALERTING,
-                ALERTING,
-                GENTLE_HEADER,
-                GENTLE);
-
-        // WHEN we go back to the keyguard
-        when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
-        mSectionsManager.updateSectionBoundaries();
-
-        verifyMockStack(
-                ChildType.MEDIA_CONTROLS,
-                ChildType.ALERTING,
-                ChildType.ALERTING,
-                ChildType.GENTLE);
-    }
-
-    @Test
-    public void testRemoveNonSilentHeader() {
-        enablePeopleFiltering();
-        enableMediaControls();
-
-        setupMockStack(
-                MEDIA_CONTROLS,
-                INCOMING_HEADER,
-                PERSON,
-                ALERTING,
-                PEOPLE_HEADER,
-                ALERTING_HEADER,
-                ALERTING,
-                ALERTING,
-                GENTLE_HEADER,
-                GENTLE,
-                GENTLE
-        );
-
-        mSectionsManager.updateSectionBoundaries();
-
-        verifyMockStack(
-                ChildType.MEDIA_CONTROLS,
-                ChildType.PERSON,
-                ChildType.ALERTING,
-                ChildType.ALERTING,
-                ChildType.ALERTING,
-                ChildType.GENTLE_HEADER,
-                ChildType.GENTLE,
-                ChildType.GENTLE
-        );
-    }
-
-    @Test
-    public void testExpandIncomingSection() {
-        enablePeopleFiltering();
-
-        setupMockStack(
-                INCOMING_HEADER,
-                PERSON,
-                ALERTING,
-                PEOPLE_HEADER,
-                ALERTING,
-                PERSON,
-                ALERTING_HEADER,
-                ALERTING
-        );
-
-        mSectionsManager.updateSectionBoundaries();
-
-        verifyMockStack(
-                ChildType.HEADS_UP,
-                ChildType.HEADS_UP,
-                ChildType.HEADS_UP,
-                ChildType.PERSON,
-                ChildType.ALERTING
-        );
-    }
-
-    @Test
-    public void testIgnoreGoneView() {
-        enablePeopleFiltering();
-
-        setupMockStack(
-                PERSON.gone(),
-                ALERTING,
-                GENTLE
-        );
-
-        mSectionsManager.updateSectionBoundaries();
-
-        verifyMockStack(
-                ChildType.PERSON,
-                ChildType.ALERTING,
-                ChildType.GENTLE_HEADER,
-                ChildType.GENTLE
-        );
-    }
-
-    private void enablePeopleFiltering() {
-        when(mSectionsFeatureManager.isFilteringEnabled()).thenReturn(true);
-    }
-
-    private void enableMediaControls() {
-        when(mSectionsFeatureManager.isMediaControlsEnabled()).thenReturn(true);
-    }
-
-    private enum ChildType {
-        INCOMING_HEADER, MEDIA_CONTROLS, PEOPLE_HEADER, ALERTING_HEADER, GENTLE_HEADER, HEADS_UP,
-        FSN, PERSON, ALERTING, GENTLE, OTHER
-    }
-
-    private void setStackState(StackEntry... children) {
-        when(mNssl.getChildCount()).thenReturn(children.length);
-        for (int i = 0; i < children.length; i++) {
-            View child;
-            StackEntry entry = children[i];
-            switch (entry.mChildType) {
-                case INCOMING_HEADER:
-                    child = mSectionsManager.getIncomingHeaderView();
-                    break;
-                case MEDIA_CONTROLS:
-                    child = mSectionsManager.getMediaControlsView();
-                    break;
-                case PEOPLE_HEADER:
-                    child = mSectionsManager.getPeopleHeaderView();
-                    break;
-                case ALERTING_HEADER:
-                    child = mSectionsManager.getAlertingHeaderView();
-                    break;
-                case GENTLE_HEADER:
-                    child = mSectionsManager.getSilentHeaderView();
-                    break;
-                case FSN:
-                    child = mockNotification(BUCKET_FOREGROUND_SERVICE, entry.mIsGone);
-                    break;
-                case PERSON:
-                    child = mockNotification(BUCKET_PEOPLE, entry.mIsGone);
-                    break;
-                case ALERTING:
-                    child = mockNotification(BUCKET_ALERTING, entry.mIsGone);
-                    break;
-                case GENTLE:
-                    child = mockNotification(BUCKET_SILENT, entry.mIsGone);
-                    break;
-                case OTHER:
-                    child = mock(View.class);
-                    when(child.getVisibility()).thenReturn(View.VISIBLE);
-                    when(child.getParent()).thenReturn(mNssl);
-                    break;
-                default:
-                    throw new RuntimeException("Unknown ChildType: " + children[i]);
-            }
-            when(mNssl.getChildAt(i)).thenReturn(child);
-            when(mNssl.indexOfChild(child)).thenReturn(i);
-        }
-    }
-
-    private View mockNotification(@PriorityBucket int bucket, boolean isGone) {
-        ExpandableNotificationRow notifRow =
-                mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS);
-        when(notifRow.getVisibility()).thenReturn(View.VISIBLE);
-        when(notifRow.getParent()).thenReturn(mNssl);
-
-        NotificationEntry mockEntry = mock(NotificationEntry.class);
-        when(notifRow.getEntry()).thenReturn(mockEntry);
-
-        int[] bucketRef = new int[] { bucket };
-        when(mockEntry.getBucket()).thenAnswer(invocation -> bucketRef[0]);
-        doAnswer(invocation -> {
-            bucketRef[0] = invocation.getArgument(0);
-            return null;
-        }).when(mockEntry).setBucket(anyInt());
-
-        when(notifRow.getVisibility()).thenReturn(isGone ? View.GONE : View.VISIBLE);
-        return notifRow;
-    }
-
-    private void verifyMockStack(ChildType... expected) {
-        final List<ChildType> actual = new ArrayList<>();
-        int childCount = mNssl.getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View child = mNssl.getChildAt(i);
-            if (child == mSectionsManager.getIncomingHeaderView()) {
-                actual.add(ChildType.INCOMING_HEADER);
-                continue;
-            }
-            if (child == mSectionsManager.getMediaControlsView()) {
-                actual.add(ChildType.MEDIA_CONTROLS);
-                continue;
-            }
-            if (child == mSectionsManager.getPeopleHeaderView()) {
-                actual.add(ChildType.PEOPLE_HEADER);
-                continue;
-            }
-            if (child == mSectionsManager.getAlertingHeaderView()) {
-                actual.add(ChildType.ALERTING_HEADER);
-                continue;
-            }
-            if (child == mSectionsManager.getSilentHeaderView()) {
-                actual.add(ChildType.GENTLE_HEADER);
-                continue;
-            }
-            if (child instanceof ExpandableNotificationRow) {
-                switch (((ExpandableNotificationRow) child).getEntry().getBucket()) {
-                    case BUCKET_HEADS_UP:
-                        actual.add(ChildType.HEADS_UP);
-                        break;
-                    case BUCKET_FOREGROUND_SERVICE:
-                        actual.add(ChildType.FSN);
-                        break;
-                    case BUCKET_PEOPLE:
-                        actual.add(ChildType.PERSON);
-                        break;
-                    case BUCKET_ALERTING:
-                        actual.add(ChildType.ALERTING);
-                        break;
-                    case BUCKET_SILENT:
-                        actual.add(ChildType.GENTLE);
-                        break;
-                    default:
-                        actual.add(ChildType.OTHER);
-                        break;
-                }
-                continue;
-            }
-            actual.add(ChildType.OTHER);
-        }
-        assertThat(actual).containsExactly((Object[]) expected).inOrder();
-    }
-
-    private void setupMockStack(StackEntry... entries) {
-        final List<View> children = new ArrayList<>();
-        when(mNssl.getChildCount()).thenAnswer(invocation -> children.size());
-        when(mNssl.getChildAt(anyInt()))
-                .thenAnswer(invocation -> {
-                    Integer index = invocation.getArgument(0);
-                    if (index == null || index < 0 || index >= children.size()) {
-                        return null;
-                    }
-                    return children.get(index);
-                });
-        when(mNssl.indexOfChild(any()))
-                .thenAnswer(invocation -> children.indexOf(invocation.getArgument(0)));
-        doAnswer(invocation -> {
-            View child = invocation.getArgument(0);
-            int index = invocation.getArgument(1);
-            children.add(index, child);
-            return null;
-        }).when(mNssl).addView(any(), anyInt());
-        doAnswer(invocation -> {
-            View child = invocation.getArgument(0);
-            children.remove(child);
-            return null;
-        }).when(mNssl).removeView(any());
-        doAnswer(invocation -> {
-            View child = invocation.getArgument(0);
-            int newIndex = invocation.getArgument(1);
-            children.remove(child);
-            children.add(newIndex, child);
-            return null;
-        }).when(mNssl).changeViewPosition(any(), anyInt());
-        for (StackEntry entry : entries) {
-            View child;
-            switch (entry.mChildType) {
-                case INCOMING_HEADER:
-                    child = mSectionsManager.getIncomingHeaderView();
-                    break;
-                case MEDIA_CONTROLS:
-                    child = mSectionsManager.getMediaControlsView();
-                    break;
-                case PEOPLE_HEADER:
-                    child = mSectionsManager.getPeopleHeaderView();
-                    break;
-                case ALERTING_HEADER:
-                    child = mSectionsManager.getAlertingHeaderView();
-                    break;
-                case GENTLE_HEADER:
-                    child = mSectionsManager.getSilentHeaderView();
-                    break;
-                case FSN:
-                    child = mockNotification(BUCKET_FOREGROUND_SERVICE, entry.mIsGone);
-                    break;
-                case PERSON:
-                    child = mockNotification(BUCKET_PEOPLE, entry.mIsGone);
-                    break;
-                case ALERTING:
-                    child = mockNotification(BUCKET_ALERTING, entry.mIsGone);
-                    break;
-                case GENTLE:
-                    child = mockNotification(BUCKET_SILENT, entry.mIsGone);
-                    break;
-                case OTHER:
-                    child = mock(View.class);
-                    when(child.getVisibility()).thenReturn(View.VISIBLE);
-                    when(child.getParent()).thenReturn(mNssl);
-                    break;
-                default:
-                    throw new RuntimeException("Unknown ChildType: " + entry.mChildType);
-            }
-            children.add(child);
-        }
-    }
-
-    private static final StackEntry INCOMING_HEADER = new StackEntry(ChildType.INCOMING_HEADER);
-    private static final StackEntry MEDIA_CONTROLS = new StackEntry(ChildType.MEDIA_CONTROLS);
-    private static final StackEntry PEOPLE_HEADER = new StackEntry(ChildType.PEOPLE_HEADER);
-    private static final StackEntry ALERTING_HEADER = new StackEntry(ChildType.ALERTING_HEADER);
-    private static final StackEntry GENTLE_HEADER = new StackEntry(ChildType.GENTLE_HEADER);
-    private static final StackEntry FSN = new StackEntry(ChildType.FSN);
-    private static final StackEntry PERSON = new StackEntry(ChildType.PERSON);
-    private static final StackEntry ALERTING = new StackEntry(ChildType.ALERTING);
-    private static final StackEntry GENTLE = new StackEntry(ChildType.GENTLE);
-
-    private static class StackEntry {
-        final ChildType mChildType;
-        final boolean mIsGone;
-
-        StackEntry(ChildType childType) {
-            this(childType, false);
-        }
-
-        StackEntry(ChildType childType, boolean isGone) {
-            mChildType = childType;
-            mIsGone = isGone;
-        }
-
-        public StackEntry gone() {
-            return new StackEntry(mChildType, true);
-        }
-    }
 }
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 9bcea10..1460e04 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
@@ -67,6 +67,7 @@
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
 import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
 import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
 import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -121,7 +122,8 @@
     @Mock private NotificationSwipeHelper mNotificationSwipeHelper;
     @Mock private CentralSurfaces mCentralSurfaces;
     @Mock private ScrimController mScrimController;
-    @Mock private NotificationGroupManagerLegacy mLegacyGroupManager;
+    @Mock private NotificationGroupManagerLegacy mGroupManagerLegacy;
+    @Mock private GroupExpansionManager mGroupExpansionManager;
     @Mock private SectionHeaderController mSilentHeaderController;
     @Mock private NotifPipelineFlags mNotifPipelineFlags;
     @Mock private NotifPipeline mNotifPipeline;
@@ -174,8 +176,8 @@
                 mNotificationSwipeHelperBuilder,
                 mCentralSurfaces,
                 mScrimController,
-                mLegacyGroupManager,
-                mLegacyGroupManager,
+                mGroupManagerLegacy,
+                mGroupExpansionManager,
                 mSilentHeaderController,
                 mNotifPipeline,
                 mNotifCollection,
@@ -184,7 +186,6 @@
                 mShadeTransitionController,
                 mUiEventLogger,
                 mRemoteInputManager,
-                mVisualStabilityManager,
                 mShadeController,
                 mJankMonitor,
                 mStackLogger,
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 37a48937..3c22edc 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
@@ -66,7 +66,6 @@
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -101,8 +100,8 @@
     @Rule public MockitoRule mockito = MockitoJUnit.rule();
     @Mock private CentralSurfaces mCentralSurfaces;
     @Mock private SysuiStatusBarStateController mBarState;
-    @Mock private NotificationGroupManagerLegacy mGroupMembershipManger;
-    @Mock private NotificationGroupManagerLegacy mGroupExpansionManager;
+    @Mock private GroupMembershipManager mGroupMembershipManger;
+    @Mock private GroupExpansionManager mGroupExpansionManager;
     @Mock private DumpManager mDumpManager;
     @Mock private ExpandHelper mExpandHelper;
     @Mock private EmptyShadeView mEmptyShadeView;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 7b7f45a..a0f7087 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -418,7 +418,6 @@
                 wakefulnessLifecycle,
                 mStatusBarStateController,
                 Optional.of(mBubbles),
-                mVisualStabilityManager,
                 mDeviceProvisionedController,
                 mNavigationBarController,
                 mAccessibilityFloatingMenuController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
index db5741c..2ab2172 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
@@ -25,7 +25,6 @@
 import android.content.Context;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
-import android.view.View;
 
 import androidx.test.filters.SmallTest;
 
@@ -35,8 +34,8 @@
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
 import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
+import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
@@ -60,19 +59,18 @@
     private HeadsUpManagerPhone mHeadsUpManager;
 
     @Mock private HeadsUpManagerLogger mHeadsUpManagerLogger;
-    @Mock private NotificationGroupManagerLegacy mGroupManager;
-    @Mock private View mNotificationShadeWindowView;
+    @Mock private GroupMembershipManager mGroupManager;
     @Mock private VisualStabilityProvider mVSProvider;
     @Mock private StatusBarStateController mStatusBarStateController;
     @Mock private KeyguardBypassController mBypassController;
     @Mock private ConfigurationControllerImpl mConfigurationController;
     private boolean mLivesPastNormalTime;
 
-    private final class TestableHeadsUpManagerPhone extends HeadsUpManagerPhone {
+    private static final class TestableHeadsUpManagerPhone extends HeadsUpManagerPhone {
         TestableHeadsUpManagerPhone(
                 Context context,
                 HeadsUpManagerLogger headsUpManagerLogger,
-                NotificationGroupManagerLegacy groupManager,
+                GroupMembershipManager groupManager,
                 VisualStabilityProvider visualStabilityProvider,
                 StatusBarStateController statusBarStateController,
                 KeyguardBypassController keyguardBypassController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProviderTest.kt
index 44325dd..a2828d33 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProviderTest.kt
@@ -16,19 +16,28 @@
 
 package com.android.systemui.statusbar.phone
 
+import android.app.WallpaperManager
+import android.app.WallpaperManager.OnColorsChangedListener
 import android.graphics.Color
+import android.os.Handler
+import android.os.Looper
 import android.testing.AndroidTestingRunner
 import android.view.IWindowManager
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Expect
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
+import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mock
+import org.mockito.Mockito.any
+import org.mockito.Mockito.doAnswer
 import org.mockito.Mockito.`when` as whenever
 import org.mockito.MockitoAnnotations
 
@@ -38,17 +47,41 @@
 
     private val fakeSystemClock = FakeSystemClock()
     private val fakeExecutor = FakeExecutor(fakeSystemClock)
+    private val mainHandler = Handler(Looper.getMainLooper())
+
+    @get:Rule var expect: Expect = Expect.create()
 
     @Mock private lateinit var windowManager: IWindowManager
     @Mock private lateinit var dumpManager: DumpManager
+    @Mock private lateinit var wallpaperManager: WallpaperManager
 
     private lateinit var provider: LetterboxBackgroundProvider
 
+    private var wallpaperColorsListener: OnColorsChangedListener? = null
+
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
 
-        provider = LetterboxBackgroundProvider(windowManager, fakeExecutor, dumpManager)
+        setUpWallpaperManager()
+        provider =
+            LetterboxBackgroundProvider(
+                windowManager, fakeExecutor, dumpManager, wallpaperManager, mainHandler)
+    }
+
+    private fun setUpWallpaperManager() {
+        doAnswer { invocation ->
+                wallpaperColorsListener = invocation.arguments[0] as OnColorsChangedListener
+                return@doAnswer Unit
+            }
+            .`when`(wallpaperManager)
+            .addOnColorsChangedListener(any(), eq(mainHandler))
+        doAnswer {
+                wallpaperColorsListener = null
+                return@doAnswer Unit
+            }
+            .`when`(wallpaperManager)
+            .removeOnColorsChangedListener(any(OnColorsChangedListener::class.java))
     }
 
     @Test
@@ -76,6 +109,31 @@
     }
 
     @Test
+    fun letterboxBackgroundColor_returnsValueFromWindowManagerOnlyOnce() {
+        whenever(windowManager.letterboxBackgroundColorInArgb).thenReturn(Color.RED)
+        provider.start()
+        fakeExecutor.runAllReady()
+        expect.that(provider.letterboxBackgroundColor).isEqualTo(Color.RED)
+
+        whenever(windowManager.letterboxBackgroundColorInArgb).thenReturn(Color.GREEN)
+        fakeExecutor.runAllReady()
+        expect.that(provider.letterboxBackgroundColor).isEqualTo(Color.RED)
+    }
+
+    @Test
+    fun letterboxBackgroundColor_afterWallpaperChanges_returnsUpdatedColor() {
+        whenever(windowManager.letterboxBackgroundColorInArgb).thenReturn(Color.RED)
+        provider.start()
+        fakeExecutor.runAllReady()
+
+        whenever(windowManager.letterboxBackgroundColorInArgb).thenReturn(Color.GREEN)
+        wallpaperColorsListener!!.onColorsChanged(null, 0)
+        fakeExecutor.runAllReady()
+
+        assertThat(provider.letterboxBackgroundColor).isEqualTo(Color.GREEN)
+    }
+
+    @Test
     fun isLetterboxBackgroundMultiColored_defaultValue_returnsFalse() {
         assertThat(provider.isLetterboxBackgroundMultiColored).isEqualTo(false)
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
deleted file mode 100644
index 7070bc1..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
+++ /dev/null
@@ -1,494 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.phone;
-
-import static com.android.systemui.statusbar.notification.NotificationEntryManager.UNDEFINED_DISMISS_REASON;
-import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.Notification;
-import android.service.notification.StatusBarNotification;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.notification.NotificationEntryListener;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
-import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
-import com.android.systemui.statusbar.notification.row.NotifBindPipeline.BindCallback;
-import com.android.systemui.statusbar.notification.row.RowContentBindParams;
-import com.android.systemui.statusbar.notification.row.RowContentBindStage;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
-import com.android.wm.shell.bubbles.Bubbles;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-import java.util.HashMap;
-import java.util.Optional;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase {
-    @Rule public MockitoRule rule = MockitoJUnit.rule();
-
-    private NotificationGroupAlertTransferHelper mGroupAlertTransferHelper;
-    private NotificationGroupManagerLegacy mGroupManager;
-    private HeadsUpManager mHeadsUpManager;
-    @Mock private NotificationEntryManager mNotificationEntryManager;
-    @Mock private RowContentBindStage mBindStage;
-    @Mock PeopleNotificationIdentifier mPeopleNotificationIdentifier;
-    @Mock StatusBarStateController mStatusBarStateController;
-    @Captor private ArgumentCaptor<NotificationEntryListener> mListenerCaptor;
-    private NotificationEntryListener mNotificationEntryListener;
-    private final HashMap<String, NotificationEntry> mPendingEntries = new HashMap<>();
-    private final NotificationGroupTestHelper mGroupTestHelper =
-            new NotificationGroupTestHelper(mContext);
-
-
-    @Before
-    public void setup() {
-        MockitoAnnotations.initMocks(this);
-        mHeadsUpManager = new HeadsUpManager(mContext, mock(HeadsUpManagerLogger.class)) {};
-
-        when(mNotificationEntryManager.getPendingNotificationsIterator())
-                .thenReturn(mPendingEntries.values());
-
-        mGroupManager = new NotificationGroupManagerLegacy(
-                mStatusBarStateController,
-                () -> mPeopleNotificationIdentifier,
-                Optional.of(mock(Bubbles.class)),
-                mock(DumpManager.class));
-        mDependency.injectTestDependency(NotificationGroupManagerLegacy.class, mGroupManager);
-        mGroupManager.setHeadsUpManager(mHeadsUpManager);
-
-        when(mBindStage.getStageParams(any())).thenReturn(new RowContentBindParams());
-
-        mGroupAlertTransferHelper = new NotificationGroupAlertTransferHelper(
-                mBindStage, mStatusBarStateController, mGroupManager);
-        mGroupAlertTransferHelper.setHeadsUpManager(mHeadsUpManager);
-
-        mGroupAlertTransferHelper.bind(mNotificationEntryManager, mGroupManager);
-        verify(mNotificationEntryManager).addNotificationEntryListener(mListenerCaptor.capture());
-        mNotificationEntryListener = mListenerCaptor.getValue();
-        mHeadsUpManager.addListener(mGroupAlertTransferHelper);
-    }
-
-    @After
-    public void tearDown() {
-        mHeadsUpManager.mHandler.removeCallbacksAndMessages(null);
-    }
-
-    private void mockHasHeadsUpContentView(NotificationEntry entry,
-            boolean hasHeadsUpContentView) {
-        RowContentBindParams params = new RowContentBindParams();
-        if (hasHeadsUpContentView) {
-            params.requireContentViews(FLAG_CONTENT_VIEW_HEADS_UP);
-        }
-        when(mBindStage.getStageParams(eq(entry))).thenReturn(params);
-    }
-
-    private void mockHasHeadsUpContentView(NotificationEntry entry) {
-        mockHasHeadsUpContentView(entry, true);
-    }
-
-    private void mockIsPriority(NotificationEntry priorityEntry) {
-        when(mPeopleNotificationIdentifier.getPeopleNotificationType(eq(priorityEntry)))
-                .thenReturn(PeopleNotificationIdentifier.TYPE_IMPORTANT_PERSON);
-    }
-
-    @Test
-    public void testSuppressedSummaryHeadsUpTransfersToChild() {
-        NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
-        mHeadsUpManager.showNotification(summaryEntry);
-        NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
-
-        mockHasHeadsUpContentView(childEntry);
-
-        // Summary will be suppressed because there is only one child.
-        mGroupManager.onEntryAdded(summaryEntry);
-        mGroupManager.onEntryAdded(childEntry);
-
-        // A suppressed summary should transfer its alert state to the child.
-        assertFalse(mHeadsUpManager.isAlerting(summaryEntry.getKey()));
-        assertTrue(mHeadsUpManager.isAlerting(childEntry.getKey()));
-    }
-
-    @Test
-    public void testSuppressedSummaryHeadsUpTransfersToChildButBackAgain() {
-        NotificationEntry summaryEntry =
-                mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY);
-        NotificationEntry childEntry =
-                mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
-        NotificationEntry childEntry2 =
-                mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
-        mHeadsUpManager.showNotification(summaryEntry);
-        // Trigger a transfer of alert state from summary to child.
-        mGroupManager.onEntryAdded(summaryEntry);
-        mGroupManager.onEntryAdded(childEntry);
-
-        // Add second child notification so that summary is no longer suppressed.
-        mPendingEntries.put(childEntry2.getKey(), childEntry2);
-        mNotificationEntryListener.onPendingEntryAdded(childEntry2);
-        mGroupManager.onEntryAdded(childEntry2);
-
-        // The alert state should transfer back to the summary as there is now more than one
-        // child and the summary should no longer be suppressed.
-        assertTrue(mHeadsUpManager.isAlerting(summaryEntry.getKey()));
-        assertFalse(mHeadsUpManager.isAlerting(childEntry.getKey()));
-    }
-
-    @Test
-    public void testSuppressedSummaryHeadsUpDoesntTransferBackOnDozingChanged() {
-        NotificationEntry summaryEntry =
-                mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY);
-        NotificationEntry childEntry =
-                mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
-        NotificationEntry childEntry2 =
-                mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
-        mHeadsUpManager.showNotification(summaryEntry);
-        // Trigger a transfer of alert state from summary to child.
-        mGroupManager.onEntryAdded(summaryEntry);
-        mGroupManager.onEntryAdded(childEntry);
-
-        // Set dozing to true.
-        mGroupAlertTransferHelper.onDozingChanged(true);
-
-        // Add second child notification so that summary is no longer suppressed.
-        mPendingEntries.put(childEntry2.getKey(), childEntry2);
-        mNotificationEntryListener.onPendingEntryAdded(childEntry2);
-        mGroupManager.onEntryAdded(childEntry2);
-
-        // Dozing changed so no reason to re-alert summary.
-        assertFalse(mHeadsUpManager.isAlerting(summaryEntry.getKey()));
-    }
-
-    @Test
-    public void testSuppressedSummaryHeadsUpTransferDoesNotAlertChildIfUninflated() {
-        NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
-        mHeadsUpManager.showNotification(summaryEntry);
-        NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
-        mockHasHeadsUpContentView(childEntry, false);
-
-        mGroupManager.onEntryAdded(summaryEntry);
-        mGroupManager.onEntryAdded(childEntry);
-
-        // Alert is immediately removed from summary, but we do not show child yet either as its
-        // content is not inflated.
-        assertFalse(mHeadsUpManager.isAlerting(summaryEntry.getKey()));
-        assertFalse(mHeadsUpManager.isAlerting(childEntry.getKey()));
-        assertTrue(mGroupAlertTransferHelper.isAlertTransferPending(childEntry));
-    }
-
-    @Test
-    public void testSuppressedSummaryHeadsUpTransferAlertsChildOnInflation() {
-        NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
-        mHeadsUpManager.showNotification(summaryEntry);
-        NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
-        mockHasHeadsUpContentView(childEntry, false);
-
-        mGroupManager.onEntryAdded(summaryEntry);
-        mGroupManager.onEntryAdded(childEntry);
-
-        // Child entry finishes its inflation.
-        ArgumentCaptor<BindCallback> callbackCaptor = ArgumentCaptor.forClass(BindCallback.class);
-        verify(mBindStage).requestRebind(eq(childEntry), callbackCaptor.capture());
-        callbackCaptor.getValue().onBindFinished(childEntry);
-
-        // Alert is immediately removed from summary, and we show child as its content is inflated.
-        assertFalse(mHeadsUpManager.isAlerting(summaryEntry.getKey()));
-        assertTrue(mHeadsUpManager.isAlerting(childEntry.getKey()));
-    }
-
-    @Test
-    public void testSuppressedSummaryHeadsUpTransferBackAbortsChildInflation() {
-        NotificationEntry summaryEntry =
-                mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY);
-        NotificationEntry childEntry =
-                mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
-        RowContentBindParams params = new RowContentBindParams();
-        when(mBindStage.getStageParams(eq(childEntry))).thenReturn(params);
-
-        NotificationEntry childEntry2 =
-                mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
-        mHeadsUpManager.showNotification(summaryEntry);
-        // Trigger a transfer of alert state from summary to child.
-        mGroupManager.onEntryAdded(summaryEntry);
-        mGroupManager.onEntryAdded(childEntry);
-
-        // Add second child notification so that summary is no longer suppressed.
-        mPendingEntries.put(childEntry2.getKey(), childEntry2);
-        mNotificationEntryListener.onPendingEntryAdded(childEntry2);
-        mGroupManager.onEntryAdded(childEntry2);
-
-        // Child entry finishes its inflation.
-        ArgumentCaptor<BindCallback> callbackCaptor = ArgumentCaptor.forClass(BindCallback.class);
-        verify(mBindStage).requestRebind(eq(childEntry), callbackCaptor.capture());
-        callbackCaptor.getValue().onBindFinished(childEntry);
-
-        assertTrue((params.getContentViews() & FLAG_CONTENT_VIEW_HEADS_UP) == 0);
-        assertFalse(mHeadsUpManager.isAlerting(childEntry.getKey()));
-    }
-
-    @Test
-    public void testCleanUpPendingAlertInfo() {
-        NotificationEntry summaryEntry =
-                mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY);
-        NotificationEntry childEntry =
-                mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
-        mockHasHeadsUpContentView(childEntry, false);
-
-        mHeadsUpManager.showNotification(summaryEntry);
-        // Trigger a transfer of alert state from summary to child.
-        mGroupManager.onEntryAdded(summaryEntry);
-        mGroupManager.onEntryAdded(childEntry);
-
-        mNotificationEntryListener.onEntryRemoved(
-                childEntry, null, false, UNDEFINED_DISMISS_REASON);
-
-        assertFalse(mGroupAlertTransferHelper.isAlertTransferPending(childEntry));
-    }
-
-    @Test
-    public void testUpdateGroupChangeDoesNotTransfer() {
-        NotificationEntry summaryEntry =
-                mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY);
-        NotificationEntry childEntry =
-                mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
-        mockHasHeadsUpContentView(childEntry, false);
-
-        mHeadsUpManager.showNotification(summaryEntry);
-        // Trigger a transfer of alert state from summary to child.
-        mGroupManager.onEntryAdded(summaryEntry);
-        mGroupManager.onEntryAdded(childEntry);
-
-        // Notify that entry changed groups.
-        StatusBarNotification oldNotification = childEntry.getSbn();
-        StatusBarNotification newSbn = spy(childEntry.getSbn().clone());
-        doReturn("other_group").when(newSbn).getGroupKey();
-        childEntry.setSbn(newSbn);
-        mGroupManager.onEntryUpdated(childEntry, oldNotification);
-
-        assertFalse(mGroupAlertTransferHelper.isAlertTransferPending(childEntry));
-    }
-
-    @Test
-    public void testUpdateChildToSummaryDoesNotTransfer() {
-        final String tag = "fooTag";
-        NotificationEntry summaryEntry =
-                mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY);
-        NotificationEntry childEntry =
-                mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY, 47, tag);
-        mockHasHeadsUpContentView(childEntry, false);
-
-        mHeadsUpManager.showNotification(summaryEntry);
-        // Trigger a transfer of alert state from summary to child.
-        mGroupManager.onEntryAdded(summaryEntry);
-        mGroupManager.onEntryAdded(childEntry);
-
-        // Update that child to a summary.
-        StatusBarNotification oldNotification = childEntry.getSbn();
-        childEntry.setSbn(
-                mGroupTestHelper.createSummaryNotification(
-                        Notification.GROUP_ALERT_SUMMARY, 47, tag).getSbn());
-        mGroupManager.onEntryUpdated(childEntry, oldNotification);
-
-        assertFalse(mGroupAlertTransferHelper.isAlertTransferPending(childEntry));
-    }
-
-    @Test
-    public void testOverriddenSummaryHeadsUpTransfersToPriority() {
-        // Creation order is oldest to newest, meaning the priority will be deemed newest
-        int groupAlert = Notification.GROUP_ALERT_SUMMARY;
-        NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(groupAlert);
-        NotificationEntry childEntry = mGroupTestHelper.createChildNotification(groupAlert);
-        NotificationEntry priorityEntry = mGroupTestHelper.createChildNotification(groupAlert);
-        mockIsPriority(priorityEntry);
-
-        // summary gets heads up
-        mHeadsUpManager.showNotification(summaryEntry);
-
-        mockHasHeadsUpContentView(summaryEntry);
-        mockHasHeadsUpContentView(priorityEntry);
-        mockHasHeadsUpContentView(childEntry);
-
-        // Summary will have an alertOverride.
-        mGroupManager.onEntryAdded(summaryEntry);
-        mGroupManager.onEntryAdded(priorityEntry);
-        mGroupManager.onEntryAdded(childEntry);
-
-        // An overridden summary should transfer its alert state to the priority.
-        assertFalse(mHeadsUpManager.isAlerting(summaryEntry.getKey()));
-        assertFalse(mHeadsUpManager.isAlerting(childEntry.getKey()));
-        assertTrue(mHeadsUpManager.isAlerting(priorityEntry.getKey()));
-    }
-
-    @Test
-    public void testOverriddenSummaryHeadsUpTransferDoesNotAlertPriorityIfUninflated() {
-        // Creation order is oldest to newest, meaning the priority will be deemed newest
-        int groupAlert = Notification.GROUP_ALERT_SUMMARY;
-        NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(groupAlert);
-        NotificationEntry childEntry = mGroupTestHelper.createChildNotification(groupAlert);
-        NotificationEntry priorityEntry = mGroupTestHelper.createChildNotification(groupAlert);
-        mockIsPriority(priorityEntry);
-
-        // summary gets heads up
-        mHeadsUpManager.showNotification(summaryEntry);
-
-        mockHasHeadsUpContentView(summaryEntry);
-        mockHasHeadsUpContentView(priorityEntry, false);
-        mockHasHeadsUpContentView(childEntry);
-
-        // Summary will have an alertOverride.
-        mGroupManager.onEntryAdded(summaryEntry);
-        mGroupManager.onEntryAdded(priorityEntry);
-        mGroupManager.onEntryAdded(childEntry);
-
-        // Alert is immediately removed from summary, but we do not show priority yet either as its
-        // content is not inflated.
-        assertFalse(mHeadsUpManager.isAlerting(summaryEntry.getKey()));
-        assertFalse(mHeadsUpManager.isAlerting(childEntry.getKey()));
-        assertFalse(mHeadsUpManager.isAlerting(priorityEntry.getKey()));
-        assertTrue(mGroupAlertTransferHelper.isAlertTransferPending(priorityEntry));
-    }
-
-    @Test
-    public void testOverriddenSummaryHeadsUpTransfersToPriorityButBackAgain() {
-        // Creation order is oldest to newest, meaning the child2 will ultimately be deemed newest
-        int groupAlert = Notification.GROUP_ALERT_SUMMARY;
-        NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(groupAlert);
-        NotificationEntry childEntry = mGroupTestHelper.createChildNotification(groupAlert);
-        NotificationEntry priorityEntry = mGroupTestHelper.createChildNotification(groupAlert);
-        NotificationEntry childEntry2 = mGroupTestHelper.createChildNotification(groupAlert);
-        mockIsPriority(priorityEntry);
-
-        // summary gets heads up
-        mHeadsUpManager.showNotification(summaryEntry);
-
-        mockHasHeadsUpContentView(summaryEntry);
-        mockHasHeadsUpContentView(priorityEntry);
-        mockHasHeadsUpContentView(childEntry);
-        mockHasHeadsUpContentView(childEntry2);
-
-        // Summary will have an alertOverride.
-        mGroupManager.onEntryAdded(summaryEntry);
-        mGroupManager.onEntryAdded(priorityEntry);
-        mGroupManager.onEntryAdded(childEntry);
-
-        // An overridden summary should transfer its alert state to the priority.
-        assertFalse(mHeadsUpManager.isAlerting(summaryEntry.getKey()));
-        assertFalse(mHeadsUpManager.isAlerting(childEntry.getKey()));
-        assertTrue(mHeadsUpManager.isAlerting(priorityEntry.getKey()));
-
-        mGroupManager.onEntryAdded(childEntry2);
-
-        // An overridden summary should transfer its alert state to the priority.
-        assertTrue(mHeadsUpManager.isAlerting(summaryEntry.getKey()));
-        assertFalse(mHeadsUpManager.isAlerting(childEntry.getKey()));
-        assertFalse(mHeadsUpManager.isAlerting(childEntry2.getKey()));
-        assertFalse(mHeadsUpManager.isAlerting(priorityEntry.getKey()));
-    }
-
-    @Test
-    public void testOverriddenSuppressedSummaryHeadsUpTransfersToChildThenToPriority() {
-        // Creation order is oldest to newest, meaning the priority will ultimately be deemed newest
-        int groupAlert = Notification.GROUP_ALERT_SUMMARY;
-        NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(groupAlert);
-        NotificationEntry childEntry = mGroupTestHelper.createChildNotification(groupAlert);
-        NotificationEntry priorityEntry = mGroupTestHelper.createChildNotification(groupAlert);
-        mockIsPriority(priorityEntry);
-
-        // summary gets heads up
-        mHeadsUpManager.showNotification(summaryEntry);
-
-        mockHasHeadsUpContentView(summaryEntry);
-        mockHasHeadsUpContentView(priorityEntry);
-        mockHasHeadsUpContentView(childEntry);
-
-        // Summary will be suppressed, and the child will receive the alert
-        mGroupManager.onEntryAdded(summaryEntry);
-        mGroupManager.onEntryAdded(childEntry);
-
-        assertFalse(mHeadsUpManager.isAlerting(summaryEntry.getKey()));
-        assertTrue(mHeadsUpManager.isAlerting(childEntry.getKey()));
-
-        // Alert should be transferred "back" from the child to the priority
-        mGroupManager.onEntryAdded(priorityEntry);
-
-        assertFalse(mHeadsUpManager.isAlerting(summaryEntry.getKey()));
-        assertFalse(mHeadsUpManager.isAlerting(childEntry.getKey()));
-        assertTrue(mHeadsUpManager.isAlerting(priorityEntry.getKey()));
-    }
-
-    @Test
-    public void testOverriddenSuppressedSummaryHeadsUpTransfersToPriorityThenToChild() {
-        // Creation order is oldest to newest, meaning the child will ultimately be deemed newest
-        int groupAlert = Notification.GROUP_ALERT_SUMMARY;
-        NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(groupAlert);
-        NotificationEntry priorityEntry = mGroupTestHelper.createChildNotification(groupAlert);
-        NotificationEntry childEntry = mGroupTestHelper.createChildNotification(groupAlert);
-        mockIsPriority(priorityEntry);
-
-        // summary gets heads up
-        mHeadsUpManager.showNotification(summaryEntry);
-
-        mockHasHeadsUpContentView(summaryEntry);
-        mockHasHeadsUpContentView(priorityEntry);
-        mockHasHeadsUpContentView(childEntry);
-
-        // Summary will have alert override of the priority
-        mGroupManager.onEntryAdded(summaryEntry);
-        mGroupManager.onEntryAdded(priorityEntry);
-
-        assertFalse(mHeadsUpManager.isAlerting(summaryEntry.getKey()));
-        assertTrue(mHeadsUpManager.isAlerting(priorityEntry.getKey()));
-
-        // Alert should be transferred "back" from the priority to the child (which is newer)
-        mGroupManager.onEntryAdded(childEntry);
-
-        assertFalse(mHeadsUpManager.isAlerting(summaryEntry.getKey()));
-        assertTrue(mHeadsUpManager.isAlerting(childEntry.getKey()));
-        assertFalse(mHeadsUpManager.isAlerting(priorityEntry.getKey()));
-    }
-
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java
deleted file mode 100644
index d002cebe5..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java
+++ /dev/null
@@ -1,406 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.phone;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
-
-import static org.junit.Assert.assertNull;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.app.Notification;
-import android.service.notification.StatusBarNotification;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.util.Log;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy.NotificationGroup;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy.OnGroupChangeListener;
-import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.wm.shell.bubbles.Bubbles;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-import java.util.Optional;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-public class NotificationGroupManagerLegacyTest extends SysuiTestCase {
-    @Rule
-    public MockitoRule rule = MockitoJUnit.rule();
-
-    private NotificationGroupManagerLegacy mGroupManager;
-    private final NotificationGroupTestHelper mGroupTestHelper =
-            new NotificationGroupTestHelper(mContext);
-
-    @Mock
-    PeopleNotificationIdentifier mPeopleNotificationIdentifier;
-    @Mock
-    HeadsUpManager mHeadsUpManager;
-
-    @Before
-    public void setup() {
-        mDependency.injectMockDependency(Bubbles.class);
-        initializeGroupManager();
-    }
-
-    private void initializeGroupManager() {
-        mGroupManager = new NotificationGroupManagerLegacy(
-                mock(StatusBarStateController.class),
-                () -> mPeopleNotificationIdentifier,
-                Optional.of(mock(Bubbles.class)),
-                mock(DumpManager.class));
-        mGroupManager.setHeadsUpManager(mHeadsUpManager);
-    }
-
-    @Test
-    public void testIsOnlyChildInGroup() {
-        NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
-        NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
-
-        mGroupManager.onEntryAdded(summaryEntry);
-        mGroupManager.onEntryAdded(childEntry);
-
-        assertTrue(mGroupManager.isOnlyChildInGroup(childEntry));
-    }
-
-    @Test
-    public void testIsChildInGroupWithSummary() {
-        NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
-        NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
-
-        mGroupManager.onEntryAdded(summaryEntry);
-        mGroupManager.onEntryAdded(childEntry);
-        mGroupManager.onEntryAdded(mGroupTestHelper.createChildNotification());
-
-        assertTrue(mGroupManager.isChildInGroup(childEntry));
-    }
-
-    @Test
-    public void testIsSummaryOfGroupWithChildren() {
-        NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
-        NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
-
-        mGroupManager.onEntryAdded(summaryEntry);
-        mGroupManager.onEntryAdded(childEntry);
-        mGroupManager.onEntryAdded(mGroupTestHelper.createChildNotification());
-
-        assertTrue(mGroupManager.isGroupSummary(summaryEntry));
-        assertEquals(summaryEntry, mGroupManager.getGroupSummary(childEntry));
-    }
-
-    @Test
-    public void testRemoveChildFromGroupWithSummary() {
-        NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
-        NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
-        mGroupManager.onEntryAdded(summaryEntry);
-        mGroupManager.onEntryAdded(childEntry);
-        mGroupManager.onEntryAdded(mGroupTestHelper.createChildNotification());
-
-        mGroupManager.onEntryRemoved(childEntry);
-
-        assertFalse(mGroupManager.isChildInGroup(childEntry));
-    }
-
-    @Test
-    public void testRemoveSummaryFromGroupWithSummary() {
-        NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
-        NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
-        mGroupManager.onEntryAdded(summaryEntry);
-        mGroupManager.onEntryAdded(childEntry);
-        mGroupManager.onEntryAdded(mGroupTestHelper.createChildNotification());
-
-        mGroupManager.onEntryRemoved(summaryEntry);
-
-        assertNull(mGroupManager.getGroupSummary(childEntry));
-        assertFalse(mGroupManager.isGroupSummary(summaryEntry));
-    }
-
-    @Test
-    public void testHeadsUpEntryIsIsolated() {
-        NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
-        NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
-        mGroupManager.onEntryAdded(summaryEntry);
-        mGroupManager.onEntryAdded(childEntry);
-        mGroupManager.onEntryAdded(mGroupTestHelper.createChildNotification());
-        when(mHeadsUpManager.isAlerting(childEntry.getKey())).thenReturn(true);
-
-        mGroupManager.onHeadsUpStateChanged(childEntry, true);
-
-        // Child entries that are heads upped should be considered separate groups visually even if
-        // they are the same group logically
-        assertEquals(childEntry, mGroupManager.getGroupSummary(childEntry));
-        assertEquals(summaryEntry, mGroupManager.getLogicalGroupSummary(childEntry));
-    }
-
-    @Test
-    public void testAlertOverrideWithSiblings_0() {
-        helpTestAlertOverrideWithSiblings(0);
-    }
-
-    @Test
-    public void testAlertOverrideWithSiblings_1() {
-        helpTestAlertOverrideWithSiblings(1);
-    }
-
-    @Test
-    public void testAlertOverrideWithSiblings_2() {
-        helpTestAlertOverrideWithSiblings(2);
-    }
-
-    @Test
-    public void testAlertOverrideWithSiblings_3() {
-        helpTestAlertOverrideWithSiblings(3);
-    }
-
-    @Test
-    public void testAlertOverrideWithSiblings_9() {
-        helpTestAlertOverrideWithSiblings(9);
-    }
-
-    /**
-     * Helper for testing various sibling counts
-     */
-    private void helpTestAlertOverrideWithSiblings(int numSiblings) {
-        helpTestAlertOverride(
-                /* numSiblings */ numSiblings,
-                /* summaryGroupAlert */ Notification.GROUP_ALERT_SUMMARY,
-                /* priorityGroupAlert */ Notification.GROUP_ALERT_SUMMARY,
-                /* siblingGroupAlert */ Notification.GROUP_ALERT_SUMMARY,
-                /* expectAlertOverride */ true);
-    }
-
-    @Test
-    public void testAlertOverrideWithParentAlertAll() {
-        // tests that summary can have GROUP_ALERT_ALL and this still works
-        helpTestAlertOverride(
-                /* numSiblings */ 1,
-                /* summaryGroupAlert */ Notification.GROUP_ALERT_ALL,
-                /* priorityGroupAlert */ Notification.GROUP_ALERT_SUMMARY,
-                /* siblingGroupAlert */ Notification.GROUP_ALERT_SUMMARY,
-                /* expectAlertOverride */ true);
-    }
-
-    @Test
-    public void testAlertOverrideWithParentAlertChild() {
-        // Tests that if the summary alerts CHILDREN, there's no alertOverride
-        helpTestAlertOverride(
-                /* numSiblings */ 1,
-                /* summaryGroupAlert */ Notification.GROUP_ALERT_CHILDREN,
-                /* priorityGroupAlert */ Notification.GROUP_ALERT_SUMMARY,
-                /* siblingGroupAlert */ Notification.GROUP_ALERT_SUMMARY,
-                /* expectAlertOverride */ false);
-    }
-
-    @Test
-    public void testAlertOverrideWithChildrenAlertAll() {
-        // Tests that if the children alert ALL, there's no alertOverride
-        helpTestAlertOverride(
-                /* numSiblings */ 1,
-                /* summaryGroupAlert */ Notification.GROUP_ALERT_SUMMARY,
-                /* priorityGroupAlert */ Notification.GROUP_ALERT_ALL,
-                /* siblingGroupAlert */ Notification.GROUP_ALERT_ALL,
-                /* expectAlertOverride */ false);
-    }
-
-    /**
-     * This tests, for a group with a priority entry and the given number of siblings, that:
-     * 1) the priority entry is identified as the alertOverride for the group
-     * 2) the onAlertOverrideChanged method is called at that time
-     * 3) when the priority entry is removed, these are reversed
-     */
-    private void helpTestAlertOverride(int numSiblings,
-            @Notification.GroupAlertBehavior int summaryGroupAlert,
-            @Notification.GroupAlertBehavior int priorityGroupAlert,
-            @Notification.GroupAlertBehavior int siblingGroupAlert,
-            boolean expectAlertOverride) {
-        long when = 10000;
-        // Create entries in an order so that the priority entry can be deemed the newest child.
-        NotificationEntry[] siblings = new NotificationEntry[numSiblings];
-        for (int i = 0; i < numSiblings; i++) {
-            siblings[i] = mGroupTestHelper
-                    .createChildNotification(siblingGroupAlert, i, "sibling", ++when);
-        }
-        NotificationEntry priorityEntry =
-                mGroupTestHelper.createChildNotification(priorityGroupAlert, 0, "priority", ++when);
-        NotificationEntry summaryEntry =
-                mGroupTestHelper.createSummaryNotification(summaryGroupAlert, 0, "summary", ++when);
-
-        // The priority entry is an important conversation.
-        when(mPeopleNotificationIdentifier.getPeopleNotificationType(eq(priorityEntry)))
-                .thenReturn(PeopleNotificationIdentifier.TYPE_IMPORTANT_PERSON);
-
-        // Register a listener so we can verify that the event is sent.
-        OnGroupChangeListener groupChangeListener = mock(OnGroupChangeListener.class);
-        mGroupManager.registerGroupChangeListener(groupChangeListener);
-
-        // Add all the entries.  The order here shouldn't matter.
-        mGroupManager.onEntryAdded(summaryEntry);
-        for (int i = 0; i < numSiblings; i++) {
-            mGroupManager.onEntryAdded(siblings[i]);
-        }
-        mGroupManager.onEntryAdded(priorityEntry);
-
-        if (!expectAlertOverride) {
-            // Test expectation is that there will NOT be an alert, so verify that!
-            NotificationGroup summaryGroup =
-                    mGroupManager.getGroupForSummary(summaryEntry.getSbn());
-            assertNull(summaryGroup.alertOverride);
-            return;
-        }
-        int max2Siblings = Math.min(2, numSiblings);
-
-        // Verify that the summary group has the priority child as its alertOverride
-        NotificationGroup summaryGroup = mGroupManager.getGroupForSummary(summaryEntry.getSbn());
-        assertEquals(priorityEntry, summaryGroup.alertOverride);
-        verify(groupChangeListener).onGroupAlertOverrideChanged(summaryGroup, null, priorityEntry);
-        verify(groupChangeListener).onGroupSuppressionChanged(summaryGroup, true);
-        if (numSiblings > 1) {
-            verify(groupChangeListener).onGroupSuppressionChanged(summaryGroup, false);
-        }
-        verify(groupChangeListener).onGroupCreated(any(), eq(priorityEntry.getKey()));
-        verify(groupChangeListener).onGroupCreated(any(), eq(summaryEntry.getSbn().getGroupKey()));
-        verify(groupChangeListener, times(max2Siblings + 1)).onGroupsChanged();
-        verifyNoMoreInteractions(groupChangeListener);
-
-        // Verify that only the priority notification is isolated from the group
-        assertEquals(priorityEntry, mGroupManager.getGroupSummary(priorityEntry));
-        assertEquals(summaryEntry, mGroupManager.getLogicalGroupSummary(priorityEntry));
-        // Verify that the siblings are NOT isolated from the group
-        for (int i = 0; i < numSiblings; i++) {
-            assertEquals(summaryEntry, mGroupManager.getGroupSummary(siblings[i]));
-            assertEquals(summaryEntry, mGroupManager.getLogicalGroupSummary(siblings[i]));
-        }
-
-        // Remove the priority notification to validate that it is removed as the alertOverride
-        mGroupManager.onEntryRemoved(priorityEntry);
-
-        // verify that the alertOverride is removed when the priority notification is
-        assertNull(summaryGroup.alertOverride);
-        verify(groupChangeListener).onGroupAlertOverrideChanged(summaryGroup, priorityEntry, null);
-        verify(groupChangeListener).onGroupRemoved(any(), eq(priorityEntry.getKey()));
-        verify(groupChangeListener, times(max2Siblings + 2)).onGroupsChanged();
-        if (numSiblings == 0) {
-            verify(groupChangeListener).onGroupSuppressionChanged(summaryGroup, false);
-        }
-        verifyNoMoreInteractions(groupChangeListener);
-    }
-
-    @Test
-    public void testAlertOverrideWhenUpdatingSummaryAtEnd() {
-        long when = 10000;
-        int numSiblings = 2;
-        int groupAlert = Notification.GROUP_ALERT_SUMMARY;
-        // Create entries in an order so that the priority entry can be deemed the newest child.
-        NotificationEntry[] siblings = new NotificationEntry[numSiblings];
-        for (int i = 0; i < numSiblings; i++) {
-            siblings[i] =
-                    mGroupTestHelper.createChildNotification(groupAlert, i, "sibling", ++when);
-        }
-        NotificationEntry priorityEntry =
-                mGroupTestHelper.createChildNotification(groupAlert, 0, "priority", ++when);
-        NotificationEntry summaryEntry =
-                mGroupTestHelper.createSummaryNotification(groupAlert, 0, "summary", ++when);
-
-        // The priority entry is an important conversation.
-        when(mPeopleNotificationIdentifier.getPeopleNotificationType(eq(priorityEntry)))
-                .thenReturn(PeopleNotificationIdentifier.TYPE_IMPORTANT_PERSON);
-
-        // Register a listener so we can verify that the event is sent.
-        OnGroupChangeListener groupChangeListener = mock(OnGroupChangeListener.class);
-        mGroupManager.registerGroupChangeListener(groupChangeListener);
-
-        // Add all the entries.  The order here shouldn't matter.
-        mGroupManager.onEntryAdded(summaryEntry);
-        for (int i = 0; i < numSiblings; i++) {
-            mGroupManager.onEntryAdded(siblings[i]);
-        }
-        mGroupManager.onEntryAdded(priorityEntry);
-
-        int max2Siblings = Math.min(2, numSiblings);
-
-        // Verify that the summary group has the priority child as its alertOverride
-        NotificationGroup summaryGroup = mGroupManager.getGroupForSummary(summaryEntry.getSbn());
-        assertEquals(priorityEntry, summaryGroup.alertOverride);
-        verify(groupChangeListener).onGroupAlertOverrideChanged(summaryGroup, null, priorityEntry);
-        verify(groupChangeListener).onGroupSuppressionChanged(summaryGroup, true);
-        if (numSiblings > 1) {
-            verify(groupChangeListener).onGroupSuppressionChanged(summaryGroup, false);
-        }
-        verify(groupChangeListener).onGroupCreated(any(), eq(priorityEntry.getKey()));
-        verify(groupChangeListener).onGroupCreated(any(), eq(summaryEntry.getSbn().getGroupKey()));
-        verify(groupChangeListener, times(max2Siblings + 1)).onGroupsChanged();
-        verifyNoMoreInteractions(groupChangeListener);
-
-        // Verify that only the priority notification is isolated from the group
-        assertEquals(priorityEntry, mGroupManager.getGroupSummary(priorityEntry));
-        assertEquals(summaryEntry, mGroupManager.getLogicalGroupSummary(priorityEntry));
-        // Verify that the siblings are NOT isolated from the group
-        for (int i = 0; i < numSiblings; i++) {
-            assertEquals(summaryEntry, mGroupManager.getGroupSummary(siblings[i]));
-            assertEquals(summaryEntry, mGroupManager.getLogicalGroupSummary(siblings[i]));
-        }
-
-        Log.d("NotificationGroupManagerLegacyTest",
-                "testAlertOverrideWhenUpdatingSummaryAtEnd: About to update summary");
-
-        StatusBarNotification oldSummarySbn = mGroupTestHelper.incrementPost(summaryEntry, 10000);
-        mGroupManager.onEntryUpdated(summaryEntry, oldSummarySbn);
-
-        verify(groupChangeListener, times(max2Siblings + 2)).onGroupsChanged();
-        verify(groupChangeListener).onGroupAlertOverrideChanged(summaryGroup, priorityEntry, null);
-        verifyNoMoreInteractions(groupChangeListener);
-
-        Log.d("NotificationGroupManagerLegacyTest",
-                "testAlertOverrideWhenUpdatingSummaryAtEnd: About to update priority child");
-
-        StatusBarNotification oldPrioritySbn = mGroupTestHelper.incrementPost(priorityEntry, 10000);
-        mGroupManager.onEntryUpdated(priorityEntry, oldPrioritySbn);
-
-        verify(groupChangeListener).onGroupRemoved(any(), eq(priorityEntry.getKey()));
-        verify(groupChangeListener, times(2)).onGroupCreated(any(), eq(priorityEntry.getKey()));
-        verify(groupChangeListener, times(2))
-                .onGroupAlertOverrideChanged(summaryGroup, null, priorityEntry);
-        verify(groupChangeListener, times(max2Siblings + 3)).onGroupsChanged();
-        verifyNoMoreInteractions(groupChangeListener);
-
-        Log.d("NotificationGroupManagerLegacyTest",
-                "testAlertOverrideWhenUpdatingSummaryAtEnd: Done");
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index c896c0a..de43a1f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -178,10 +178,10 @@
         bubbleSbn.getNotification().contentIntent = mContentIntent;
         bubbleSbn.getNotification().flags |= Notification.FLAG_AUTO_CANCEL;
 
-        ArrayList<NotificationEntry> activeNotifications = new ArrayList<>();
-        activeNotifications.add(mNotificationRow.getEntry());
-        activeNotifications.add(mBubbleNotificationRow.getEntry());
-        when(mEntryManager.getVisibleNotifications()).thenReturn(activeNotifications);
+//        ArrayList<NotificationEntry> activeNotifications = new ArrayList<>();
+//        activeNotifications.add(mNotificationRow.getEntry());
+//        activeNotifications.add(mBubbleNotificationRow.getEntry());
+//        when(mEntryManager.getVisibleNotifications()).thenReturn(activeNotifications);
         when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
         when(mOnUserInteractionCallback.registerFutureDismissal(eq(mNotificationRow.getEntry()),
                 anyInt())).thenReturn(mFutureDismissalRunnable);
@@ -347,9 +347,6 @@
 
         // The content intent should NOT be sent on click.
         verifyZeroInteractions(mContentIntent);
-
-        // Notification should not be cancelled.
-        verify(mEntryManager, never()).performRemoveNotification(eq(sbn), any(), anyInt());
     }
 
     @Test
@@ -380,9 +377,6 @@
         verify(mContentIntent).getIntent();
         verify(mContentIntent).isActivity();
         verifyNoMoreInteractions(mContentIntent);
-
-        // Notification should not be cancelled.
-        verify(mEntryManager, never()).performRemoveNotification(eq(sbn), any(), anyInt());
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
index 23b1404..1ec4de9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
@@ -38,7 +38,7 @@
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
+import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -79,7 +79,7 @@
                 mNotificationLockscreenUserManager);
 
         mRemoteInputCallback = spy(new StatusBarRemoteInputCallback(mContext,
-                mock(NotificationGroupManagerLegacy.class), mNotificationLockscreenUserManager,
+                mock(GroupExpansionManager.class), mNotificationLockscreenUserManager,
                 mKeyguardStateController, mStatusBarStateController, mStatusBarKeyguardViewManager,
                 mActivityStarter, mShadeController, new CommandQueue(mContext),
                 mock(ActionClickLogger.class), mFakeExecutor));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
index 87fca1f..7e07040 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
@@ -30,13 +30,13 @@
 import com.android.systemui.unfold.updates.screen.ScreenStatusProvider.ScreenListener
 import com.android.systemui.util.mockito.any
 import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.Executor
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mock
-import org.mockito.MockitoAnnotations
-import java.util.concurrent.Executor
 import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
 
 @RunWith(AndroidTestingRunner::class)
 @SmallTest
@@ -331,6 +331,47 @@
         assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING)
     }
 
+    @Test
+    fun screenOff_whileFolded_hingeAngleProviderRemainsOff() {
+        setFoldState(folded = true)
+        assertThat(testHingeAngleProvider.isStarted).isFalse()
+
+        screenOnStatusProvider.notifyScreenTurningOff()
+
+        assertThat(testHingeAngleProvider.isStarted).isFalse()
+    }
+
+    @Test
+    fun screenOff_whileUnfolded_hingeAngleProviderStops() {
+        setFoldState(folded = false)
+        assertThat(testHingeAngleProvider.isStarted).isTrue()
+
+        screenOnStatusProvider.notifyScreenTurningOff()
+
+        assertThat(testHingeAngleProvider.isStarted).isFalse()
+    }
+
+    @Test
+    fun screenOn_whileUnfoldedAndScreenOff_hingeAngleProviderStarted() {
+        setFoldState(folded = false)
+        screenOnStatusProvider.notifyScreenTurningOff()
+        assertThat(testHingeAngleProvider.isStarted).isFalse()
+
+        screenOnStatusProvider.notifyScreenTurningOn()
+
+        assertThat(testHingeAngleProvider.isStarted).isTrue()
+    }
+
+    @Test
+    fun screenOn_whileFolded_hingeAngleRemainsOff() {
+        setFoldState(folded = true)
+        assertThat(testHingeAngleProvider.isStarted).isFalse()
+
+        screenOnStatusProvider.notifyScreenTurningOn()
+
+        assertThat(testHingeAngleProvider.isStarted).isFalse()
+    }
+
     private fun setupForegroundActivityType(isHomeActivity: Boolean?) {
         whenever(activityTypeProvider.isHomeActivity).thenReturn(isHomeActivity)
     }
@@ -391,6 +432,14 @@
         fun notifyScreenTurnedOn() {
             callbacks.forEach { it.onScreenTurnedOn() }
         }
+
+        fun notifyScreenTurningOn() {
+            callbacks.forEach { it.onScreenTurningOn() }
+        }
+
+        fun notifyScreenTurningOff() {
+            callbacks.forEach { it.onScreenTurningOff() }
+        }
     }
 
     private class TestHingeAngleProvider : HingeAngleProvider {
@@ -398,11 +447,11 @@
         var isStarted: Boolean = false
 
         override fun start() {
-            isStarted = true;
+            isStarted = true
         }
 
         override fun stop() {
-            isStarted = false;
+            isStarted = false
         }
 
         override fun addCallback(listener: Consumer<Float>) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/FakeSharedPreferencesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/FakeSharedPreferencesTest.kt
new file mode 100644
index 0000000..d886ffd
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/FakeSharedPreferencesTest.kt
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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
+
+import android.content.SharedPreferences
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.mockito.eq
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.anyString
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyNoMoreInteractions
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class FakeSharedPreferencesTest : SysuiTestCase() {
+
+    @Mock
+    private lateinit var listener: SharedPreferences.OnSharedPreferenceChangeListener
+
+    private lateinit var sharedPreferences: SharedPreferences
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        sharedPreferences = FakeSharedPreferences()
+    }
+
+    @Test
+    fun testGetString_default() {
+        val default = "default"
+        val result = sharedPreferences.getString("key", default)
+        assertThat(result).isEqualTo(default)
+    }
+
+    @Test
+    fun testGetStringSet_default() {
+        val default = setOf("one", "two")
+        val result = sharedPreferences.getStringSet("key", default)
+        assertThat(result).isEqualTo(default)
+    }
+
+    @Test
+    fun testGetInt_default() {
+        val default = 10
+        val result = sharedPreferences.getInt("key", default)
+        assertThat(result).isEqualTo(default)
+    }
+
+    @Test
+    fun testGetLong_default() {
+        val default = 11L
+        val result = sharedPreferences.getLong("key", default)
+        assertThat(result).isEqualTo(default)
+    }
+
+    @Test
+    fun testGetFloat_default() {
+        val default = 1.3f
+        val result = sharedPreferences.getFloat("key", default)
+        assertThat(result).isEqualTo(default)
+    }
+
+    @Test
+    fun testGetBoolean_default() {
+        val default = true
+        val result = sharedPreferences.getBoolean("key", default)
+        assertThat(result).isEqualTo(default)
+    }
+
+    @Test
+    fun testPutValuesAndRetrieve() {
+        val editor = sharedPreferences.edit()
+        val data = listOf<Data<*>>(
+            Data(
+                "keyString",
+                "value",
+                SharedPreferences.Editor::putString,
+                { getString(it, "") }
+            ),
+            Data(
+                "keyStringSet",
+                setOf("one", "two"),
+                SharedPreferences.Editor::putStringSet,
+                { getStringSet(it, emptySet()) }
+            ),
+            Data("keyInt", 10, SharedPreferences.Editor::putInt, { getInt(it, 0) }),
+            Data("keyLong", 11L, SharedPreferences.Editor::putLong, { getLong(it, 0L) }),
+            Data(
+                "keyFloat",
+                1.3f,
+                SharedPreferences.Editor::putFloat,
+                { getFloat(it, 0f) }
+            ),
+            Data(
+                "keyBoolean",
+                true,
+                SharedPreferences.Editor::putBoolean,
+                { getBoolean(it, false) }
+            )
+        )
+
+        data.fold(editor) { ed, d ->
+            d.set(ed)
+        }
+        editor.commit()
+
+        data.forEach {
+            assertThat(it.get(sharedPreferences)).isEqualTo(it.value)
+        }
+    }
+
+    @Test
+    fun testContains() {
+        sharedPreferences.edit().putInt("key", 10).commit()
+
+        assertThat(sharedPreferences.contains("key")).isTrue()
+        assertThat(sharedPreferences.contains("other")).isFalse()
+    }
+
+    @Test
+    fun testOverwrite() {
+        sharedPreferences.edit().putInt("key", 10).commit()
+        sharedPreferences.edit().putInt("key", 11).commit()
+
+        assertThat(sharedPreferences.getInt("key", 0)).isEqualTo(11)
+    }
+
+    @Test
+    fun testDeleteString() {
+        sharedPreferences.edit().putString("key", "value").commit()
+        sharedPreferences.edit().putString("key", null).commit()
+
+        assertThat(sharedPreferences.contains("key")).isFalse()
+    }
+
+    @Test
+    fun testDeleteAndReplaceString() {
+        sharedPreferences.edit().putString("key", "value").commit()
+        sharedPreferences.edit().putString("key", "other").putString("key", null).commit()
+
+        assertThat(sharedPreferences.getString("key", "")).isEqualTo("other")
+    }
+
+    @Test
+    fun testDeleteStringSet() {
+        sharedPreferences.edit().putStringSet("key", setOf("one")).commit()
+        sharedPreferences.edit().putStringSet("key", setOf("two")).commit()
+
+        assertThat(sharedPreferences.getStringSet("key", emptySet())).isEqualTo(setOf("two"))
+    }
+
+    @Test
+    fun testClear() {
+        sharedPreferences.edit().putInt("keyInt", 1).putString("keyString", "a").commit()
+        sharedPreferences.edit().clear().commit()
+
+        assertThat(sharedPreferences.contains("keyInt")).isFalse()
+        assertThat(sharedPreferences.contains("keyString")).isFalse()
+    }
+
+    @Test
+    fun testClearAndWrite() {
+        sharedPreferences.edit().putInt("key", 10).commit()
+        sharedPreferences.edit().putInt("key", 11).clear().commit()
+
+        assertThat(sharedPreferences.getInt("key", 0)).isEqualTo(11)
+    }
+
+    @Test
+    fun testListenerNotifiedOnChanges() {
+        sharedPreferences.registerOnSharedPreferenceChangeListener(listener)
+
+        sharedPreferences.edit().putInt("keyInt", 10).putString("keyString", "value").commit()
+
+        verify(listener).onSharedPreferenceChanged(sharedPreferences, "keyInt")
+        verify(listener).onSharedPreferenceChanged(sharedPreferences, "keyString")
+        verifyNoMoreInteractions(listener)
+    }
+
+    @Test
+    fun testListenerNotifiedOnClear() {
+        sharedPreferences.edit().putInt("keyInt", 10).commit()
+        sharedPreferences.registerOnSharedPreferenceChangeListener(listener)
+
+        sharedPreferences.edit().clear().commit()
+
+        verify(listener).onSharedPreferenceChanged(sharedPreferences, null)
+        verifyNoMoreInteractions(listener)
+    }
+
+    @Test
+    fun testListenerNotifiedOnRemoval() {
+        sharedPreferences.edit()
+            .putString("keyString", "a")
+            .putStringSet("keySet", setOf("a"))
+            .commit()
+
+        sharedPreferences.registerOnSharedPreferenceChangeListener(listener)
+        sharedPreferences.edit().putString("keyString", null).putStringSet("keySet", null).commit()
+
+        verify(listener).onSharedPreferenceChanged(sharedPreferences, "keyString")
+        verify(listener).onSharedPreferenceChanged(sharedPreferences, "keySet")
+        verifyNoMoreInteractions(listener)
+    }
+
+    @Test
+    fun testListenerUnregistered() {
+        sharedPreferences.registerOnSharedPreferenceChangeListener(listener)
+        sharedPreferences.unregisterOnSharedPreferenceChangeListener(listener)
+        sharedPreferences.edit().putInt("key", 10).commit()
+
+        verify(listener, never()).onSharedPreferenceChanged(eq(sharedPreferences), anyString())
+    }
+
+    @Test
+    fun testSharedPreferencesOnlyModifiedOnCommit() {
+        sharedPreferences.edit().putInt("key", 10)
+
+        assertThat(sharedPreferences.contains("key")).isFalse()
+    }
+
+    private data class Data<T>(
+        val key: String,
+        val value: T,
+        private val setter: SharedPreferences.Editor.(String, T) -> SharedPreferences.Editor,
+        private val getter: SharedPreferences.(String) -> T
+    ) {
+        fun set(editor: SharedPreferences.Editor): SharedPreferences.Editor {
+            return editor.setter(key, value)
+        }
+
+        fun get(sharedPreferences: SharedPreferences): T {
+            return sharedPreferences.getter(key)
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/FakeSharedPreferences.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/FakeSharedPreferences.kt
new file mode 100644
index 0000000..4a881a7
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/FakeSharedPreferences.kt
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util
+
+import android.content.SharedPreferences
+
+/**
+ * Fake [SharedPreferences] to use within tests
+ *
+ * This will act in the same way as a real one for a particular file, but will store all the
+ * data in memory in the instance.
+ *
+ * [SharedPreferences.Editor.apply] and [SharedPreferences.Editor.commit] both act in the same way,
+ * synchronously modifying the stored data. Listeners are dispatched in the same thread, also
+ * synchronously.
+ */
+class FakeSharedPreferences : SharedPreferences {
+    private val data = mutableMapOf<String, Any>()
+    private val listeners = mutableSetOf<SharedPreferences.OnSharedPreferenceChangeListener>()
+
+    override fun getAll(): Map<String, *> {
+        return data
+    }
+
+    override fun getString(key: String, defValue: String?): String? {
+        return data.getOrDefault(key, defValue) as? String?
+    }
+
+    override fun getStringSet(key: String, defValues: MutableSet<String>?): MutableSet<String>? {
+        return data.getOrDefault(key, defValues) as? MutableSet<String>?
+    }
+
+    override fun getInt(key: String, defValue: Int): Int {
+        return data.getOrDefault(key, defValue) as Int
+    }
+
+    override fun getLong(key: String, defValue: Long): Long {
+        return data.getOrDefault(key, defValue) as Long
+    }
+
+    override fun getFloat(key: String, defValue: Float): Float {
+        return data.getOrDefault(key, defValue) as Float
+    }
+
+    override fun getBoolean(key: String, defValue: Boolean): Boolean {
+        return data.getOrDefault(key, defValue) as Boolean
+    }
+
+    override fun contains(key: String): Boolean {
+        return key in data
+    }
+
+    override fun edit(): SharedPreferences.Editor {
+        return Editor()
+    }
+
+    override fun registerOnSharedPreferenceChangeListener(
+        listener: SharedPreferences.OnSharedPreferenceChangeListener
+    ) {
+        listeners.add(listener)
+    }
+
+    override fun unregisterOnSharedPreferenceChangeListener(
+        listener: SharedPreferences.OnSharedPreferenceChangeListener
+    ) {
+        listeners.remove(listener)
+    }
+
+    private inner class Editor : SharedPreferences.Editor {
+
+        private var clear = false
+        private val changes = mutableMapOf<String, Any>()
+        private val removals = mutableSetOf<String>()
+
+        override fun putString(key: String, value: String?): SharedPreferences.Editor {
+            if (value != null) {
+                changes[key] = value
+            } else {
+                removals.add(key)
+            }
+            return this
+        }
+
+        override fun putStringSet(
+            key: String,
+            values: MutableSet<String>?
+        ): SharedPreferences.Editor {
+            if (values != null) {
+                changes[key] = values
+            } else {
+                removals.add(key)
+            }
+            return this
+        }
+
+        override fun putInt(key: String, value: Int): SharedPreferences.Editor {
+            changes[key] = value
+            return this
+        }
+
+        override fun putLong(key: String, value: Long): SharedPreferences.Editor {
+            changes[key] = value
+            return this
+        }
+
+        override fun putFloat(key: String, value: Float): SharedPreferences.Editor {
+            changes[key] = value
+            return this
+        }
+
+        override fun putBoolean(key: String, value: Boolean): SharedPreferences.Editor {
+            changes[key] = value
+            return this
+        }
+
+        override fun remove(key: String): SharedPreferences.Editor {
+            removals.add(key)
+            return this
+        }
+
+        override fun clear(): SharedPreferences.Editor {
+            clear = true
+            return this
+        }
+
+        override fun commit(): Boolean {
+            if (clear) {
+                data.clear()
+            }
+            removals.forEach { data.remove(it) }
+            data.putAll(changes)
+            val keys = removals + data.keys
+            if (clear || removals.isNotEmpty() || data.isNotEmpty()) {
+                listeners.forEach { listener ->
+                    if (clear) {
+                        listener.onSharedPreferenceChanged(this@FakeSharedPreferences, null)
+                    }
+                    keys.forEach {
+                        listener.onSharedPreferenceChanged(this@FakeSharedPreferences, it)
+                    }
+                }
+            }
+            return true
+        }
+
+        override fun apply() {
+            commit()
+        }
+    }
+}
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
index e8038fd..19cfc80 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
@@ -65,6 +65,7 @@
     private val halfOpenedTimeoutMillis: Int = config.halfFoldedTimeoutMillis
 
     private var isFolded = false
+    private var isScreenOn = false
     private var isUnfoldHandled = true
 
     override fun start() {
@@ -198,6 +199,25 @@
                 isUnfoldHandled = true
             }
         }
+
+        override fun onScreenTurningOn() {
+            isScreenOn = true
+            updateHingeAngleProviderState()
+        }
+
+        override fun onScreenTurningOff() {
+            isScreenOn = false
+            updateHingeAngleProviderState()
+        }
+    }
+
+    /** While the screen is off or the device is folded, hinge angle updates are not needed. */
+    private fun updateHingeAngleProviderState() {
+        if (isScreenOn && !isFolded) {
+            hingeAngleProvider.start()
+        } else {
+            hingeAngleProvider.stop()
+        }
     }
 
     private inner class HingeAngleListener : Consumer<Float> {
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt
index 3fc5d61..577137c 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt
@@ -30,8 +30,10 @@
 
     private val sensorListener = HingeAngleSensorListener()
     private val listeners: MutableList<Consumer<Float>> = arrayListOf()
+    var started = false
 
     override fun start() = executor.execute {
+        if (started) return@execute
         Trace.beginSection("HingeSensorAngleProvider#start")
         val sensor = sensorManager.getDefaultSensor(Sensor.TYPE_HINGE_ANGLE)
         sensorManager.registerListener(
@@ -40,10 +42,13 @@
             SensorManager.SENSOR_DELAY_FASTEST
         )
         Trace.endSection()
+        started = true
     }
 
     override fun stop() = executor.execute {
+        if (!started) return@execute
         sensorManager.unregisterListener(sensorListener)
+        started = false
     }
 
     override fun removeCallback(listener: Consumer<Float>) {
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/screen/ScreenStatusProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/screen/ScreenStatusProvider.kt
index d95e050..f09b53d 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/screen/ScreenStatusProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/screen/ScreenStatusProvider.kt
@@ -25,5 +25,15 @@
          * Called when the screen is on and ready (windows are drawn and screen blocker is removed)
          */
         fun onScreenTurnedOn()
+
+        /**
+         * Called when the screen is starting to be turned off.
+         */
+        fun onScreenTurningOff()
+
+        /**
+         * Called when the screen is starting to be turned on.
+         */
+        fun onScreenTurningOn()
     }
 }
diff --git a/services/Android.bp b/services/Android.bp
index 70692a6..1e4ce19 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -102,6 +102,7 @@
         ":services.profcollect-sources",
         ":services.restrictions-sources",
         ":services.searchui-sources",
+        ":services.selectiontoolbar-sources",
         ":services.smartspace-sources",
         ":services.speech-sources",
         ":services.systemcaptions-sources",
@@ -157,6 +158,7 @@
         "services.profcollect",
         "services.restrictions",
         "services.searchui",
+        "services.selectiontoolbar",
         "services.smartspace",
         "services.speech",
         "services.systemcaptions",
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index e1a0bfd..1fab28e 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -160,6 +160,7 @@
     public static final String[] AIDL_INTERFACE_PREFIXES_OF_INTEREST = new String[] {
             "android.hardware.biometrics.face.IFace/",
             "android.hardware.biometrics.fingerprint.IFingerprint/",
+            "android.hardware.graphics.composer3.IComposer/",
             "android.hardware.input.processor.IInputProcessor/",
             "android.hardware.light.ILights/",
             "android.hardware.power.IPower/",
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 03dcc8d..82fe6c6 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -1914,7 +1914,7 @@
         return null;
     }
 
-    UUID getDeviceSensorUuid(AudioDeviceAttributes device) {
+    @Nullable UUID getDeviceSensorUuid(AudioDeviceAttributes device) {
         synchronized (mDeviceStateLock) {
             return mDeviceInventory.getDeviceSensorUuid(device);
         }
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index dbe4fb8..82e68d9 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -16,6 +16,7 @@
 package com.android.server.audio;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothProfile;
@@ -1495,7 +1496,7 @@
         mDevRoleCapturePresetDispatchers.finishBroadcast();
     }
 
-    UUID getDeviceSensorUuid(AudioDeviceAttributes device) {
+    @Nullable UUID getDeviceSensorUuid(AudioDeviceAttributes device) {
         final String key = DeviceInfo.makeDeviceListKey(device.getInternalType(),
                 device.getAddress());
         synchronized (mDevicesLock) {
diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java
index e27fb11..8356134 100644
--- a/services/core/java/com/android/server/audio/SpatializerHelper.java
+++ b/services/core/java/com/android/server/audio/SpatializerHelper.java
@@ -353,6 +353,14 @@
         mASA.getDevicesForAttributes(
                 DEFAULT_ATTRIBUTES, false /* forVolume */).toArray(ROUTING_DEVICES);
 
+        // check validity of routing information
+        if (ROUTING_DEVICES[0] == null) {
+            logloge("onRoutingUpdated: device is null, no Spatial Audio");
+            setDispatchAvailableState(false);
+            // not changing the spatializer level as this is likely a transient state
+            return;
+        }
+
         // is media routed to a new device?
         if (isWireless(ROUTING_DEVICES[0].getType())) {
             addWirelessDeviceIfNew(ROUTING_DEVICES[0]);
@@ -1098,7 +1106,7 @@
         logDeviceState(deviceState, "setHeadTrackerEnabled");
 
         // check current routing to see if it affects the headtracking mode
-        if (ROUTING_DEVICES[0].getType() == ada.getType()
+        if (ROUTING_DEVICES[0] != null && ROUTING_DEVICES[0].getType() == ada.getType()
                 && ROUTING_DEVICES[0].getAddress().equals(ada.getAddress())) {
             setDesiredHeadTrackingMode(enabled ? mDesiredHeadTrackingModeWhenEnabled
                     : Spatializer.HEAD_TRACKING_MODE_DISABLED);
@@ -1633,7 +1641,11 @@
 
     private int getHeadSensorHandleUpdateTracker() {
         int headHandle = -1;
-        UUID routingDeviceUuid = mAudioService.getDeviceSensorUuid(ROUTING_DEVICES[0]);
+        final AudioDeviceAttributes currentDevice = ROUTING_DEVICES[0];
+        if (currentDevice == null) {
+            return headHandle;
+        }
+        UUID routingDeviceUuid = mAudioService.getDeviceSensorUuid(currentDevice);
         // We limit only to Sensor.TYPE_HEAD_TRACKER here to avoid confusion
         // with gaming sensors. (Note that Sensor.TYPE_ROTATION_VECTOR
         // and Sensor.TYPE_GAME_ROTATION_VECTOR are supported internally by
@@ -1644,7 +1656,7 @@
             final UUID uuid = sensor.getUuid();
             if (uuid.equals(routingDeviceUuid)) {
                 headHandle = sensor.getHandle();
-                if (!setHasHeadTracker(ROUTING_DEVICES[0])) {
+                if (!setHasHeadTracker(currentDevice)) {
                     headHandle = -1;
                 }
                 break;
diff --git a/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java b/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java
index 23f0ffb..351a1e9 100644
--- a/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java
+++ b/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java
@@ -39,7 +39,6 @@
 
 public class BroadcastRadioService extends SystemService {
     private static final String TAG = "BcRadioSrv";
-    private static final boolean DEBUG = false;
 
     private final ServiceImpl mServiceImpl = new ServiceImpl();
 
@@ -74,6 +73,7 @@
 
         @Override
         public List<RadioManager.ModuleProperties> listModules() {
+            Slog.v(TAG, "Listing HIDL modules");
             enforcePolicyAccess();
             List<RadioManager.ModuleProperties> modules = new ArrayList<>();
             modules.addAll(mV1Modules);
@@ -84,7 +84,7 @@
         @Override
         public ITuner openTuner(int moduleId, RadioManager.BandConfig bandConfig,
                 boolean withAudio, ITunerCallback callback) throws RemoteException {
-            if (DEBUG) Slog.i(TAG, "Opening module " + moduleId);
+            Slog.v(TAG, "Opening module " + moduleId);
             enforcePolicyAccess();
             if (callback == null) {
                 throw new IllegalArgumentException("Callback must not be empty");
@@ -101,16 +101,14 @@
         @Override
         public ICloseHandle addAnnouncementListener(int[] enabledTypes,
                 IAnnouncementListener listener) {
-            if (DEBUG) {
-                Slog.i(TAG, "Adding announcement listener for " + Arrays.toString(enabledTypes));
-            }
+            Slog.v(TAG, "Adding announcement listener for " + Arrays.toString(enabledTypes));
             Objects.requireNonNull(enabledTypes);
             Objects.requireNonNull(listener);
             enforcePolicyAccess();
 
             synchronized (mLock) {
                 if (!mHal2.hasAnyModules()) {
-                    Slog.i(TAG, "There are no HAL 2.x modules registered");
+                    Slog.i(TAG, "There are no HAL 2.0 modules registered");
                     return new AnnouncementAggregator(listener, mLock);
                 }
 
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java b/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
index 5c07f76..534e828 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
@@ -132,6 +132,7 @@
     }
 
     public @NonNull Collection<RadioManager.ModuleProperties> listModules() {
+        Slog.v(TAG, "List HIDL 2.0 modules");
         synchronized (mLock) {
             return mModules.values().stream().map(module -> module.mProperties)
                     .collect(Collectors.toList());
@@ -152,10 +153,11 @@
 
     public ITuner openSession(int moduleId, @Nullable RadioManager.BandConfig legacyConfig,
         boolean withAudio, @NonNull ITunerCallback callback) throws RemoteException {
+        Slog.v(TAG, "Open HIDL 2.0 session");
         Objects.requireNonNull(callback);
 
         if (!withAudio) {
-            throw new IllegalArgumentException("Non-audio sessions not supported with HAL 2.x");
+            throw new IllegalArgumentException("Non-audio sessions not supported with HAL 2.0");
         }
 
         RadioModule module = null;
@@ -175,6 +177,7 @@
 
     public ICloseHandle addAnnouncementListener(@NonNull int[] enabledTypes,
             @NonNull IAnnouncementListener listener) {
+        Slog.v(TAG, "Add announcementListener");
         AnnouncementAggregator aggregator = new AnnouncementAggregator(listener, mLock);
         boolean anySupported = false;
         synchronized (mLock) {
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
index ef7f4c9..aeaa678 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
@@ -142,8 +142,12 @@
     public static @Nullable RadioModule tryLoadingModule(int idx, @NonNull String fqName,
             Object lock) {
         try {
+            Slog.i(TAG, "Try loading module for idx " + idx + ", fqName " + fqName);
             IBroadcastRadio service = IBroadcastRadio.getService(fqName);
-            if (service == null) return null;
+            if (service == null) {
+                Slog.w(TAG, "No service found for fqName " + fqName);
+                return null;
+            }
 
             Mutable<AmFmRegionConfig> amfmConfig = new Mutable<>();
             service.getAmFmRegionConfig(false, (result, config) -> {
@@ -160,7 +164,7 @@
 
             return new RadioModule(service, prop, lock);
         } catch (RemoteException ex) {
-            Slog.e(TAG, "failed to load module " + fqName, ex);
+            Slog.e(TAG, "Failed to load module " + fqName, ex);
             return null;
         }
     }
@@ -171,6 +175,7 @@
 
     public @NonNull TunerSession openSession(@NonNull android.hardware.radio.ITunerCallback userCb)
             throws RemoteException {
+        Slog.i(TAG, "Open TunerSession");
         synchronized (mLock) {
             if (mHalTunerSession == null) {
                 Mutable<ITunerSession> hwSession = new Mutable<>();
@@ -201,6 +206,7 @@
         // Copy the contents of mAidlTunerSessions into a local array because TunerSession.close()
         // must be called without mAidlTunerSessions locked because it can call
         // onTunerSessionClosed().
+        Slog.i(TAG, "Close TunerSessions");
         TunerSession[] tunerSessions;
         synchronized (mLock) {
             tunerSessions = new TunerSession[mAidlTunerSessions.size()];
@@ -313,7 +319,7 @@
         }
         onTunerSessionProgramListFilterChanged(null);
         if (mAidlTunerSessions.isEmpty() && mHalTunerSession != null) {
-            Slog.v(TAG, "closing HAL tuner session");
+            Slog.i(TAG, "Closing HAL tuner session");
             try {
                 mHalTunerSession.close();
             } catch (RemoteException ex) {
@@ -365,6 +371,7 @@
 
     public android.hardware.radio.ICloseHandle addAnnouncementListener(@NonNull int[] enabledTypes,
             @NonNull android.hardware.radio.IAnnouncementListener listener) throws RemoteException {
+        Slog.i(TAG, "Add AnnouncementListener");
         ArrayList<Byte> enabledList = new ArrayList<>();
         for (int type : enabledTypes) {
             enabledList.add((byte)type);
@@ -401,6 +408,7 @@
     }
 
     Bitmap getImage(int id) {
+        Slog.i(TAG, "Get image for id " + id);
         if (id == 0) throw new IllegalArgumentException("Image ID is missing");
 
         byte[] rawImage;
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
index d476fd6..c13216b 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
@@ -27,6 +27,7 @@
 import android.hardware.radio.ProgramSelector;
 import android.hardware.radio.RadioManager;
 import android.os.RemoteException;
+import android.util.Log;
 import android.util.MutableBoolean;
 import android.util.MutableInt;
 import android.util.Slog;
@@ -61,8 +62,13 @@
         mLock = Objects.requireNonNull(lock);
     }
 
+    private boolean isDebugEnabled() {
+        return Log.isLoggable(TAG, Log.DEBUG);
+    }
+
     @Override
     public void close() {
+        if (isDebugEnabled()) Slog.d(TAG, "Close");
         close(null);
     }
 
@@ -74,6 +80,7 @@
      * @param error Optional error to send to client before session is closed.
      */
     public void close(@Nullable Integer error) {
+        if (isDebugEnabled()) Slog.d(TAG, "Close on error " + error);
         synchronized (mLock) {
             if (mIsClosed) return;
             if (error != null) {
@@ -104,7 +111,7 @@
         synchronized (mLock) {
             checkNotClosedLocked();
             mDummyConfig = Objects.requireNonNull(config);
-            Slog.i(TAG, "Ignoring setConfiguration - not applicable for broadcastradio HAL 2.x");
+            Slog.i(TAG, "Ignoring setConfiguration - not applicable for broadcastradio HAL 2.0");
             mModule.fanoutAidlCallback(cb -> cb.onConfigurationChanged(config));
         }
     }
@@ -137,6 +144,10 @@
 
     @Override
     public void step(boolean directionDown, boolean skipSubChannel) throws RemoteException {
+        if (isDebugEnabled()) {
+            Slog.d(TAG, "Step with directionDown " + directionDown
+                    + " skipSubChannel " + skipSubChannel);
+        }
         synchronized (mLock) {
             checkNotClosedLocked();
             int halResult = mHwSession.step(!directionDown);
@@ -146,6 +157,10 @@
 
     @Override
     public void scan(boolean directionDown, boolean skipSubChannel) throws RemoteException {
+        if (isDebugEnabled()) {
+            Slog.d(TAG, "Scan with directionDown " + directionDown
+                    + " skipSubChannel " + skipSubChannel);
+        }
         synchronized (mLock) {
             checkNotClosedLocked();
             int halResult = mHwSession.scan(!directionDown, skipSubChannel);
@@ -155,6 +170,7 @@
 
     @Override
     public void tune(ProgramSelector selector) throws RemoteException {
+        if (isDebugEnabled()) Slog.d(TAG, "Tune with selector " + selector);
         synchronized (mLock) {
             checkNotClosedLocked();
             int halResult = mHwSession.tune(Convert.programSelectorToHal(selector));
@@ -164,6 +180,7 @@
 
     @Override
     public void cancel() {
+        Slog.i(TAG, "Cancel");
         synchronized (mLock) {
             checkNotClosedLocked();
             Utils.maybeRethrow(mHwSession::cancel);
@@ -172,23 +189,25 @@
 
     @Override
     public void cancelAnnouncement() {
-        Slog.i(TAG, "Announcements control doesn't involve cancelling at the HAL level in 2.x");
+        Slog.i(TAG, "Announcements control doesn't involve cancelling at the HAL level in HAL 2.0");
     }
 
     @Override
     public Bitmap getImage(int id) {
+        if (isDebugEnabled()) Slog.d(TAG, "Get image for " + id);
         return mModule.getImage(id);
     }
 
     @Override
     public boolean startBackgroundScan() {
-        Slog.i(TAG, "Explicit background scan trigger is not supported with HAL 2.x");
+        Slog.i(TAG, "Explicit background scan trigger is not supported with HAL 2.0");
         mModule.fanoutAidlCallback(cb -> cb.onBackgroundScanComplete());
         return true;
     }
 
     @Override
     public void startProgramListUpdates(ProgramList.Filter filter) throws RemoteException {
+        if (isDebugEnabled()) Slog.d(TAG, "start programList updates " + filter);
         // If the AIDL client provides a null filter, it wants all updates, so use the most broad
         // filter.
         if (filter == null) {
@@ -247,6 +266,7 @@
 
     @Override
     public void stopProgramListUpdates() throws RemoteException {
+        if (isDebugEnabled()) Slog.d(TAG, "Stop programList updates");
         synchronized (mLock) {
             checkNotClosedLocked();
             mProgramInfoCache = null;
@@ -270,7 +290,7 @@
 
     @Override
     public boolean isConfigFlagSet(int flag) {
-        Slog.v(TAG, "isConfigFlagSet " + ConfigFlag.toString(flag));
+        if (isDebugEnabled()) Slog.d(TAG, "Is ConfigFlagSet for " + ConfigFlag.toString(flag));
         synchronized (mLock) {
             checkNotClosedLocked();
 
@@ -292,7 +312,9 @@
 
     @Override
     public void setConfigFlag(int flag, boolean value) throws RemoteException {
-        Slog.v(TAG, "setConfigFlag " + ConfigFlag.toString(flag) + " = " + value);
+        if (isDebugEnabled()) {
+            Slog.d(TAG, "Set ConfigFlag " + ConfigFlag.toString(flag) + " = " + value);
+        }
         synchronized (mLock) {
             checkNotClosedLocked();
             int halResult = mHwSession.setConfigFlag(flag, value);
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index b5aa7b1..4f3fd64 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -33,6 +33,7 @@
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.display.BrightnessSynchronizer;
+import com.android.server.display.config.AutoBrightness;
 import com.android.server.display.config.BrightnessThresholds;
 import com.android.server.display.config.BrightnessThrottlingMap;
 import com.android.server.display.config.BrightnessThrottlingPoint;
@@ -65,13 +66,13 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
+import java.util.Locale;
 
 import javax.xml.datatype.DatatypeConfigurationException;
 
 /**
- *  Reads and stores display-specific configurations.
- *  File format:
- *  <pre>
+ * Reads and stores display-specific configurations. File format:
+ * <pre>
  *  {@code
  *    <displayConfiguration>
  *      <densityMapping>
@@ -147,6 +148,15 @@
  *       <quirk>canSetBrightnessViaHwc</quirk>
  *      </quirks>
  *
+ *      <autoBrightness>
+ *           <brighteningLightDebounceMillis>
+ *              2000
+ *           </brighteningLightDebounceMillis>
+ *          <darkeningLightDebounceMillis>
+ *              1000
+ *          </darkeningLightDebounceMillis>
+ *      </autoBrightness>
+ *
  *      <screenBrightnessRampFastDecrease>0.01</screenBrightnessRampFastDecrease>
  *      <screenBrightnessRampFastIncrease>0.02</screenBrightnessRampFastIncrease>
  *      <screenBrightnessRampSlowDecrease>0.03</screenBrightnessRampSlowDecrease>
@@ -224,6 +234,9 @@
     // Length of the ambient light horizon used to calculate short-term estimate of ambient light.
     private static final int AMBIENT_LIGHT_SHORT_HORIZON_MILLIS = 2000;
 
+    // Invalid value of AutoBrightness brightening and darkening light debounce
+    private static final int INVALID_AUTO_BRIGHTNESS_LIGHT_DEBOUNCE = -1;
+
     @VisibleForTesting
     static final float HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT = 0.5f;
 
@@ -281,6 +294,14 @@
     private String mLoadedFrom = null;
     private Spline mSdrToHdrRatioSpline;
 
+    // Represents the auto-brightness brightening light debounce.
+    private long mAutoBrightnessBrighteningLightDebounce =
+            INVALID_AUTO_BRIGHTNESS_LIGHT_DEBOUNCE;
+
+    // Represents the auto-brightness darkening light debounce.
+    private long mAutoBrightnessDarkeningLightDebounce =
+            INVALID_AUTO_BRIGHTNESS_LIGHT_DEBOUNCE;
+
     // Brightness Throttling data may be updated via the DeviceConfig. Here we store the original
     // data, which comes from the ddc, and the current one, which may be the DeviceConfig
     // overwritten value.
@@ -293,8 +314,8 @@
     }
 
     /**
-     * Creates an instance for the specified display.
-     * Tries to find a file with identifier in the following priority order:
+     * Creates an instance for the specified display. Tries to find a file with identifier in the
+     * following priority order:
      * <ol>
      *     <li>physicalDisplayId</li>
      *     <li>physicalDisplayId without a stable flag (old system)</li>
@@ -314,11 +335,12 @@
     }
 
     /**
-     * Creates an instance using global values since no display device config xml exists.
-     * Uses values from config or PowerManager.
+     * Creates an instance using global values since no display device config xml exists. Uses
+     * values from config or PowerManager.
      *
-     * @param context
-     * @param useConfigXml
+     * @param context      The context from which the DisplayDeviceConfig is to be constructed.
+     * @param useConfigXml A flag indicating if values are to be loaded from the configuration file,
+     *                     or the default values.
      * @return A configuration instance.
      */
     public static DisplayDeviceConfig create(Context context, boolean useConfigXml) {
@@ -450,8 +472,8 @@
     }
 
     /**
-     * Calculates the backlight value, as recognised by the HAL, from the brightness value
-     * given that the rest of the system deals with.
+     * Calculates the backlight value, as recognised by the HAL, from the brightness value given
+     * that the rest of the system deals with.
      *
      * @param brightness value on the framework scale of 0-1
      * @return backlight value on the HAL scale of 0-1
@@ -502,13 +524,13 @@
 
         if (DEBUG) {
             Slog.d(TAG, "getHdrBrightnessFromSdr: sdr brightness " + brightness
-                + " backlight " + backlight
-                + " nits " + nits
-                + " ratio " + ratio
-                + " hdrNits " + hdrNits
-                + " hdrBacklight " + hdrBacklight
-                + " hdrBrightness " + hdrBrightness
-                );
+                    + " backlight " + backlight
+                    + " nits " + nits
+                    + " ratio " + ratio
+                    + " hdrNits " + hdrNits
+                    + " hdrBacklight " + hdrBacklight
+                    + " hdrBrightness " + hdrBrightness
+            );
         }
         return hdrBrightness;
     }
@@ -590,8 +612,8 @@
 
     /**
      * @param quirkValue The quirk to test.
-     * @return {@code true} if the specified quirk is present in this configuration,
-     * {@code false} otherwise.
+     * @return {@code true} if the specified quirk is present in this configuration, {@code false}
+     * otherwise.
      */
     public boolean hasQuirk(String quirkValue) {
         return mQuirks != null && mQuirks.contains(quirkValue);
@@ -625,6 +647,20 @@
         return BrightnessThrottlingData.create(mBrightnessThrottlingData);
     }
 
+    /**
+     * @return Auto brightness darkening light debounce
+     */
+    public long getAutoBrightnessDarkeningLightDebounce() {
+        return mAutoBrightnessDarkeningLightDebounce;
+    }
+
+    /**
+     * @return Auto brightness brightening light debounce
+     */
+    public long getAutoBrightnessBrighteningLightDebounce() {
+        return mAutoBrightnessBrighteningLightDebounce;
+    }
+
     @Override
     public String toString() {
         return "DisplayDeviceConfig{"
@@ -663,14 +699,18 @@
                 + ", mProximitySensor=" + mProximitySensor
                 + ", mRefreshRateLimitations= " + Arrays.toString(mRefreshRateLimitations.toArray())
                 + ", mDensityMapping= " + mDensityMapping
+                + ", mAutoBrightnessBrighteningLightDebounce= "
+                + mAutoBrightnessBrighteningLightDebounce
+                + ", mAutoBrightnessDarkeningLightDebounce= "
+                + mAutoBrightnessDarkeningLightDebounce
                 + "}";
     }
 
     private static DisplayDeviceConfig getConfigFromSuffix(Context context, File baseDirectory,
             String suffixFormat, long idNumber) {
 
-        final String suffix = String.format(suffixFormat, idNumber);
-        final String filename = String.format(CONFIG_FILE_FORMAT, suffix);
+        final String suffix = String.format(Locale.ROOT, suffixFormat, idNumber);
+        final String filename = String.format(Locale.ROOT, CONFIG_FILE_FORMAT, suffix);
         final File filePath = Environment.buildPath(
                 baseDirectory, ETC_DIR, DISPLAY_CONFIG_DIR, filename);
         final DisplayDeviceConfig config = new DisplayDeviceConfig(context);
@@ -719,6 +759,7 @@
                 loadProxSensorFromDdc(config);
                 loadAmbientHorizonFromDdc(config);
                 loadBrightnessChangeThresholds(config);
+                loadAutoBrightnessConfigValues(config);
             } else {
                 Slog.w(TAG, "DisplayDeviceConfig file is null");
             }
@@ -899,8 +940,8 @@
             if (i > 0) {
                 if (nits[i] < nits[i - 1]) {
                     Slog.e(TAG, "sdrHdrRatioMap must be non-decreasing, ignoring rest "
-                                + " of configuration. nits: " + nits[i] + " < "
-                                + nits[i - 1]);
+                            + " of configuration. nits: " + nits[i] + " < "
+                            + nits[i - 1]);
                     return null;
                 }
             }
@@ -927,7 +968,7 @@
         final List<BrightnessThrottlingPoint> points = map.getBrightnessThrottlingPoint();
         // At least 1 point is guaranteed by the display device config schema
         List<BrightnessThrottlingData.ThrottlingLevel> throttlingLevels =
-            new ArrayList<>(points.size());
+                new ArrayList<>(points.size());
 
         boolean badConfig = false;
         for (BrightnessThrottlingPoint point : points) {
@@ -938,7 +979,7 @@
             }
 
             throttlingLevels.add(new BrightnessThrottlingData.ThrottlingLevel(
-                convertThermalStatus(status), point.getBrightness().floatValue()));
+                    convertThermalStatus(status), point.getBrightness().floatValue()));
         }
 
         if (!badConfig) {
@@ -947,6 +988,41 @@
         }
     }
 
+    private void loadAutoBrightnessConfigValues(DisplayConfiguration config) {
+        loadAutoBrightnessBrighteningLightDebounce(config.getAutoBrightness());
+        loadAutoBrightnessDarkeningLightDebounce(config.getAutoBrightness());
+    }
+
+    /**
+     * Loads the auto-brightness brightening light debounce. Internally, this takes care of loading
+     * the value from the display config, and if not present, falls back to config.xml.
+     */
+    private void loadAutoBrightnessBrighteningLightDebounce(AutoBrightness autoBrightnessConfig) {
+        if (autoBrightnessConfig == null
+                || autoBrightnessConfig.getBrighteningLightDebounceMillis() == null) {
+            mAutoBrightnessBrighteningLightDebounce = mContext.getResources().getInteger(
+                    com.android.internal.R.integer.config_autoBrightnessBrighteningLightDebounce);
+        } else {
+            mAutoBrightnessBrighteningLightDebounce =
+                    autoBrightnessConfig.getBrighteningLightDebounceMillis().intValue();
+        }
+    }
+
+    /**
+     * Loads the auto-brightness darkening light debounce. Internally, this takes care of loading
+     * the value from the display config, and if not present, falls back to config.xml.
+     */
+    private void loadAutoBrightnessDarkeningLightDebounce(AutoBrightness autoBrightnessConfig) {
+        if (autoBrightnessConfig == null
+                || autoBrightnessConfig.getDarkeningLightDebounceMillis() == null) {
+            mAutoBrightnessDarkeningLightDebounce = mContext.getResources().getInteger(
+                    com.android.internal.R.integer.config_autoBrightnessDarkeningLightDebounce);
+        } else {
+            mAutoBrightnessDarkeningLightDebounce =
+                    autoBrightnessConfig.getDarkeningLightDebounceMillis().intValue();
+        }
+    }
+
     private void loadBrightnessMapFromConfigXml() {
         // Use the config.xml mapping
         final Resources res = mContext.getResources();
@@ -1058,17 +1134,17 @@
                     PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, mBacklight[i]);
         }
         mBrightnessToBacklightSpline = mInterpolationType == INTERPOLATION_LINEAR
-            ? Spline.createLinearSpline(mBrightness, mBacklight)
-            : Spline.createSpline(mBrightness, mBacklight);
+                ? Spline.createLinearSpline(mBrightness, mBacklight)
+                : Spline.createSpline(mBrightness, mBacklight);
         mBacklightToBrightnessSpline = mInterpolationType == INTERPOLATION_LINEAR
-            ? Spline.createLinearSpline(mBacklight, mBrightness)
-            : Spline.createSpline(mBacklight, mBrightness);
+                ? Spline.createLinearSpline(mBacklight, mBrightness)
+                : Spline.createSpline(mBacklight, mBrightness);
         mBacklightToNitsSpline = mInterpolationType == INTERPOLATION_LINEAR
-            ? Spline.createLinearSpline(mBacklight, mNits)
-            : Spline.createSpline(mBacklight, mNits);
+                ? Spline.createLinearSpline(mBacklight, mNits)
+                : Spline.createSpline(mBacklight, mNits);
         mNitsToBacklightSpline = mInterpolationType == INTERPOLATION_LINEAR
-            ? Spline.createLinearSpline(mNits, mBacklight)
-            : Spline.createSpline(mNits, mBacklight);
+                ? Spline.createLinearSpline(mNits, mBacklight)
+                : Spline.createSpline(mNits, mBacklight);
     }
 
     private void loadQuirks(DisplayConfiguration config) {
@@ -1111,7 +1187,7 @@
                 if (mHbmData.minimumHdrPercentOfScreen > 1
                         || mHbmData.minimumHdrPercentOfScreen < 0) {
                     Slog.w(TAG, "Invalid minimum HDR percent of screen: "
-                                    + String.valueOf(mHbmData.minimumHdrPercentOfScreen));
+                            + String.valueOf(mHbmData.minimumHdrPercentOfScreen));
                     mHbmData.minimumHdrPercentOfScreen = HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT;
                 }
             } else {
@@ -1235,7 +1311,7 @@
                     ambientBrightnessThresholds.getDarkeningThresholds();
 
             final BigDecimal ambientBrighteningThreshold = brighteningAmbientLux.getMinimum();
-            final BigDecimal ambientDarkeningThreshold =  darkeningAmbientLux.getMinimum();
+            final BigDecimal ambientDarkeningThreshold = darkeningAmbientLux.getMinimum();
 
             if (ambientBrighteningThreshold != null) {
                 mAmbientLuxBrighteningMinThreshold = ambientBrighteningThreshold.floatValue();
@@ -1330,8 +1406,8 @@
         }
 
         /**
-         * @return True if the sensor matches both the specified name and type, or one if only
-         * one is specified (not-empty). Always returns false if both parameters are null or empty.
+         * @return True if the sensor matches both the specified name and type, or one if only one
+         * is specified (not-empty). Always returns false if both parameters are null or empty.
          */
         public boolean matches(String sensorName, String sensorType) {
             final boolean isNameSpecified = !TextUtils.isEmpty(sensorName);
@@ -1446,6 +1522,7 @@
                 return otherThrottlingLevel.thermalStatus == this.thermalStatus
                         && otherThrottlingLevel.brightness == this.brightness;
             }
+
             @Override
             public int hashCode() {
                 int result = 1;
@@ -1455,8 +1532,11 @@
             }
         }
 
-        static public BrightnessThrottlingData create(List<ThrottlingLevel> throttlingLevels)
-        {
+
+        /**
+         * Creates multiple teperature based throttling levels of brightness
+         */
+        public static BrightnessThrottlingData create(List<ThrottlingLevel> throttlingLevels) {
             if (throttlingLevels == null || throttlingLevels.size() == 0) {
                 Slog.e(TAG, "BrightnessThrottlingData received null or empty throttling levels");
                 return null;
@@ -1498,8 +1578,9 @@
         }
 
         static public BrightnessThrottlingData create(BrightnessThrottlingData other) {
-            if (other == null)
+            if (other == null) {
                 return null;
+            }
 
             return BrightnessThrottlingData.create(other.throttlingLevels);
         }
@@ -1508,8 +1589,8 @@
         @Override
         public String toString() {
             return "BrightnessThrottlingData{"
-                + "throttlingLevels:" + throttlingLevels
-                + "} ";
+                    + "throttlingLevels:" + throttlingLevels
+                    + "} ";
         }
 
         @Override
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 6285ef1..b153c1b 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -70,8 +70,6 @@
 import android.hardware.display.DisplayManagerInternal;
 import android.hardware.display.DisplayManagerInternal.DisplayGroupListener;
 import android.hardware.display.DisplayManagerInternal.DisplayTransactionListener;
-import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation;
-import android.hardware.display.DisplayManagerInternal.RefreshRateRange;
 import android.hardware.display.DisplayViewport;
 import android.hardware.display.DisplayedContentSample;
 import android.hardware.display.DisplayedContentSamplingAttributes;
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 8781a8d..9c86076 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -985,10 +985,10 @@
                     screenBrighteningThresholds, screenDarkeningThresholds, screenThresholdLevels,
                     screenDarkeningMinThreshold, screenBrighteningMinThreshold);
 
-            long brighteningLightDebounce = resources.getInteger(
-                    com.android.internal.R.integer.config_autoBrightnessBrighteningLightDebounce);
-            long darkeningLightDebounce = resources.getInteger(
-                    com.android.internal.R.integer.config_autoBrightnessDarkeningLightDebounce);
+            long brighteningLightDebounce = mDisplayDeviceConfig
+                    .getAutoBrightnessBrighteningLightDebounce();
+            long darkeningLightDebounce = mDisplayDeviceConfig
+                    .getAutoBrightnessDarkeningLightDebounce();
             boolean autoBrightnessResetAmbientLuxAfterWarmUp = resources.getBoolean(
                     com.android.internal.R.bool.config_autoBrightnessResetAmbientLuxAfterWarmUp);
 
@@ -1204,6 +1204,7 @@
         }
         assert(state != Display.STATE_UNKNOWN);
 
+        boolean skipRampBecauseOfProximityChangeToNegative = false;
         // Apply the proximity sensor.
         if (mProximitySensor != null) {
             if (mPowerRequest.useProximitySensor && state != Display.STATE_OFF) {
@@ -1241,6 +1242,7 @@
                 // the screen back on.  Also turn it back on if we've been asked to ignore the
                 // prox sensor temporarily.
                 mScreenOffBecauseOfProximity = false;
+                skipRampBecauseOfProximityChangeToNegative = true;
                 sendOnProximityNegativeWithWakelock();
             }
         } else {
@@ -1313,9 +1315,6 @@
         }
 
         final boolean autoBrightnessAdjustmentChanged = updateAutoBrightnessAdjustment();
-        if (autoBrightnessAdjustmentChanged) {
-            mTemporaryAutoBrightnessAdjustment = Float.NaN;
-        }
 
         // Use the autobrightness adjustment override if set.
         final float autoBrightnessAdjustment;
@@ -1523,8 +1522,8 @@
 
             final boolean wasOrWillBeInVr =
                     (state == Display.STATE_VR || oldState == Display.STATE_VR);
-            final boolean initialRampSkip =
-                    state == Display.STATE_ON && mSkipRampState != RAMP_STATE_SKIP_NONE;
+            final boolean initialRampSkip = (state == Display.STATE_ON && mSkipRampState
+                    != RAMP_STATE_SKIP_NONE) || skipRampBecauseOfProximityChangeToNegative;
             // While dozing, sometimes the brightness is split into buckets. Rather than animating
             // through the buckets, which is unlikely to be smooth in the first place, just jump
             // right to the suggested brightness.
@@ -2291,14 +2290,15 @@
 
     private void handleSettingsChange(boolean userSwitch) {
         mPendingScreenBrightnessSetting = getScreenBrightnessSetting();
+        mPendingAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting();
         if (userSwitch) {
             // Don't treat user switches as user initiated change.
             setCurrentScreenBrightness(mPendingScreenBrightnessSetting);
+            updateAutoBrightnessAdjustment();
             if (mAutomaticBrightnessController != null) {
                 mAutomaticBrightnessController.resetShortTermModel();
             }
         }
-        mPendingAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting();
         // We don't bother with a pending variable for VR screen brightness since we just
         // immediately adapt to it.
         mScreenBrightnessForVr = getScreenBrightnessForVrSetting();
@@ -2367,6 +2367,7 @@
         }
         mAutoBrightnessAdjustment = mPendingAutoBrightnessAdjustment;
         mPendingAutoBrightnessAdjustment = Float.NaN;
+        mTemporaryAutoBrightnessAdjustment = Float.NaN;
         return true;
     }
 
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 9d15ed3..faa219e 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -4855,7 +4855,8 @@
     }
 
     @BinderThread
-    private void hideMySoftInput(@NonNull IBinder token, int flags) {
+    private void hideMySoftInput(@NonNull IBinder token, int flags,
+            @SoftInputShowHideReason int reason) {
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.hideMySoftInput");
         synchronized (ImfLock.class) {
             if (!calledWithValidTokenLocked(token)) {
@@ -4863,10 +4864,7 @@
             }
             final long ident = Binder.clearCallingIdentity();
             try {
-                hideCurrentInputLocked(
-                        mLastImeTargetWindow, flags, null,
-                        SoftInputShowHideReason.HIDE_MY_SOFT_INPUT);
-
+                hideCurrentInputLocked(mLastImeTargetWindow, flags, null, reason);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -4884,7 +4882,7 @@
             final long ident = Binder.clearCallingIdentity();
             try {
                 showCurrentInputLocked(mLastImeTargetWindow, flags, null,
-                        SoftInputShowHideReason.SHOW_MY_SOFT_INPUT);
+                        SoftInputShowHideReason.SHOW_SOFT_INPUT_FROM_IME);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -6698,11 +6696,12 @@
 
         @BinderThread
         @Override
-        public void hideMySoftInput(int flags, AndroidFuture future /* T=Void */) {
+        public void hideMySoftInput(int flags, @SoftInputShowHideReason int reason,
+                AndroidFuture future /* T=Void */) {
             @SuppressWarnings("unchecked")
             final AndroidFuture<Void> typedFuture = future;
             try {
-                mImms.hideMySoftInput(mToken, flags);
+                mImms.hideMySoftInput(mToken, flags, reason);
                 typedFuture.complete(null);
             } catch (Throwable e) {
                 typedFuture.completeExceptionally(e);
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 7d12ede..ed8d852 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -335,8 +335,8 @@
 
         @Override // Binder call
         public void stopActiveProjection() {
-            if (mContext.checkCallingPermission(Manifest.permission.MANAGE_MEDIA_PROJECTION)
-                        != PackageManager.PERMISSION_GRANTED) {
+            if (mContext.checkCallingOrSelfPermission(Manifest.permission.MANAGE_MEDIA_PROJECTION)
+                    != PackageManager.PERMISSION_GRANTED) {
                 throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to add "
                         + "projection callbacks");
             }
@@ -393,9 +393,14 @@
                     if (!isValidMediaProjection(projection)) {
                         throw new SecurityException("Invalid media projection");
                     }
-                    LocalServices.getService(
+                    if (!LocalServices.getService(
                             WindowManagerInternal.class).setContentRecordingSession(
-                            incomingSession);
+                            incomingSession)) {
+                        // Unable to start mirroring, so tear down this projection.
+                        if (mProjectionGrant != null) {
+                            mProjectionGrant.stop();
+                        }
+                    }
                 }
             } finally {
                 Binder.restoreCallingIdentity(origId);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 85b0149..0c4273f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -7051,7 +7051,8 @@
             mResolveActivity.processName = pkg.getProcessName();
             mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
             mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS
-                    | ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
+                    | ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS
+                    | ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES;
             mResolveActivity.theme = 0;
             mResolveActivity.exported = true;
             mResolveActivity.enabled = true;
@@ -7084,7 +7085,8 @@
                 mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
                 mResolveActivity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NEVER;
                 mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS
-                        | ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
+                        | ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY
+                        | ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES;
                 mResolveActivity.theme = R.style.Theme_Material_Dialog_Alert;
                 mResolveActivity.exported = true;
                 mResolveActivity.enabled = true;
diff --git a/services/core/java/com/android/server/policy/SideFpsEventHandler.java b/services/core/java/com/android/server/policy/SideFpsEventHandler.java
index af2b902..8582f54 100644
--- a/services/core/java/com/android/server/policy/SideFpsEventHandler.java
+++ b/services/core/java/com/android/server/policy/SideFpsEventHandler.java
@@ -23,11 +23,8 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.app.AlertDialog;
-import android.app.Dialog;
 import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
@@ -35,12 +32,11 @@
 import android.hardware.fingerprint.FingerprintManager;
 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
 import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
-import android.os.Build;
 import android.os.Handler;
 import android.os.PowerManager;
-import android.os.UserHandle;
-import android.provider.Settings;
 import android.util.Log;
+import android.view.View;
+import android.view.Window;
 import android.view.WindowManager;
 
 import com.android.internal.R;
@@ -48,49 +44,48 @@
 
 import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.function.Supplier;
 
 /**
  * Defines behavior for handling interactions between power button events and fingerprint-related
  * operations, for devices where the fingerprint sensor (side fps) lives on the power button.
  */
-public class SideFpsEventHandler {
+public class SideFpsEventHandler implements View.OnClickListener {
 
     private static final int DEBOUNCE_DELAY_MILLIS = 500;
 
-    private int getTapWaitForPowerDuration(Context context) {
-        int tap = context.getResources().getInteger(
-                R.integer.config_sidefpsEnrollPowerPressWindow);
-        if (Build.isDebuggable()) {
-            tap = Settings.Secure.getIntForUser(context.getContentResolver(),
-                    Settings.Secure.FINGERPRINT_SIDE_FPS_ENROLL_TAP_WINDOW, tap,
-                    UserHandle.USER_CURRENT);
-        }
-        return tap;
-    }
-
     private static final String TAG = "SideFpsEventHandler";
 
-    @NonNull private final Context mContext;
-    @NonNull private final Handler mHandler;
-    @NonNull private final PowerManager mPowerManager;
-    @NonNull private final Supplier<AlertDialog.Builder> mDialogSupplier;
-    @NonNull private final AtomicBoolean mSideFpsEventHandlerReady;
-
-    @Nullable private Dialog mDialog;
+    @NonNull
+    private final Context mContext;
+    @NonNull
+    private final Handler mHandler;
+    @NonNull
+    private final PowerManager mPowerManager;
+    @NonNull
+    private final AtomicBoolean mSideFpsEventHandlerReady;
+    private final int mDismissDialogTimeout;
+    @Nullable
+    private SideFpsToast mDialog;
     private final Runnable mTurnOffDialog =
             () -> {
                 dismissDialog("mTurnOffDialog");
             };
-
-    @NonNull private final DialogInterface.OnDismissListener mDialogDismissListener;
-
     private @BiometricStateListener.State int mBiometricState;
-    private final int mTapWaitForPowerDuration;
     private FingerprintManager mFingerprintManager;
+    private DialogProvider mDialogProvider;
+    private long mLastPowerPressTime;
 
-    SideFpsEventHandler(Context context, Handler handler, PowerManager powerManager) {
-        this(context, handler, powerManager, () -> new AlertDialog.Builder(context));
+    SideFpsEventHandler(
+            Context context,
+            Handler handler,
+            PowerManager powerManager) {
+        this(context, handler, powerManager, (ctx) -> {
+            SideFpsToast dialog = new SideFpsToast(ctx);
+            dialog.getWindow()
+                    .setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL);
+            dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
+            return dialog;
+        });
     }
 
     @VisibleForTesting
@@ -98,23 +93,13 @@
             Context context,
             Handler handler,
             PowerManager powerManager,
-            Supplier<AlertDialog.Builder> dialogSupplier) {
+            DialogProvider provider) {
         mContext = context;
         mHandler = handler;
         mPowerManager = powerManager;
-        mDialogSupplier = dialogSupplier;
         mBiometricState = STATE_IDLE;
         mSideFpsEventHandlerReady = new AtomicBoolean(false);
-        mDialogDismissListener =
-                (dialog) -> {
-                    if (mDialog == dialog) {
-                        if (mHandler != null) {
-                            mHandler.removeCallbacks(mTurnOffDialog);
-                        }
-                        mDialog = null;
-                    }
-                };
-
+        mDialogProvider = provider;
         // ensure dialog is dismissed if screen goes off for unrelated reasons
         context.registerReceiver(
                 new BroadcastReceiver() {
@@ -127,7 +112,13 @@
                     }
                 },
                 new IntentFilter(Intent.ACTION_SCREEN_OFF));
-        mTapWaitForPowerDuration = getTapWaitForPowerDuration(context);
+        mDismissDialogTimeout = context.getResources().getInteger(
+                R.integer.config_sideFpsToastTimeout);
+    }
+
+    @Override
+    public void onClick(View v) {
+        goToSleep(mLastPowerPressTime);
     }
 
     /**
@@ -165,8 +156,9 @@
                                 Log.v(TAG, "Detected a tap to turn off dialog, ignoring");
                                 mHandler.removeCallbacks(mTurnOffDialog);
                             }
+                            showDialog(eventTime, "Enroll Power Press");
+                            mHandler.postDelayed(mTurnOffDialog, mDismissDialogTimeout);
                         });
-                showDialog(eventTime, "Enroll Power Press");
                 return true;
             case STATE_BP_AUTH:
                 return true;
@@ -176,54 +168,11 @@
         }
     }
 
-    @NonNull
-    private static Dialog showConfirmDialog(
-            @NonNull AlertDialog.Builder dialogBuilder,
-            @NonNull PowerManager powerManager,
-            long eventTime,
-            @BiometricStateListener.State int biometricState,
-            @NonNull DialogInterface.OnDismissListener dismissListener) {
-        final boolean enrolling = biometricState == STATE_ENROLLING;
-        final int title =
-                enrolling
-                        ? R.string.fp_power_button_enrollment_title
-                        : R.string.fp_power_button_bp_title;
-        final int message =
-                enrolling
-                        ? R.string.fp_power_button_enrollment_message
-                        : R.string.fp_power_button_bp_message;
-        final int positiveText =
-                enrolling
-                        ? R.string.fp_power_button_enrollment_positive_button
-                        : R.string.fp_power_button_bp_positive_button;
-        final int negativeText =
-                enrolling
-                        ? R.string.fp_power_button_enrollment_negative_button
-                        : R.string.fp_power_button_bp_negative_button;
-
-        final Dialog confirmScreenOffDialog =
-                dialogBuilder
-                        .setTitle(title)
-                        .setMessage(message)
-                        .setPositiveButton(
-                                positiveText,
-                                (dialog, which) -> {
-                                    dialog.dismiss();
-                                    powerManager.goToSleep(
-                                            eventTime,
-                                            PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
-                                            0 /* flags */);
-                                })
-                        .setNegativeButton(negativeText, (dialog, which) -> dialog.dismiss())
-                        .setOnDismissListener(dismissListener)
-                        .setCancelable(false)
-                        .create();
-        confirmScreenOffDialog
-                .getWindow()
-                .setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL);
-        confirmScreenOffDialog.show();
-
-        return confirmScreenOffDialog;
+    private void goToSleep(long eventTime) {
+        mPowerManager.goToSleep(
+                eventTime,
+                PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
+                0 /* flags */);
     }
 
     /**
@@ -247,7 +196,8 @@
                         if (fingerprintManager.isPowerbuttonFps()) {
                             fingerprintManager.registerBiometricStateListener(
                                     new BiometricStateListener() {
-                                        @Nullable private Runnable mStateRunnable = null;
+                                        @Nullable
+                                        private Runnable mStateRunnable = null;
 
                                         @Override
                                         public void onStateChanged(
@@ -281,13 +231,6 @@
                                         public void onBiometricAction(
                                                 @BiometricStateListener.Action int action) {
                                             Log.d(TAG, "onBiometricAction " + action);
-                                            switch (action) {
-                                                case BiometricStateListener.ACTION_SENSOR_TOUCH:
-                                                    mHandler.postDelayed(
-                                                            mTurnOffDialog,
-                                                            mTapWaitForPowerDuration);
-                                                    break;
-                                            }
                                         }
                                     });
                             mSideFpsEventHandlerReady.set(true);
@@ -309,12 +252,13 @@
             Log.d(TAG, "Ignoring show dialog");
             return;
         }
-        mDialog =
-                showConfirmDialog(
-                        mDialogSupplier.get(),
-                        mPowerManager,
-                        time,
-                        mBiometricState,
-                        mDialogDismissListener);
+        mDialog = mDialogProvider.provideDialog(mContext);
+        mLastPowerPressTime = time;
+        mDialog.show();
+        mDialog.setOnClickListener(this);
     }
-}
+
+    interface DialogProvider {
+        SideFpsToast provideDialog(Context context);
+    }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/policy/SideFpsToast.java b/services/core/java/com/android/server/policy/SideFpsToast.java
new file mode 100644
index 0000000..db07467
--- /dev/null
+++ b/services/core/java/com/android/server/policy/SideFpsToast.java
@@ -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.server.policy;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.Button;
+
+import com.android.internal.R;
+
+/**
+ * Toast for side fps. This is typically shown during enrollment
+ * when a user presses the power button.
+ *
+ * This dialog is used by {@link SideFpsEventHandler}
+ */
+public class SideFpsToast extends Dialog {
+
+    SideFpsToast(Context context) {
+        super(context);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.side_fps_toast);
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        final Window window = this.getWindow();
+        WindowManager.LayoutParams windowParams = window.getAttributes();
+        windowParams.dimAmount = 0;
+        windowParams.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
+        windowParams.gravity = Gravity.BOTTOM;
+        window.setAttributes(windowParams);
+    }
+
+    /**
+     * Sets the onClickListener for the toast dialog.
+     * @param listener
+     */
+    public void setOnClickListener(View.OnClickListener listener) {
+        final Button turnOffScreen = findViewById(R.id.turn_off_screen);
+        if (turnOffScreen != null) {
+            turnOffScreen.setOnClickListener(listener);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/vibrator/AbstractVibratorStep.java b/services/core/java/com/android/server/vibrator/AbstractVibratorStep.java
index 12e68b1..eebd046 100644
--- a/services/core/java/com/android/server/vibrator/AbstractVibratorStep.java
+++ b/services/core/java/com/android/server/vibrator/AbstractVibratorStep.java
@@ -96,6 +96,7 @@
                     "Turning off vibrator " + getVibratorId());
         }
         controller.off();
+        getVibration().stats().reportVibratorOff();
     }
 
     protected void changeAmplitude(float amplitude) {
@@ -104,6 +105,7 @@
                     "Amplitude changed on vibrator " + getVibratorId() + " to " + amplitude);
         }
         controller.setAmplitude(amplitude);
+        getVibration().stats().reportSetAmplitude();
     }
 
     /**
@@ -147,6 +149,8 @@
         if (nextSegmentIndex >= effectSize && repeatIndex >= 0) {
             // Count the loops that were played.
             int loopSize = effectSize - repeatIndex;
+            int loopSegmentsPlayed = nextSegmentIndex - repeatIndex;
+            getVibration().stats().reportRepetition(loopSegmentsPlayed / loopSize);
             nextSegmentIndex = repeatIndex + ((nextSegmentIndex - effectSize) % loopSize);
         }
         Step nextStep = conductor.nextVibrateStep(nextStartTime, controller, effect,
diff --git a/services/core/java/com/android/server/vibrator/ComposePrimitivesVibratorStep.java b/services/core/java/com/android/server/vibrator/ComposePrimitivesVibratorStep.java
index 3bc11c8..f8b9926 100644
--- a/services/core/java/com/android/server/vibrator/ComposePrimitivesVibratorStep.java
+++ b/services/core/java/com/android/server/vibrator/ComposePrimitivesVibratorStep.java
@@ -67,9 +67,10 @@
                 Slog.d(VibrationThread.TAG, "Compose " + primitives + " primitives on vibrator "
                         + controller.getVibratorInfo().getId());
             }
-            mVibratorOnResult = controller.on(
-                    primitives.toArray(new PrimitiveSegment[primitives.size()]),
-                    getVibration().id);
+            PrimitiveSegment[] primitivesArray =
+                    primitives.toArray(new PrimitiveSegment[primitives.size()]);
+            mVibratorOnResult = controller.on(primitivesArray, getVibration().id);
+            getVibration().stats().reportComposePrimitives(mVibratorOnResult, primitivesArray);
 
             return nextSteps(/* segmentsPlayed= */ primitives.size());
         } finally {
diff --git a/services/core/java/com/android/server/vibrator/ComposePwleVibratorStep.java b/services/core/java/com/android/server/vibrator/ComposePwleVibratorStep.java
index 919f1be..81f52c9 100644
--- a/services/core/java/com/android/server/vibrator/ComposePwleVibratorStep.java
+++ b/services/core/java/com/android/server/vibrator/ComposePwleVibratorStep.java
@@ -68,8 +68,9 @@
                 Slog.d(VibrationThread.TAG, "Compose " + pwles + " PWLEs on vibrator "
                         + controller.getVibratorInfo().getId());
             }
-            mVibratorOnResult = controller.on(pwles.toArray(new RampSegment[pwles.size()]),
-                    getVibration().id);
+            RampSegment[] pwlesArray = pwles.toArray(new RampSegment[pwles.size()]);
+            mVibratorOnResult = controller.on(pwlesArray, getVibration().id);
+            getVibration().stats().reportComposePwle(mVibratorOnResult, pwlesArray);
 
             return nextSteps(/* segmentsPlayed= */ pwles.size());
         } finally {
diff --git a/services/core/java/com/android/server/vibrator/PerformPrebakedVibratorStep.java b/services/core/java/com/android/server/vibrator/PerformPrebakedVibratorStep.java
index 601ae97..419021478 100644
--- a/services/core/java/com/android/server/vibrator/PerformPrebakedVibratorStep.java
+++ b/services/core/java/com/android/server/vibrator/PerformPrebakedVibratorStep.java
@@ -62,6 +62,7 @@
 
             VibrationEffect fallback = getVibration().getFallback(prebaked.getEffectId());
             mVibratorOnResult = controller.on(prebaked, getVibration().id);
+            getVibration().stats().reportPerformEffect(mVibratorOnResult, prebaked);
 
             if (mVibratorOnResult == 0 && prebaked.shouldFallback()
                     && (fallback instanceof VibrationEffect.Composed)) {
diff --git a/services/core/java/com/android/server/vibrator/SetAmplitudeVibratorStep.java b/services/core/java/com/android/server/vibrator/SetAmplitudeVibratorStep.java
index 1f0d2d7..6fb9111 100644
--- a/services/core/java/com/android/server/vibrator/SetAmplitudeVibratorStep.java
+++ b/services/core/java/com/android/server/vibrator/SetAmplitudeVibratorStep.java
@@ -148,7 +148,9 @@
                     "Turning on vibrator " + controller.getVibratorInfo().getId() + " for "
                             + duration + "ms");
         }
-        return controller.on(duration, getVibration().id);
+        long vibratorOnResult = controller.on(duration, getVibration().id);
+        getVibration().stats().reportVibratorOn(vibratorOnResult);
+        return vibratorOnResult;
     }
 
     /**
diff --git a/services/core/java/com/android/server/vibrator/StartSequentialEffectStep.java b/services/core/java/com/android/server/vibrator/StartSequentialEffectStep.java
index 080a36c..2c6fbbc9 100644
--- a/services/core/java/com/android/server/vibrator/StartSequentialEffectStep.java
+++ b/services/core/java/com/android/server/vibrator/StartSequentialEffectStep.java
@@ -93,10 +93,8 @@
             }
 
             mVibratorsOnMaxDuration = startVibrating(effectMapping, nextSteps);
-            if (mVibratorsOnMaxDuration > 0) {
-                conductor.vibratorManagerHooks.noteVibratorOn(conductor.getVibration().uid,
-                        mVibratorsOnMaxDuration);
-            }
+            conductor.vibratorManagerHooks.noteVibratorOn(conductor.getVibration().uid,
+                    mVibratorsOnMaxDuration);
         } finally {
             if (mVibratorsOnMaxDuration >= 0) {
                 // It least one vibrator was started then add a finish step to wait for all
diff --git a/services/core/java/com/android/server/vibrator/Vibration.java b/services/core/java/com/android/server/vibrator/Vibration.java
index d79837b..a375d0a 100644
--- a/services/core/java/com/android/server/vibrator/Vibration.java
+++ b/services/core/java/com/android/server/vibrator/Vibration.java
@@ -16,10 +16,10 @@
 
 package com.android.server.vibrator;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.CombinedVibration;
 import android.os.IBinder;
-import android.os.SystemClock;
 import android.os.VibrationAttributes;
 import android.os.VibrationEffect;
 import android.os.vibrator.PrebakedSegment;
@@ -30,48 +30,60 @@
 import android.util.SparseArray;
 import android.util.proto.ProtoOutputStream;
 
+import com.android.internal.util.FrameworkStatsLog;
+
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.List;
+import java.util.Objects;
 import java.util.concurrent.CountDownLatch;
 import java.util.function.Function;
 
 /** Represents a vibration request to the vibrator service. */
 final class Vibration {
-    private static final String TAG = "Vibration";
     private static final SimpleDateFormat DEBUG_DATE_FORMAT =
             new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
 
+    /** Vibration status with reference to values from vibratormanagerservice.proto for logging. */
     enum Status {
-        RUNNING,
-        FINISHED,
-        FINISHED_UNEXPECTED,  // Didn't terminate in the usual way.
-        FORWARDED_TO_INPUT_DEVICES,
-        CANCELLED_BINDER_DIED,
-        CANCELLED_BY_SCREEN_OFF,
-        CANCELLED_BY_SETTINGS_UPDATE,
-        CANCELLED_BY_USER,
-        CANCELLED_BY_UNKNOWN_REASON,
-        CANCELLED_SUPERSEDED,
-        IGNORED_ERROR_APP_OPS,
-        IGNORED_ERROR_CANCELLING,
-        IGNORED_ERROR_SCHEDULING,
-        IGNORED_ERROR_TOKEN,
-        IGNORED_APP_OPS,
-        IGNORED_BACKGROUND,
-        IGNORED_UNKNOWN_VIBRATION,
-        IGNORED_UNSUPPORTED,
-        IGNORED_FOR_EXTERNAL,
-        IGNORED_FOR_HIGHER_IMPORTANCE,
-        IGNORED_FOR_ONGOING,
-        IGNORED_FOR_POWER,
-        IGNORED_FOR_RINGER_MODE,
-        IGNORED_FOR_SETTINGS,
-        IGNORED_SUPERSEDED,
+        UNKNOWN(VibrationProto.UNKNOWN),
+        RUNNING(VibrationProto.RUNNING),
+        FINISHED(VibrationProto.FINISHED),
+        FINISHED_UNEXPECTED(VibrationProto.FINISHED_UNEXPECTED),
+        FORWARDED_TO_INPUT_DEVICES(VibrationProto.FORWARDED_TO_INPUT_DEVICES),
+        CANCELLED_BINDER_DIED(VibrationProto.CANCELLED_BINDER_DIED),
+        CANCELLED_BY_SCREEN_OFF(VibrationProto.CANCELLED_BY_SCREEN_OFF),
+        CANCELLED_BY_SETTINGS_UPDATE(VibrationProto.CANCELLED_BY_SETTINGS_UPDATE),
+        CANCELLED_BY_USER(VibrationProto.CANCELLED_BY_USER),
+        CANCELLED_BY_UNKNOWN_REASON(VibrationProto.CANCELLED_BY_UNKNOWN_REASON),
+        CANCELLED_SUPERSEDED(VibrationProto.CANCELLED_SUPERSEDED),
+        IGNORED_ERROR_APP_OPS(VibrationProto.IGNORED_ERROR_APP_OPS),
+        IGNORED_ERROR_CANCELLING(VibrationProto.IGNORED_ERROR_CANCELLING),
+        IGNORED_ERROR_SCHEDULING(VibrationProto.IGNORED_ERROR_SCHEDULING),
+        IGNORED_ERROR_TOKEN(VibrationProto.IGNORED_ERROR_TOKEN),
+        IGNORED_APP_OPS(VibrationProto.IGNORED_APP_OPS),
+        IGNORED_BACKGROUND(VibrationProto.IGNORED_BACKGROUND),
+        IGNORED_UNKNOWN_VIBRATION(VibrationProto.IGNORED_UNKNOWN_VIBRATION),
+        IGNORED_UNSUPPORTED(VibrationProto.IGNORED_UNSUPPORTED),
+        IGNORED_FOR_EXTERNAL(VibrationProto.IGNORED_FOR_EXTERNAL),
+        IGNORED_FOR_HIGHER_IMPORTANCE(VibrationProto.IGNORED_FOR_HIGHER_IMPORTANCE),
+        IGNORED_FOR_ONGOING(VibrationProto.IGNORED_FOR_ONGOING),
+        IGNORED_FOR_POWER(VibrationProto.IGNORED_FOR_POWER),
+        IGNORED_FOR_RINGER_MODE(VibrationProto.IGNORED_FOR_RINGER_MODE),
+        IGNORED_FOR_SETTINGS(VibrationProto.IGNORED_FOR_SETTINGS),
+        IGNORED_SUPERSEDED(VibrationProto.IGNORED_SUPERSEDED);
+
+        private final int mProtoEnumValue;
+
+        Status(int value) {
+            mProtoEnumValue = value;
+        }
+
+        public int getProtoEnumValue() {
+            return mProtoEnumValue;
+        }
     }
 
-    /** Start time using {@link SystemClock#uptimeMillis()}, for calculations. */
-    public final long startUptimeMillis;
     public final VibrationAttributes attrs;
     public final long id;
     public final int uid;
@@ -91,17 +103,11 @@
     @Nullable
     private CombinedVibration mOriginalEffect;
 
-    /**
-     * Start/end times in unix epoch time. Only to be used for debugging purposes and to correlate
-     * with other system events, any duration calculations should be done use
-     * {@link #startUptimeMillis} so as not to be affected by discontinuities created by RTC
-     * adjustments.
-     */
-    private final long mStartTimeDebug;
-    private long mEndTimeDebug;
-    /** End time using {@link SystemClock#uptimeMillis()}, for calculations. */
-    private long mEndUptimeMillis;
-    private Status mStatus;
+    /** Vibration status. */
+    private Vibration.Status mStatus;
+
+    /** Vibration runtime stats. */
+    private final VibrationStats mStats = new VibrationStats();
 
     /** A {@link CountDownLatch} to enable waiting for completion. */
     private final CountDownLatch mCompletionLatch = new CountDownLatch(1);
@@ -111,34 +117,35 @@
         this.token = token;
         this.mEffect = effect;
         this.id = id;
-        this.startUptimeMillis = SystemClock.uptimeMillis();
         this.attrs = attrs;
         this.uid = uid;
         this.opPkg = opPkg;
         this.reason = reason;
-        mStartTimeDebug = System.currentTimeMillis();
-        mStatus = Status.RUNNING;
+        mStatus = Vibration.Status.RUNNING;
+    }
+
+    VibrationStats stats() {
+        return mStats;
     }
 
     /**
-     * Set the {@link Status} of this vibration and the current system time as this
+     * Set the {@link Status} of this vibration and reports the current system time as this
      * vibration end time, for debugging purposes.
      *
      * <p>This method will only accept given value if the current status is {@link
      * Status#RUNNING}.
      */
-    public void end(Status status) {
+    public void end(EndInfo info) {
         if (hasEnded()) {
             // Vibration already ended, keep first ending status set and ignore this one.
             return;
         }
-        mStatus = status;
-        mEndUptimeMillis = SystemClock.uptimeMillis();
-        mEndTimeDebug = System.currentTimeMillis();
+        mStatus = info.status;
+        mStats.reportEnded(info.endedByUid, info.endedByUsage);
         mCompletionLatch.countDown();
     }
 
-    /** Waits indefinitely until another thread calls {@link #end(Status)} on this vibration. */
+    /** Waits indefinitely until another thread calls {@link #end} on this vibration. */
     public void waitForEnd() throws InterruptedException {
         mCompletionLatch.await();
     }
@@ -228,16 +235,69 @@
 
     /** Return {@link Vibration.DebugInfo} with read-only debug information about this vibration. */
     public Vibration.DebugInfo getDebugInfo() {
-        long durationMs = hasEnded() ? mEndUptimeMillis - startUptimeMillis : -1;
-        return new Vibration.DebugInfo(
-                mStartTimeDebug, mEndTimeDebug, durationMs, mEffect, mOriginalEffect,
-                /* scale= */ 0, attrs, uid, opPkg, reason, mStatus);
+        return new Vibration.DebugInfo(mStatus, mStats, mEffect, mOriginalEffect, /* scale= */ 0,
+                attrs, uid, opPkg, reason);
+    }
+
+    /** Return {@link VibrationStats.StatsInfo} with read-only metrics about this vibration. */
+    public VibrationStats.StatsInfo getStatsInfo(long completionUptimeMillis) {
+        int vibrationType = isRepeating()
+                ? FrameworkStatsLog.VIBRATION_REPORTED__VIBRATION_TYPE__REPEATED
+                : FrameworkStatsLog.VIBRATION_REPORTED__VIBRATION_TYPE__SINGLE;
+        return new VibrationStats.StatsInfo(
+                uid, vibrationType, attrs.getUsage(), mStatus, mStats, completionUptimeMillis);
+    }
+
+    /** Immutable info passed as a signal to end a vibration. */
+    static final class EndInfo {
+        /** The {@link Status} to be set to the vibration when it ends with this info. */
+        @NonNull
+        public final Status status;
+        /** The UID that triggered the vibration that ended this, or -1 if undefined. */
+        public final int endedByUid;
+        /** The VibrationAttributes.USAGE_* of the vibration that ended this, or -1 if undefined. */
+        public final int endedByUsage;
+
+        EndInfo(@NonNull Vibration.Status status) {
+            this(status, /* endedByUid= */ -1, /* endedByUsage= */ -1);
+        }
+
+        EndInfo(@NonNull Vibration.Status status, int endedByUid, int endedByUsage) {
+            this.status = status;
+            this.endedByUid = endedByUid;
+            this.endedByUsage = endedByUsage;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (!(o instanceof EndInfo)) return false;
+            EndInfo that = (EndInfo) o;
+            return endedByUid == that.endedByUid
+                    && endedByUsage == that.endedByUsage
+                    && status == that.status;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(status, endedByUid, endedByUsage);
+        }
+
+        @Override
+        public String toString() {
+            return "EndInfo{"
+                    + "status=" + status
+                    + ", endedByUid=" + endedByUid
+                    + ", endedByUsage=" + endedByUsage
+                    + '}';
+        }
     }
 
     /** Debug information about vibrations. */
     static final class DebugInfo {
-        private final long mStartTimeDebug;
-        private final long mEndTimeDebug;
+        private final long mCreateTime;
+        private final long mStartTime;
+        private final long mEndTime;
         private final long mDurationMs;
         private final CombinedVibration mEffect;
         private final CombinedVibration mOriginalEffect;
@@ -248,12 +308,13 @@
         private final String mReason;
         private final Status mStatus;
 
-        DebugInfo(long startTimeDebug, long endTimeDebug, long durationMs,
-                CombinedVibration effect, CombinedVibration originalEffect, float scale,
-                VibrationAttributes attrs, int uid, String opPkg, String reason, Status status) {
-            mStartTimeDebug = startTimeDebug;
-            mEndTimeDebug = endTimeDebug;
-            mDurationMs = durationMs;
+        DebugInfo(Status status, VibrationStats stats, @Nullable CombinedVibration effect,
+                @Nullable CombinedVibration originalEffect, float scale, VibrationAttributes attrs,
+                int uid, String opPkg, String reason) {
+            mCreateTime = stats.getCreateTimeDebug();
+            mStartTime = stats.getStartTimeDebug();
+            mEndTime = stats.getEndTimeDebug();
+            mDurationMs = stats.getDurationDebug();
             mEffect = effect;
             mOriginalEffect = originalEffect;
             mScale = scale;
@@ -267,11 +328,13 @@
         @Override
         public String toString() {
             return new StringBuilder()
-                    .append("startTime: ")
-                    .append(DEBUG_DATE_FORMAT.format(new Date(mStartTimeDebug)))
+                    .append("createTime: ")
+                    .append(DEBUG_DATE_FORMAT.format(new Date(mCreateTime)))
+                    .append(", startTime: ")
+                    .append(DEBUG_DATE_FORMAT.format(new Date(mStartTime)))
                     .append(", endTime: ")
-                    .append(mEndTimeDebug == 0 ? null
-                            : DEBUG_DATE_FORMAT.format(new Date(mEndTimeDebug)))
+                    .append(mEndTime == 0 ? null
+                            : DEBUG_DATE_FORMAT.format(new Date(mEndTime)))
                     .append(", durationMs: ")
                     .append(mDurationMs)
                     .append(", status: ")
@@ -296,8 +359,8 @@
         /** Write this info into given {@code fieldId} on {@link ProtoOutputStream}. */
         public void dumpProto(ProtoOutputStream proto, long fieldId) {
             final long token = proto.start(fieldId);
-            proto.write(VibrationProto.START_TIME, mStartTimeDebug);
-            proto.write(VibrationProto.END_TIME, mEndTimeDebug);
+            proto.write(VibrationProto.START_TIME, mStartTime);
+            proto.write(VibrationProto.END_TIME, mEndTime);
             proto.write(VibrationProto.DURATION_MS, mDurationMs);
             proto.write(VibrationProto.STATUS, mStatus.ordinal());
 
@@ -421,4 +484,5 @@
             proto.end(token);
         }
     }
+
 }
diff --git a/services/core/java/com/android/server/vibrator/VibrationStats.java b/services/core/java/com/android/server/vibrator/VibrationStats.java
new file mode 100644
index 0000000..931be1d
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/VibrationStats.java
@@ -0,0 +1,395 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vibrator;
+
+import android.os.SystemClock;
+import android.os.vibrator.PrebakedSegment;
+import android.os.vibrator.PrimitiveSegment;
+import android.os.vibrator.RampSegment;
+import android.util.Slog;
+import android.util.SparseBooleanArray;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FrameworkStatsLog;
+
+/** Holds basic stats about the vibration playback and interaction with the vibrator HAL. */
+final class VibrationStats {
+    static final String TAG = "VibrationStats";
+
+    // Milestone timestamps, using SystemClock.uptimeMillis(), for calculations.
+    // - Create: time a vibration object was created, which is closer to when the service receives a
+    //           vibrate request.
+    // - Start: time a vibration started to play, which is closer to the time that the
+    //          VibrationEffect started playing the very first segment.
+    // - End: time a vibration ended, even if it never started to play. This can be as soon as the
+    //        vibrator HAL reports it has finished the last command, or before it has even started
+    //        when the vibration is ignored or cancelled.
+    // Create and end times set by VibratorManagerService only, guarded by its lock.
+    // Start times set by VibrationThread only (single-threaded).
+    private long mCreateUptimeMillis;
+    private long mStartUptimeMillis;
+    private long mEndUptimeMillis;
+
+    // Milestone timestamps, using unix epoch time, only to be used for debugging purposes and
+    // to correlate with other system events. Any duration calculations should be done with the
+    // {create/start/end}UptimeMillis counterparts so as not to be affected by discontinuities
+    // created by RTC adjustments.
+    // Set together with the *UptimeMillis counterparts.
+    private long mCreateTimeDebug;
+    private long mStartTimeDebug;
+    private long mEndTimeDebug;
+
+    // Vibration interruption tracking.
+    // Set by VibratorManagerService only, guarded by its lock.
+    private int mEndedByUid;
+    private int mEndedByUsage;
+    private int mInterruptedUsage;
+
+    // All following counters are set by VibrationThread only (single-threaded):
+    // Counts how many times the VibrationEffect was repeated.
+    private int mRepeatCount;
+    // Total duration, in milliseconds, the vibrator was active with non-zero amplitude.
+    private int mVibratorOnTotalDurationMillis;
+    // Total number of primitives used in compositions.
+    private int mVibrationCompositionTotalSize;
+    private int mVibrationPwleTotalSize;
+    // Counts how many times each IVibrator method was triggered by this vibration.
+    private int mVibratorOnCount;
+    private int mVibratorOffCount;
+    private int mVibratorSetAmplitudeCount;
+    private int mVibratorSetExternalControlCount;
+    private int mVibratorPerformCount;
+    private int mVibratorComposeCount;
+    private int mVibratorComposePwleCount;
+
+    // Ids of vibration effects and primitives used by this vibration, with support flag.
+    // Set by VibrationThread only (single-threaded).
+    private SparseBooleanArray mVibratorEffectsUsed = new SparseBooleanArray();
+    private SparseBooleanArray mVibratorPrimitivesUsed = new SparseBooleanArray();
+
+    VibrationStats() {
+        mCreateUptimeMillis = SystemClock.uptimeMillis();
+        mCreateTimeDebug = System.currentTimeMillis();
+        // Set invalid UID and VibrationAttributes.USAGE values to indicate fields are unset.
+        mEndedByUid = -1;
+        mEndedByUsage = -1;
+        mInterruptedUsage = -1;
+    }
+
+    long getCreateUptimeMillis() {
+        return mCreateUptimeMillis;
+    }
+
+    long getStartUptimeMillis() {
+        return mStartUptimeMillis;
+    }
+
+    long getEndUptimeMillis() {
+        return mEndUptimeMillis;
+    }
+
+    long getCreateTimeDebug() {
+        return mCreateTimeDebug;
+    }
+
+    long getStartTimeDebug() {
+        return mStartTimeDebug;
+    }
+
+    long getEndTimeDebug() {
+        return mEndTimeDebug;
+    }
+
+    /**
+     * Duration calculated for debugging purposes, between the creation of a vibration and the
+     * end time being reported, or -1 if the vibration has not ended.
+     */
+    long getDurationDebug() {
+        return hasEnded() ? (mEndUptimeMillis - mCreateUptimeMillis) : -1;
+    }
+
+    /** Return true if vibration reported it has ended. */
+    boolean hasEnded() {
+        return mEndUptimeMillis > 0;
+    }
+
+    /** Return true if vibration reported it has started triggering the vibrator. */
+    boolean hasStarted() {
+        return mStartUptimeMillis > 0;
+    }
+
+    /**
+     * Set the current system time as this vibration start time, for debugging purposes.
+     *
+     * <p>This indicates the vibration has started to interact with the vibrator HAL and the
+     * device may start vibrating after this point.
+     *
+     * <p>This method will only accept given value if the start timestamp was never set.
+     */
+    void reportStarted() {
+        if (hasEnded() || (mStartUptimeMillis != 0)) {
+            // Vibration already started or ended, keep first time set and ignore this one.
+            return;
+        }
+        mStartUptimeMillis = SystemClock.uptimeMillis();
+        mStartTimeDebug = System.currentTimeMillis();
+    }
+
+    /**
+     * Set status and end cause for this vibration to end, and the current system time as this
+     * vibration end time, for debugging purposes.
+     *
+     * <p>This might be triggered before {@link #reportStarted()}, which indicates this
+     * vibration was cancelled or ignored before it started triggering the vibrator.
+     *
+     * @return true if the status was accepted. This method will only accept given values if
+     * the end timestamp was never set.
+     */
+    boolean reportEnded(int endedByUid, int endedByUsage) {
+        if (hasEnded()) {
+            // Vibration already ended, keep first ending stats set and ignore this one.
+            return false;
+        }
+        mEndedByUid = endedByUid;
+        mEndedByUsage = endedByUsage;
+        mEndUptimeMillis = SystemClock.uptimeMillis();
+        mEndTimeDebug = System.currentTimeMillis();
+        return true;
+    }
+
+    /**
+     * Report this vibration has interrupted another vibration.
+     *
+     * <p>This method will only accept the first value as the one that was interrupted by this
+     * vibration, and will ignore all successive calls.
+     */
+    void reportInterruptedAnotherVibration(int interruptedUsage) {
+        if (mInterruptedUsage < 0) {
+            mInterruptedUsage = interruptedUsage;
+        }
+    }
+
+    /** Report the vibration has looped a few more times. */
+    void reportRepetition(int loops) {
+        mRepeatCount += loops;
+    }
+
+    /** Report a call to vibrator method to turn on for given duration. */
+    void reportVibratorOn(long halResult) {
+        mVibratorOnCount++;
+
+        if (halResult > 0) {
+            // If HAL result is positive then it represents the actual duration it will be ON.
+            mVibratorOnTotalDurationMillis += (int) halResult;
+        }
+    }
+
+    /** Report a call to vibrator method to turn off. */
+    void reportVibratorOff() {
+        mVibratorOffCount++;
+    }
+
+    /** Report a call to vibrator method to change the vibration amplitude. */
+    void reportSetAmplitude() {
+        mVibratorSetAmplitudeCount++;
+    }
+
+    /** Report a call to vibrator method to trigger a vibration effect. */
+    void reportPerformEffect(long halResult, PrebakedSegment prebaked) {
+        mVibratorPerformCount++;
+
+        if (halResult > 0) {
+            // If HAL result is positive then it represents the actual duration of the vibration.
+            mVibratorEffectsUsed.put(prebaked.getEffectId(), true);
+            mVibratorOnTotalDurationMillis += (int) halResult;
+        } else {
+            // Effect unsupported or request failed.
+            mVibratorEffectsUsed.put(prebaked.getEffectId(), false);
+        }
+    }
+
+    /** Report a call to vibrator method to trigger a vibration as a composition of primitives. */
+    void reportComposePrimitives(long halResult, PrimitiveSegment[] primitives) {
+        mVibratorComposeCount++;
+        mVibrationCompositionTotalSize += primitives.length;
+
+        if (halResult > 0) {
+            // If HAL result is positive then it represents the actual duration of the vibration.
+            // Remove the requested delays to update the total time the vibrator was ON.
+            for (PrimitiveSegment primitive : primitives) {
+                halResult -= primitive.getDelay();
+                mVibratorPrimitivesUsed.put(primitive.getPrimitiveId(), true);
+            }
+            if (halResult > 0) {
+                mVibratorOnTotalDurationMillis += (int) halResult;
+            }
+        } else {
+            // One or more primitives were unsupported, or request failed.
+            for (PrimitiveSegment primitive : primitives) {
+                mVibratorPrimitivesUsed.put(primitive.getPrimitiveId(), false);
+            }
+        }
+    }
+
+    /** Report a call to vibrator method to trigger a vibration as a PWLE. */
+    void reportComposePwle(long halResult, RampSegment[] segments) {
+        mVibratorComposePwleCount++;
+        mVibrationPwleTotalSize += segments.length;
+
+        if (halResult > 0) {
+            // If HAL result is positive then it represents the actual duration of the vibration.
+            // Remove the zero-amplitude segments to update the total time the vibrator was ON.
+            for (RampSegment ramp : segments) {
+                if ((ramp.getStartAmplitude() == 0) && (ramp.getEndAmplitude() == 0)) {
+                    halResult -= ramp.getDuration();
+                }
+            }
+            if (halResult > 0) {
+                mVibratorOnTotalDurationMillis += (int) halResult;
+            }
+        }
+    }
+
+    /**
+     * Increment the stats for total number of times the {@code setExternalControl} method was
+     * triggered in the vibrator HAL.
+     */
+    void reportSetExternalControl() {
+        mVibratorSetExternalControlCount++;
+    }
+
+    /**
+     * Immutable metrics about this vibration, to be kept in memory until it can be pushed through
+     * {@link com.android.internal.util.FrameworkStatsLog} as a
+     * {@link com.android.internal.util.FrameworkStatsLog#VIBRATION_REPORTED}.
+     */
+    static final class StatsInfo {
+        public final int uid;
+        public final int vibrationType;
+        public final int usage;
+        public final int status;
+        public final boolean endedBySameUid;
+        public final int endedByUsage;
+        public final int interruptedUsage;
+        public final int repeatCount;
+        public final int totalDurationMillis;
+        public final int vibratorOnMillis;
+        public final int startLatencyMillis;
+        public final int endLatencyMillis;
+        public final int halComposeCount;
+        public final int halComposePwleCount;
+        public final int halOnCount;
+        public final int halOffCount;
+        public final int halPerformCount;
+        public final int halSetAmplitudeCount;
+        public final int halSetExternalControlCount;
+        public final int halCompositionSize;
+        public final int halPwleSize;
+        public final int[] halSupportedCompositionPrimitivesUsed;
+        public final int[] halSupportedEffectsUsed;
+        public final int[] halUnsupportedCompositionPrimitivesUsed;
+        public final int[] halUnsupportedEffectsUsed;
+        private boolean mIsWritten;
+
+        StatsInfo(int uid, int vibrationType, int usage, Vibration.Status status,
+                VibrationStats stats, long completionUptimeMillis) {
+            this.uid = uid;
+            this.vibrationType = vibrationType;
+            this.usage = usage;
+            this.status = status.getProtoEnumValue();
+            endedBySameUid = (uid == stats.mEndedByUid);
+            endedByUsage = stats.mEndedByUsage;
+            interruptedUsage = stats.mInterruptedUsage;
+            repeatCount = stats.mRepeatCount;
+
+            // This duration goes from the time this object was created until the time it was
+            // completed. We can use latencies to detect the times between first and last
+            // interaction with vibrator.
+            totalDurationMillis =
+                    (int) Math.max(0,  completionUptimeMillis - stats.mCreateUptimeMillis);
+            vibratorOnMillis = stats.mVibratorOnTotalDurationMillis;
+
+            if (stats.hasStarted()) {
+                // We only measure latencies for vibrations that actually triggered the vibrator.
+                startLatencyMillis =
+                        (int) Math.max(0, stats.mStartUptimeMillis - stats.mCreateUptimeMillis);
+                endLatencyMillis =
+                        (int) Math.max(0, completionUptimeMillis - stats.mEndUptimeMillis);
+            } else {
+                startLatencyMillis = endLatencyMillis = 0;
+            }
+
+            halComposeCount = stats.mVibratorComposeCount;
+            halComposePwleCount = stats.mVibratorComposePwleCount;
+            halOnCount = stats.mVibratorOnCount;
+            halOffCount = stats.mVibratorOffCount;
+            halPerformCount = stats.mVibratorPerformCount;
+            halSetAmplitudeCount = stats.mVibratorSetAmplitudeCount;
+            halSetExternalControlCount = stats.mVibratorSetExternalControlCount;
+            halCompositionSize = stats.mVibrationCompositionTotalSize;
+            halPwleSize = stats.mVibrationPwleTotalSize;
+            halSupportedCompositionPrimitivesUsed =
+                    filteredKeys(stats.mVibratorPrimitivesUsed, /* supported= */ true);
+            halSupportedEffectsUsed =
+                    filteredKeys(stats.mVibratorEffectsUsed, /* supported= */ true);
+            halUnsupportedCompositionPrimitivesUsed =
+                    filteredKeys(stats.mVibratorPrimitivesUsed, /* supported= */ false);
+            halUnsupportedEffectsUsed =
+                    filteredKeys(stats.mVibratorEffectsUsed, /* supported= */ false);
+        }
+
+        @VisibleForTesting
+        boolean isWritten() {
+            return mIsWritten;
+        }
+
+        void writeVibrationReported() {
+            if (mIsWritten) {
+                Slog.wtf(TAG, "Writing same vibration stats multiple times for uid=" + uid);
+            }
+            mIsWritten = true;
+            // Mapping from this MetricInfo representation and the atom proto VibrationReported.
+            FrameworkStatsLog.write_non_chained(
+                    FrameworkStatsLog.VIBRATION_REPORTED,
+                    uid, null, vibrationType, usage, status, endedBySameUid, endedByUsage,
+                    interruptedUsage, repeatCount, totalDurationMillis, vibratorOnMillis,
+                    startLatencyMillis, endLatencyMillis, halComposeCount, halComposePwleCount,
+                    halOnCount, halOffCount, halPerformCount, halSetAmplitudeCount,
+                    halSetExternalControlCount, halSupportedCompositionPrimitivesUsed,
+                    halSupportedEffectsUsed, halUnsupportedCompositionPrimitivesUsed,
+                    halUnsupportedEffectsUsed, halCompositionSize, halPwleSize);
+        }
+
+        private static int[] filteredKeys(SparseBooleanArray supportArray, boolean supported) {
+            int count = 0;
+            for (int i = 0; i < supportArray.size(); i++) {
+                if (supportArray.valueAt(i) == supported) count++;
+            }
+            if (count == 0) {
+                return null;
+            }
+            int pos = 0;
+            int[] res = new int[count];
+            for (int i = 0; i < supportArray.size(); i++) {
+                if (supportArray.valueAt(i) == supported) {
+                    res[pos++] = supportArray.keyAt(i);
+                }
+            }
+            return res;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/vibrator/VibrationStepConductor.java b/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
index e3d8067..0799b95 100644
--- a/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
+++ b/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
@@ -81,12 +81,12 @@
     private final IntArray mSignalVibratorsComplete;
     @Nullable
     @GuardedBy("mLock")
-    private Vibration.Status mSignalCancelStatus = null;
+    private Vibration.EndInfo mSignalCancel = null;
     @GuardedBy("mLock")
     private boolean mSignalCancelImmediate = false;
 
     @Nullable
-    private Vibration.Status mCancelStatus = null;
+    private Vibration.EndInfo mCancelledVibrationEndInfo = null;
     private boolean mCancelledImmediately = false;  // hard stop
     private int mPendingVibrateSteps;
     private int mRemainingStartSequentialEffectSteps;
@@ -153,6 +153,9 @@
         // This count is decremented at the completion of the step, so we don't subtract one.
         mRemainingStartSequentialEffectSteps = sequentialEffect.getEffects().size();
         mNextSteps.offer(new StartSequentialEffectStep(this, sequentialEffect));
+        // Vibration will start playing in the Vibrator, following the effect timings and delays.
+        // Report current time as the vibration start time, for debugging.
+        mVibration.stats().reportStarted();
     }
 
     public Vibration getVibration() {
@@ -182,24 +185,25 @@
      * Calculate the {@link Vibration.Status} based on the current queue state and the expected
      * number of {@link StartSequentialEffectStep} to be played.
      */
-    public Vibration.Status calculateVibrationStatus() {
+    @Nullable
+    public Vibration.EndInfo calculateVibrationEndInfo() {
         if (Build.IS_DEBUGGABLE) {
             expectIsVibrationThread(true);
         }
 
-        if (mCancelStatus != null) {
-            return mCancelStatus;
+        if (mCancelledVibrationEndInfo != null) {
+            return mCancelledVibrationEndInfo;
         }
-        if (mPendingVibrateSteps > 0
-                || mRemainingStartSequentialEffectSteps > 0) {
-            return Vibration.Status.RUNNING;
+        if (mPendingVibrateSteps > 0 || mRemainingStartSequentialEffectSteps > 0) {
+            // Vibration still running.
+            return null;
         }
         // No pending steps, and something happened.
         if (mSuccessfulVibratorOnSteps > 0) {
-            return Vibration.Status.FINISHED;
+            return new Vibration.EndInfo(Vibration.Status.FINISHED);
         }
         // If no step was able to turn the vibrator ON successfully.
-        return Vibration.Status.IGNORED_UNSUPPORTED;
+        return new Vibration.EndInfo(Vibration.Status.IGNORED_UNSUPPORTED);
     }
 
     /**
@@ -305,45 +309,50 @@
         if (DEBUG) {
             Slog.d(TAG, "Binder died, cancelling vibration...");
         }
-        notifyCancelled(Vibration.Status.CANCELLED_BINDER_DIED, /* immediate= */ false);
+        notifyCancelled(new Vibration.EndInfo(Vibration.Status.CANCELLED_BINDER_DIED),
+                /* immediate= */ false);
     }
 
     /**
      * Notify the execution that cancellation is requested. This will be acted upon
      * asynchronously in the VibrationThread.
      *
+     * <p>Only the first cancel signal will be used to end a cancelled vibration, but subsequent
+     * calls with {@code immediate} flag set to true can still force the first cancel signal to
+     * take effect urgently.
+     *
      * @param immediate indicates whether cancellation should abort urgently and skip cleanup steps.
      */
-    public void notifyCancelled(@NonNull Vibration.Status cancelStatus, boolean immediate) {
+    public void notifyCancelled(@NonNull Vibration.EndInfo cancelInfo, boolean immediate) {
         if (Build.IS_DEBUGGABLE) {
             expectIsVibrationThread(false);
         }
         if (DEBUG) {
-            Slog.d(TAG, "Vibration cancel requested with status=" + cancelStatus
+            Slog.d(TAG, "Vibration cancel requested with signal=" + cancelInfo
                     + ", immediate=" + immediate);
         }
-        if ((cancelStatus == null) || !cancelStatus.name().startsWith("CANCEL")) {
-            Slog.w(TAG, "Vibration cancel requested with bad status=" + cancelStatus
+        if ((cancelInfo == null) || !cancelInfo.status.name().startsWith("CANCEL")) {
+            Slog.w(TAG, "Vibration cancel requested with bad signal=" + cancelInfo
                     + ", using CANCELLED_UNKNOWN_REASON to ensure cancellation.");
-            cancelStatus = Vibration.Status.CANCELLED_BY_UNKNOWN_REASON;
+            cancelInfo = new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_UNKNOWN_REASON);
         }
         synchronized (mLock) {
-            if (immediate && mSignalCancelImmediate || (mSignalCancelStatus != null)) {
+            if ((immediate && mSignalCancelImmediate) || (mSignalCancel != null)) {
                 if (DEBUG) {
                     Slog.d(TAG, "Vibration cancel request ignored as the vibration "
-                            + mVibration.id + "is already being cancelled with status="
-                            + mSignalCancelStatus + ", immediate=" + mSignalCancelImmediate);
+                            + mVibration.id + "is already being cancelled with signal="
+                            + mSignalCancel + ", immediate=" + mSignalCancelImmediate);
                 }
                 return;
             }
             mSignalCancelImmediate |= immediate;
-            if (mSignalCancelStatus == null) {
-                mSignalCancelStatus = cancelStatus;
+            if (mSignalCancel == null) {
+                mSignalCancel = cancelInfo;
             } else {
                 if (DEBUG) {
-                    Slog.d(TAG, "Vibration cancel request new status=" + cancelStatus
-                            + " ignored as the vibration was already cancelled with status="
-                            + mSignalCancelStatus + ", but immediate flag was updated to "
+                    Slog.d(TAG, "Vibration cancel request new signal=" + cancelInfo
+                            + " ignored as the vibration was already cancelled with signal="
+                            + mSignalCancel + ", but immediate flag was updated to "
                             + mSignalCancelImmediate);
                 }
             }
@@ -401,9 +410,9 @@
         if (Build.IS_DEBUGGABLE) {
             expectIsVibrationThread(true);  // Reads VibrationThread variables as well as signals.
         }
-        return (mSignalCancelStatus != mCancelStatus)
-            || (mSignalCancelImmediate && !mCancelledImmediately)
-            || (mSignalVibratorsComplete.size() > 0);
+        return (mSignalCancel != null && mCancelledVibrationEndInfo == null)
+                || (mSignalCancelImmediate && !mCancelledImmediately)
+                || (mSignalVibratorsComplete.size() > 0);
     }
 
     /**
@@ -416,7 +425,7 @@
         }
 
         int[] vibratorsToProcess = null;
-        Vibration.Status doCancelStatus = null;
+        Vibration.EndInfo doCancelInfo = null;
         boolean doCancelImmediate = false;
         // Collect signals to process, but don't keep the lock while processing them.
         synchronized (mLock) {
@@ -426,10 +435,10 @@
                 }
                 // This should only happen once.
                 doCancelImmediate = true;
-                doCancelStatus = mSignalCancelStatus;
+                doCancelInfo = mSignalCancel;
             }
-            if (mSignalCancelStatus != mCancelStatus) {
-                doCancelStatus = mSignalCancelStatus;
+            if ((mSignalCancel != null) && (mCancelledVibrationEndInfo == null)) {
+                doCancelInfo = mSignalCancel;
             }
             if (!doCancelImmediate && mSignalVibratorsComplete.size() > 0) {
                 // Swap out the queue of completions to process.
@@ -443,11 +452,11 @@
         // completion signals that were collected in this call, but we won't process them
         // anyway as all steps are cancelled.
         if (doCancelImmediate) {
-            processCancelImmediately(doCancelStatus);
+            processCancelImmediately(doCancelInfo);
             return;
         }
-        if (doCancelStatus != null) {
-            processCancel(doCancelStatus);
+        if (doCancelInfo != null) {
+            processCancel(doCancelInfo);
         }
         if (vibratorsToProcess != null) {
             processVibratorsComplete(vibratorsToProcess);
@@ -460,12 +469,12 @@
      * <p>This will remove all steps and replace them with respective results of
      * {@link Step#cancel()}.
      */
-    public void processCancel(Vibration.Status cancelStatus) {
+    public void processCancel(Vibration.EndInfo cancelInfo) {
         if (Build.IS_DEBUGGABLE) {
             expectIsVibrationThread(true);
         }
 
-        mCancelStatus = cancelStatus;
+        mCancelledVibrationEndInfo = cancelInfo;
         // Vibrator callbacks should wait until all steps from the queue are properly cancelled
         // and clean up steps are added back to the queue, so they can handle the callback.
         List<Step> cleanUpSteps = new ArrayList<>();
@@ -483,13 +492,13 @@
      *
      * <p>This will remove and trigger {@link Step#cancelImmediately()} in all steps, in order.
      */
-    public void processCancelImmediately(Vibration.Status cancelStatus) {
+    public void processCancelImmediately(Vibration.EndInfo cancelInfo) {
         if (Build.IS_DEBUGGABLE) {
             expectIsVibrationThread(true);
         }
 
         mCancelledImmediately = true;
-        mCancelStatus = cancelStatus;
+        mCancelledVibrationEndInfo = cancelInfo;
         Step step;
         while ((step = pollNext()) != null) {
             step.cancelImmediately();
diff --git a/services/core/java/com/android/server/vibrator/VibrationThread.java b/services/core/java/com/android/server/vibrator/VibrationThread.java
index cecc5c0..e824db10 100644
--- a/services/core/java/com/android/server/vibrator/VibrationThread.java
+++ b/services/core/java/com/android/server/vibrator/VibrationThread.java
@@ -76,7 +76,7 @@
          * cleanup tasks, and should not be given new work until {@link #onVibrationThreadReleased}
          * is called.
          */
-        void onVibrationCompleted(long vibrationId, Vibration.Status status);
+        void onVibrationCompleted(long vibrationId, @NonNull Vibration.EndInfo vibrationEndInfo);
 
         /**
          * Tells the manager that the VibrationThread is finished with the previous vibration and
@@ -237,7 +237,8 @@
             try {
                 runCurrentVibrationWithWakeLockAndDeathLink();
             } finally {
-                clientVibrationCompleteIfNotAlready(Vibration.Status.FINISHED_UNEXPECTED);
+                clientVibrationCompleteIfNotAlready(
+                        new Vibration.EndInfo(Vibration.Status.FINISHED_UNEXPECTED));
             }
         } finally {
             mWakeLock.release();
@@ -255,7 +256,8 @@
             vibrationBinderToken.linkToDeath(mExecutingConductor, 0);
         } catch (RemoteException e) {
             Slog.e(TAG, "Error linking vibration to token death", e);
-            clientVibrationCompleteIfNotAlready(Vibration.Status.IGNORED_ERROR_TOKEN);
+            clientVibrationCompleteIfNotAlready(
+                    new Vibration.EndInfo(Vibration.Status.IGNORED_ERROR_TOKEN));
             return;
         }
         // Ensure that the unlink always occurs now.
@@ -274,11 +276,11 @@
     // Indicate that the vibration is complete. This can be called multiple times only for
     // convenience of handling error conditions - an error after the client is complete won't
     // affect the status.
-    private void clientVibrationCompleteIfNotAlready(Vibration.Status completedStatus) {
+    private void clientVibrationCompleteIfNotAlready(@NonNull Vibration.EndInfo vibrationEndInfo) {
         if (!mCalledVibrationCompleteCallback) {
             mCalledVibrationCompleteCallback = true;
             mVibratorManagerHooks.onVibrationCompleted(
-                    mExecutingConductor.getVibration().id, completedStatus);
+                    mExecutingConductor.getVibration().id, vibrationEndInfo);
         }
     }
 
@@ -298,12 +300,15 @@
                     mExecutingConductor.runNextStep();
                 }
 
-                Vibration.Status status = mExecutingConductor.calculateVibrationStatus();
-                // This block can only run once due to mCalledVibrationCompleteCallback.
-                if (status != Vibration.Status.RUNNING && !mCalledVibrationCompleteCallback) {
-                    // First time vibration stopped running, start clean-up tasks and notify
-                    // callback immediately.
-                    clientVibrationCompleteIfNotAlready(status);
+                if (!mCalledVibrationCompleteCallback) {
+                    // This block can only run once due to mCalledVibrationCompleteCallback.
+                    Vibration.EndInfo vibrationEndInfo =
+                            mExecutingConductor.calculateVibrationEndInfo();
+                    if (vibrationEndInfo != null) {
+                        // First time vibration stopped running, start clean-up tasks and notify
+                        // callback immediately.
+                        clientVibrationCompleteIfNotAlready(vibrationEndInfo);
+                    }
                 }
             }
         } finally {
diff --git a/services/core/java/com/android/server/vibrator/VibratorFrameworkStatsLogger.java b/services/core/java/com/android/server/vibrator/VibratorFrameworkStatsLogger.java
new file mode 100644
index 0000000..f600a29
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/VibratorFrameworkStatsLogger.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vibrator;
+
+import android.os.Handler;
+import android.os.SystemClock;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FrameworkStatsLog;
+
+import java.util.ArrayDeque;
+import java.util.Queue;
+
+/** Helper class for async write of atoms to {@link FrameworkStatsLog} using a given Handler. */
+public class VibratorFrameworkStatsLogger {
+    private static final String TAG = "VibratorFrameworkStatsLogger";
+
+    // VibrationReported pushed atom needs to be throttled to at most one every 10ms.
+    private static final int VIBRATION_REPORTED_MIN_INTERVAL_MILLIS = 10;
+    // We accumulate events that should take 3s to write and drop excessive metrics.
+    private static final int VIBRATION_REPORTED_MAX_QUEUE_SIZE = 300;
+    // Warning about dropping entries after this amount of atoms were dropped by the throttle.
+    private static final int VIBRATION_REPORTED_WARNING_QUEUE_SIZE = 200;
+
+    private final Object mLock = new Object();
+    private final Handler mHandler;
+    private final long mVibrationReportedLogIntervalMillis;
+    private final long mVibrationReportedQueueMaxSize;
+    private final Runnable mConsumeVibrationStatsQueueRunnable =
+            () -> writeVibrationReportedFromQueue();
+
+    @GuardedBy("mLock")
+    private long mLastVibrationReportedLogUptime;
+    @GuardedBy("mLock")
+    private Queue<VibrationStats.StatsInfo> mVibrationStatsQueue = new ArrayDeque<>();
+
+    VibratorFrameworkStatsLogger(Handler handler) {
+        this(handler, VIBRATION_REPORTED_MIN_INTERVAL_MILLIS, VIBRATION_REPORTED_MAX_QUEUE_SIZE);
+    }
+
+    @VisibleForTesting
+    VibratorFrameworkStatsLogger(Handler handler, int vibrationReportedLogIntervalMillis,
+            int vibrationReportedQueueMaxSize) {
+        mHandler = handler;
+        mVibrationReportedLogIntervalMillis = vibrationReportedLogIntervalMillis;
+        mVibrationReportedQueueMaxSize = vibrationReportedQueueMaxSize;
+    }
+
+    /** Writes {@link FrameworkStatsLog#VIBRATOR_STATE_CHANGED} for state ON. */
+    public void writeVibratorStateOnAsync(int uid, long duration) {
+        mHandler.post(
+                () -> FrameworkStatsLog.write_non_chained(
+                        FrameworkStatsLog.VIBRATOR_STATE_CHANGED, uid, null,
+                        FrameworkStatsLog.VIBRATOR_STATE_CHANGED__STATE__ON, duration));
+    }
+
+    /** Writes {@link FrameworkStatsLog#VIBRATOR_STATE_CHANGED} for state OFF. */
+    public void writeVibratorStateOffAsync(int uid) {
+        mHandler.post(
+                () -> FrameworkStatsLog.write_non_chained(
+                        FrameworkStatsLog.VIBRATOR_STATE_CHANGED, uid, null,
+                        FrameworkStatsLog.VIBRATOR_STATE_CHANGED__STATE__OFF,
+                        /* duration= */ 0));
+    }
+
+    /**
+     *  Writes {@link FrameworkStatsLog#VIBRATION_REPORTED} for given vibration.
+     *
+     *  <p>This atom is throttled to be pushed once every 10ms, so this logger can keep a queue of
+     *  {@link VibrationStats.StatsInfo} entries to slowly write to statsd.
+     */
+    public void writeVibrationReportedAsync(VibrationStats.StatsInfo metrics) {
+        boolean needsScheduling;
+        long scheduleDelayMs;
+        int queueSize;
+
+        synchronized (mLock) {
+            queueSize = mVibrationStatsQueue.size();
+            needsScheduling = (queueSize == 0);
+
+            if (queueSize < mVibrationReportedQueueMaxSize) {
+                mVibrationStatsQueue.offer(metrics);
+            }
+
+            long nextLogUptime =
+                    mLastVibrationReportedLogUptime + mVibrationReportedLogIntervalMillis;
+            scheduleDelayMs = Math.max(0, nextLogUptime - SystemClock.uptimeMillis());
+        }
+
+        if ((queueSize + 1) == VIBRATION_REPORTED_WARNING_QUEUE_SIZE) {
+            Slog.w(TAG, " Approaching vibration metrics queue limit, events might be dropped.");
+        }
+
+        if (needsScheduling) {
+            mHandler.postDelayed(mConsumeVibrationStatsQueueRunnable, scheduleDelayMs);
+        }
+    }
+
+    /** Writes next {@link FrameworkStatsLog#VIBRATION_REPORTED} from the queue. */
+    private void writeVibrationReportedFromQueue() {
+        boolean needsScheduling;
+        VibrationStats.StatsInfo stats;
+
+        synchronized (mLock) {
+            stats = mVibrationStatsQueue.poll();
+            needsScheduling = !mVibrationStatsQueue.isEmpty();
+
+            if (stats != null) {
+                mLastVibrationReportedLogUptime = SystemClock.uptimeMillis();
+            }
+        }
+
+        if (stats == null) {
+            Slog.w(TAG, "Unexpected vibration metric flush with empty queue. Ignoring.");
+        } else {
+            stats.writeVibrationReported();
+        }
+
+        if (needsScheduling) {
+            mHandler.postDelayed(mConsumeVibrationStatsQueueRunnable,
+                    mVibrationReportedLogIntervalMillis);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index 5ac2f4f..2f12a82 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -129,6 +129,7 @@
     private final Context mContext;
     private final PowerManager.WakeLock mWakeLock;
     private final IBatteryStats mBatteryStatsService;
+    private final VibratorFrameworkStatsLogger mFrameworkStatsLogger;
     private final Handler mHandler;
     private final VibrationThread mVibrationThread;
     private final AppOpsManager mAppOps;
@@ -163,10 +164,12 @@
                     // When the system is entering a non-interactive state, we want to cancel
                     // vibrations in case a misbehaving app has abandoned them.
                     if (shouldCancelOnScreenOffLocked(mNextVibration)) {
-                        clearNextVibrationLocked(Vibration.Status.CANCELLED_BY_SCREEN_OFF);
+                        clearNextVibrationLocked(
+                                new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_SCREEN_OFF));
                     }
                     if (shouldCancelOnScreenOffLocked(mCurrentVibration)) {
-                        mCurrentVibration.notifyCancelled(Vibration.Status.CANCELLED_BY_SCREEN_OFF,
+                        mCurrentVibration.notifyCancelled(
+                                new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_SCREEN_OFF),
                                 /* immediate= */ false);
                     }
                 }
@@ -207,6 +210,7 @@
         mVibratorManagerRecords = new VibratorManagerRecords(dumpLimit);
 
         mBatteryStatsService = injector.getBatteryStatsService();
+        mFrameworkStatsLogger = injector.getFrameworkStatsLogger(mHandler);
 
         mAppOps = mContext.getSystemService(AppOpsManager.class);
 
@@ -384,7 +388,8 @@
      * The Vibration is only returned if it is ongoing after this method returns.
      */
     @Nullable
-    private Vibration vibrateInternal(int uid, String opPkg, @NonNull CombinedVibration effect,
+    @VisibleForTesting
+    Vibration vibrateInternal(int uid, String opPkg, @NonNull CombinedVibration effect,
             @Nullable VibrationAttributes attrs, String reason, IBinder token) {
         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "vibrate, reason = " + reason);
         try {
@@ -399,6 +404,7 @@
                 return null;
             }
             attrs = fixupVibrationAttributes(attrs, effect);
+            // Create Vibration.Stats as close to the received request as possible, for tracking.
             Vibration vib = new Vibration(token, mNextVibrationId.getAndIncrement(), effect, attrs,
                     uid, opPkg, reason);
             fillVibrationFallbacks(vib, effect);
@@ -413,32 +419,56 @@
                 if (DEBUG) {
                     Slog.d(TAG, "Starting vibrate for vibration  " + vib.id);
                 }
-                Vibration.Status ignoreStatus = shouldIgnoreVibrationLocked(
-                        vib.uid, vib.opPkg, vib.attrs);
+                int ignoredByUid = -1;
+                int ignoredByUsage = -1;
+                Vibration.Status status = null;
 
-                if (ignoreStatus == null) {
-                    ignoreStatus = shouldIgnoreVibrationForOngoingLocked(vib);
+                // Check if user settings or DnD is set to ignore this vibration.
+                status = shouldIgnoreVibrationLocked(vib.uid, vib.opPkg, vib.attrs);
+
+                // Check if something has external control, assume it's more important.
+                if ((status == null) && (mCurrentExternalVibration != null)) {
+                    status = Vibration.Status.IGNORED_FOR_EXTERNAL;
+                    ignoredByUid = mCurrentExternalVibration.externalVibration.getUid();
+                    ignoredByUsage = mCurrentExternalVibration.externalVibration
+                            .getVibrationAttributes().getUsage();
                 }
 
-                if (ignoreStatus != null) {
-                    endVibrationLocked(vib, ignoreStatus);
-                    return vib;
-                }
-
-                final long ident = Binder.clearCallingIdentity();
-                try {
-                    if (mCurrentVibration != null) {
-                        mCurrentVibration.notifyCancelled(Vibration.Status.CANCELLED_SUPERSEDED,
-                                /* immediate= */ false);
+                // Check if ongoing vibration is more important than this vibration.
+                if (status == null) {
+                    status = shouldIgnoreVibrationForOngoingLocked(vib);
+                    if (status != null) {
+                        ignoredByUid = mCurrentVibration.getVibration().uid;
+                        ignoredByUsage = mCurrentVibration.getVibration().attrs.getUsage();
                     }
-                    Vibration.Status status = startVibrationLocked(vib);
-                    if (status != Vibration.Status.RUNNING) {
-                        endVibrationLocked(vib, status);
-                    }
-                    return vib;
-                } finally {
-                    Binder.restoreCallingIdentity(ident);
                 }
+
+                // If not ignored so far then try to start this vibration.
+                if (status == null) {
+                    final long ident = Binder.clearCallingIdentity();
+                    try {
+                        if (mCurrentVibration != null) {
+                            vib.stats().reportInterruptedAnotherVibration(
+                                    mCurrentVibration.getVibration().attrs.getUsage());
+                            mCurrentVibration.notifyCancelled(
+                                    new Vibration.EndInfo(
+                                            Vibration.Status.CANCELLED_SUPERSEDED, vib.uid,
+                                            vib.attrs.getUsage()),
+                                    /* immediate= */ false);
+                        }
+                        status = startVibrationLocked(vib);
+                    } finally {
+                        Binder.restoreCallingIdentity(ident);
+                    }
+                }
+
+                // Ignored or failed to start the vibration, end it and report metrics right away.
+                if (status != Vibration.Status.RUNNING) {
+                    endVibrationLocked(vib,
+                            new Vibration.EndInfo(status, ignoredByUid, ignoredByUsage),
+                            /* shouldWriteStats= */ true);
+                }
+                return vib;
             }
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
@@ -457,26 +487,28 @@
                 if (DEBUG) {
                     Slog.d(TAG, "Canceling vibration");
                 }
+                Vibration.EndInfo cancelledByUserInfo =
+                        new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_USER);
                 final long ident = Binder.clearCallingIdentity();
                 try {
                     if (mNextVibration != null
                             && shouldCancelVibration(mNextVibration.getVibration(),
                             usageFilter, token)) {
-                        clearNextVibrationLocked(Vibration.Status.CANCELLED_BY_USER);
+                        clearNextVibrationLocked(cancelledByUserInfo);
                     }
                     if (mCurrentVibration != null
                             && shouldCancelVibration(mCurrentVibration.getVibration(),
                             usageFilter, token)) {
-                        mCurrentVibration.notifyCancelled(Vibration.Status.CANCELLED_BY_USER,
-                                /* immediate= */false);
+                        mCurrentVibration.notifyCancelled(
+                                cancelledByUserInfo, /* immediate= */false);
                     }
                     if (mCurrentExternalVibration != null
                             && shouldCancelVibration(
                             mCurrentExternalVibration.externalVibration.getVibrationAttributes(),
                             usageFilter)) {
-                        mCurrentExternalVibration.externalVibration.mute();
-                        endExternalVibrateLocked(Vibration.Status.CANCELLED_BY_USER,
-                                /* continueExternalControl= */ false);
+                        mCurrentExternalVibration.mute();
+                        endExternalVibrateLocked(
+                                cancelledByUserInfo, /* continueExternalControl= */ false);
                     }
                 } finally {
                     Binder.restoreCallingIdentity(ident);
@@ -604,15 +636,17 @@
                     Slog.d(TAG, "Canceling vibration because settings changed: "
                             + (inputDevicesChanged ? "input devices changed" : ignoreStatus));
                 }
-                mCurrentVibration.notifyCancelled(Vibration.Status.CANCELLED_BY_SETTINGS_UPDATE,
+                mCurrentVibration.notifyCancelled(
+                        new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_SETTINGS_UPDATE),
                         /* immediate= */ false);
             }
         }
     }
 
-    private void setExternalControl(boolean externalControl) {
+    private void setExternalControl(boolean externalControl, VibrationStats vibrationStats) {
         for (int i = 0; i < mVibrators.size(); i++) {
             mVibrators.valueAt(i).setExternalControl(externalControl);
+            vibrationStats.reportSetExternalControl();
         }
     }
 
@@ -654,7 +688,9 @@
             }
             // If there's already a vibration queued (waiting for the previous one to finish
             // cancelling), end it cleanly and replace it with the new one.
-            clearNextVibrationLocked(Vibration.Status.IGNORED_SUPERSEDED);
+            clearNextVibrationLocked(
+                    new Vibration.EndInfo(Vibration.Status.IGNORED_SUPERSEDED,
+                            vib.uid, vib.attrs.getUsage()));
             mNextVibration = conductor;
             return Vibration.Status.RUNNING;
         } finally {
@@ -671,6 +707,7 @@
             switch (mode) {
                 case AppOpsManager.MODE_ALLOWED:
                     Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
+                    // Make sure mCurrentVibration is set while triggering the VibrationThread.
                     mCurrentVibration = conductor;
                     if (!mVibrationThread.runVibrationOnVibrationThread(mCurrentVibration)) {
                         // Shouldn't happen. The method call already logs a wtf.
@@ -690,18 +727,26 @@
     }
 
     @GuardedBy("mLock")
-    private void endVibrationLocked(Vibration vib, Vibration.Status status) {
-        vib.end(status);
-        logVibrationStatus(vib.uid, vib.attrs, status);
+    private void endVibrationLocked(Vibration vib, Vibration.EndInfo vibrationEndInfo,
+            boolean shouldWriteStats) {
+        vib.end(vibrationEndInfo);
+        logVibrationStatus(vib.uid, vib.attrs, vibrationEndInfo.status);
         mVibratorManagerRecords.record(vib);
+        if (shouldWriteStats) {
+            mFrameworkStatsLogger.writeVibrationReportedAsync(
+                    vib.getStatsInfo(/* completionUptimeMillis= */ SystemClock.uptimeMillis()));
+        }
     }
 
     @GuardedBy("mLock")
-    private void endVibrationLocked(ExternalVibrationHolder vib, Vibration.Status status) {
-        vib.end(status);
+    private void endVibrationAndWriteStatsLocked(ExternalVibrationHolder vib,
+            Vibration.EndInfo vibrationEndInfo) {
+        vib.end(vibrationEndInfo);
         logVibrationStatus(vib.externalVibration.getUid(),
-                vib.externalVibration.getVibrationAttributes(), status);
+                vib.externalVibration.getVibrationAttributes(), vibrationEndInfo.status);
         mVibratorManagerRecords.record(vib);
+        mFrameworkStatsLogger.writeVibrationReportedAsync(
+                vib.getStatsInfo(/* completionUptimeMillis= */ SystemClock.uptimeMillis()));
     }
 
     private void logVibrationStatus(int uid, VibrationAttributes attrs, Vibration.Status status) {
@@ -744,15 +789,17 @@
     }
 
     @GuardedBy("mLock")
-    private void reportFinishedVibrationLocked(Vibration.Status status) {
+    private void reportFinishedVibrationLocked(Vibration.EndInfo vibrationEndInfo) {
         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "reportFinishVibrationLocked");
         Trace.asyncTraceEnd(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
         try {
             Vibration vib = mCurrentVibration.getVibration();
             if (DEBUG) {
-                Slog.d(TAG, "Reporting vibration " + vib.id + " finished with status " + status);
+                Slog.d(TAG, "Reporting vibration " + vib.id + " finished with " + vibrationEndInfo);
             }
-            endVibrationLocked(vib, status);
+            // DO NOT write metrics at this point, wait for the VibrationThread to report the
+            // vibration was released, after all cleanup. The metrics will be reported then.
+            endVibrationLocked(vib, vibrationEndInfo, /* shouldWriteStats= */ false);
             finishAppOpModeLocked(vib.uid, vib.opPkg);
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
@@ -791,11 +838,6 @@
     @GuardedBy("mLock")
     @Nullable
     private Vibration.Status shouldIgnoreVibrationForOngoingLocked(Vibration vib) {
-        if (mCurrentExternalVibration != null) {
-            // If something has external control of the vibrator, assume that it's more important.
-            return Vibration.Status.IGNORED_FOR_EXTERNAL;
-        }
-
         if (mCurrentVibration == null || vib.isRepeating()) {
             // Incoming repeating vibrations always take precedence over ongoing vibrations.
             return null;
@@ -1122,7 +1164,7 @@
         }
         Vibration vib = conductor.getVibration();
         return mVibrationSettings.shouldCancelVibrationOnScreenOff(
-                vib.uid, vib.opPkg, vib.attrs.getUsage(), vib.startUptimeMillis);
+                vib.uid, vib.opPkg, vib.attrs.getUsage(), vib.stats().getCreateUptimeMillis());
     }
 
     @GuardedBy("mLock")
@@ -1158,6 +1200,10 @@
                     BatteryStats.SERVICE_NAME));
         }
 
+        VibratorFrameworkStatsLogger getFrameworkStatsLogger(Handler handler) {
+            return new VibratorFrameworkStatsLogger(handler);
+        }
+
         VibratorController createVibratorController(int vibratorId,
                 VibratorController.OnVibrationCompleteListener listener) {
             return new VibratorController(vibratorId, listener);
@@ -1197,6 +1243,10 @@
         public void noteVibratorOn(int uid, long duration) {
             try {
                 if (duration <= 0) {
+                    // Tried to turn vibrator ON and got:
+                    // duration == 0: Unsupported effect/method or zero-amplitude segment.
+                    // duration < 0: Unexpected error triggering the vibrator.
+                    // Skip battery stats and atom metric for VibratorStageChanged to ON.
                     return;
                 }
                 if (duration == Long.MAX_VALUE) {
@@ -1205,10 +1255,9 @@
                     duration = BATTERY_STATS_REPEATING_VIBRATION_DURATION;
                 }
                 mBatteryStatsService.noteVibratorOn(uid, duration);
-                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.VIBRATOR_STATE_CHANGED,
-                        uid, null, FrameworkStatsLog.VIBRATOR_STATE_CHANGED__STATE__ON,
-                        duration);
+                mFrameworkStatsLogger.writeVibratorStateOnAsync(uid, duration);
             } catch (RemoteException e) {
+                Slog.e(TAG, "Error logging VibratorStateChanged to ON", e);
             }
         }
 
@@ -1216,22 +1265,21 @@
         public void noteVibratorOff(int uid) {
             try {
                 mBatteryStatsService.noteVibratorOff(uid);
-                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.VIBRATOR_STATE_CHANGED,
-                        uid, null, FrameworkStatsLog.VIBRATOR_STATE_CHANGED__STATE__OFF,
-                        /* duration= */ 0);
+                mFrameworkStatsLogger.writeVibratorStateOffAsync(uid);
             } catch (RemoteException e) {
+                Slog.e(TAG, "Error logging VibratorStateChanged to OFF", e);
             }
         }
 
         @Override
-        public void onVibrationCompleted(long vibrationId, Vibration.Status status) {
+        public void onVibrationCompleted(long vibrationId, Vibration.EndInfo vibrationEndInfo) {
             if (DEBUG) {
-                Slog.d(TAG, "Vibration " + vibrationId + " finished with status " + status);
+                Slog.d(TAG, "Vibration " + vibrationId + " finished with " + vibrationEndInfo);
             }
             synchronized (mLock) {
                 if (mCurrentVibration != null
                         && mCurrentVibration.getVibration().id == vibrationId) {
-                    reportFinishedVibrationLocked(status);
+                    reportFinishedVibrationLocked(vibrationEndInfo);
                 }
             }
         }
@@ -1251,13 +1299,21 @@
                             "VibrationId mismatch on release. expected=%d, released=%d",
                             mCurrentVibration.getVibration().id, vibrationId));
                 }
-                mCurrentVibration = null;
+                if (mCurrentVibration != null) {
+                    // This is when we consider the current vibration complete, so report metrics.
+                    mFrameworkStatsLogger.writeVibrationReportedAsync(
+                            mCurrentVibration.getVibration().getStatsInfo(
+                                    /* completionUptimeMillis= */ SystemClock.uptimeMillis()));
+                    mCurrentVibration = null;
+                }
                 if (mNextVibration != null) {
                     VibrationStepConductor nextConductor = mNextVibration;
                     mNextVibration = null;
                     Vibration.Status status = startVibrationOnThreadLocked(nextConductor);
                     if (status != Vibration.Status.RUNNING) {
-                        endVibrationLocked(nextConductor.getVibration(), status);
+                        // Failed to start the vibration, end it and report metrics right away.
+                        endVibrationLocked(nextConductor.getVibration(),
+                                new Vibration.EndInfo(status), /* shouldWriteStats= */ true);
                     }
                 }
             }
@@ -1325,31 +1381,48 @@
     private final class ExternalVibrationHolder implements IBinder.DeathRecipient {
 
         public final ExternalVibration externalVibration;
+        public final VibrationStats stats = new VibrationStats();
         public int scale;
 
-        private final long mStartUptimeMillis;
-        private final long mStartTimeDebug;
-
-        private long mEndUptimeMillis;
-        private long mEndTimeDebug;
         private Vibration.Status mStatus;
 
         private ExternalVibrationHolder(ExternalVibration externalVibration) {
             this.externalVibration = externalVibration;
             this.scale = IExternalVibratorService.SCALE_NONE;
-            mStartUptimeMillis = SystemClock.uptimeMillis();
-            mStartTimeDebug = System.currentTimeMillis();
             mStatus = Vibration.Status.RUNNING;
         }
 
-        public void end(Vibration.Status status) {
+        public void mute() {
+            externalVibration.mute();
+        }
+
+        public void linkToDeath() {
+            externalVibration.linkToDeath(this);
+        }
+
+        public void unlinkToDeath() {
+            externalVibration.unlinkToDeath(this);
+        }
+
+        public boolean isHoldingSameVibration(ExternalVibration externalVibration) {
+            return this.externalVibration.equals(externalVibration);
+        }
+
+        public void end(Vibration.EndInfo info) {
             if (mStatus != Vibration.Status.RUNNING) {
-                // Vibration already ended, keep first ending status set and ignore this one.
+                // Already ended, ignore this call
                 return;
             }
-            mStatus = status;
-            mEndUptimeMillis = SystemClock.uptimeMillis();
-            mEndTimeDebug = System.currentTimeMillis();
+            mStatus = info.status;
+            stats.reportEnded(info.endedByUid, info.endedByUsage);
+
+            if (stats.hasStarted()) {
+                // External vibration doesn't have feedback from total time the vibrator was playing
+                // with non-zero amplitude, so we use the duration between start and end times of
+                // the vibration as the time the vibrator was ON, since the haptic channels are
+                // open for this duration and can receive vibration waveform data.
+                stats.reportVibratorOn(stats.getEndUptimeMillis() - stats.getStartUptimeMillis());
+            }
         }
 
         public void binderDied() {
@@ -1358,19 +1431,26 @@
                     if (DEBUG) {
                         Slog.d(TAG, "External vibration finished because binder died");
                     }
-                    endExternalVibrateLocked(Vibration.Status.CANCELLED_BINDER_DIED,
+                    endExternalVibrateLocked(
+                            new Vibration.EndInfo(Vibration.Status.CANCELLED_BINDER_DIED),
                             /* continueExternalControl= */ false);
                 }
             }
         }
 
         public Vibration.DebugInfo getDebugInfo() {
-            long durationMs = mEndUptimeMillis == 0 ? -1 : mEndUptimeMillis - mStartUptimeMillis;
             return new Vibration.DebugInfo(
-                    mStartTimeDebug, mEndTimeDebug, durationMs,
-                    /* effect= */ null, /* originalEffect= */ null, scale,
+                    mStatus, stats, /* effect= */ null, /* originalEffect= */ null, scale,
                     externalVibration.getVibrationAttributes(), externalVibration.getUid(),
-                    externalVibration.getPackage(), /* reason= */ null, mStatus);
+                    externalVibration.getPackage(), /* reason= */ null);
+        }
+
+        public VibrationStats.StatsInfo getStatsInfo(long completionUptimeMillis) {
+            return new VibrationStats.StatsInfo(
+                    externalVibration.getUid(),
+                    FrameworkStatsLog.VIBRATION_REPORTED__VIBRATION_TYPE__EXTERNAL,
+                    externalVibration.getVibrationAttributes().getUsage(), mStatus, stats,
+                    completionUptimeMillis);
         }
     }
 
@@ -1500,9 +1580,11 @@
 
     /** Clears mNextVibration if set, ending it cleanly */
     @GuardedBy("mLock")
-    private void clearNextVibrationLocked(Vibration.Status endStatus) {
+    private void clearNextVibrationLocked(Vibration.EndInfo vibrationEndInfo) {
         if (mNextVibration != null) {
-            endVibrationLocked(mNextVibration.getVibration(), endStatus);
+            // Clearing next vibration before playing it, end it and report metrics right away.
+            endVibrationLocked(mNextVibration.getVibration(), vibrationEndInfo,
+                    /* shouldWriteStats= */ true);
             mNextVibration = null;
         }
     }
@@ -1510,25 +1592,25 @@
     /**
      * Ends the external vibration, and clears related service state.
      *
-     * @param status the status to end the associated Vibration with
+     * @param vibrationEndInfo the status and related info to end the associated Vibration with
      * @param continueExternalControl indicates whether external control will continue. If not, the
      *                                HAL will have external control turned off.
      */
     @GuardedBy("mLock")
-    private void endExternalVibrateLocked(Vibration.Status status,
+    private void endExternalVibrateLocked(Vibration.EndInfo vibrationEndInfo,
             boolean continueExternalControl) {
         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "endExternalVibrateLocked");
         try {
             if (mCurrentExternalVibration == null) {
                 return;
             }
-            endVibrationLocked(mCurrentExternalVibration, status);
-            mCurrentExternalVibration.externalVibration.unlinkToDeath(
-                    mCurrentExternalVibration);
-            mCurrentExternalVibration = null;
+            mCurrentExternalVibration.unlinkToDeath();
             if (!continueExternalControl) {
-                setExternalControl(false);
+                setExternalControl(false, mCurrentExternalVibration.stats);
             }
+            // The external control was turned off, end it and report metrics right away.
+            endVibrationAndWriteStatsLocked(mCurrentExternalVibration, vibrationEndInfo);
+            mCurrentExternalVibration = null;
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
         }
@@ -1552,6 +1634,8 @@
                 return IExternalVibratorService.SCALE_MUTE;
             }
 
+            // Create Vibration.Stats as close to the received request as possible, for tracking.
+            ExternalVibrationHolder vibHolder = new ExternalVibrationHolder(vib);
             VibrationAttributes attrs = fixupVibrationAttributes(vib.getVibrationAttributes(),
                     /* effect= */ null);
             if (attrs.isFlagSet(VibrationAttributes.FLAG_INVALIDATE_SETTINGS_CACHE)) {
@@ -1562,18 +1646,17 @@
 
             boolean alreadyUnderExternalControl = false;
             boolean waitForCompletion = false;
-            int scale;
             synchronized (mLock) {
                 Vibration.Status ignoreStatus = shouldIgnoreVibrationLocked(
                         vib.getUid(), vib.getPackage(), attrs);
                 if (ignoreStatus != null) {
-                    ExternalVibrationHolder vibHolder = new ExternalVibrationHolder(vib);
                     vibHolder.scale = IExternalVibratorService.SCALE_MUTE;
-                    endVibrationLocked(vibHolder, ignoreStatus);
+                    // Failed to start the vibration, end it and report metrics right away.
+                    endVibrationAndWriteStatsLocked(vibHolder, new Vibration.EndInfo(ignoreStatus));
                     return vibHolder.scale;
                 }
                 if (mCurrentExternalVibration != null
-                        && mCurrentExternalVibration.externalVibration.equals(vib)) {
+                        && mCurrentExternalVibration.isHoldingSameVibration(vib)) {
                     // We are already playing this external vibration, so we can return the same
                     // scale calculated in the previous call to this method.
                     return mCurrentExternalVibration.scale;
@@ -1582,8 +1665,14 @@
                     // If we're not under external control right now, then cancel any normal
                     // vibration that may be playing and ready the vibrator for external control.
                     if (mCurrentVibration != null) {
-                        clearNextVibrationLocked(Vibration.Status.IGNORED_FOR_EXTERNAL);
-                        mCurrentVibration.notifyCancelled(Vibration.Status.CANCELLED_SUPERSEDED,
+                        vibHolder.stats.reportInterruptedAnotherVibration(
+                                mCurrentVibration.getVibration().attrs.getUsage());
+                        clearNextVibrationLocked(
+                                new Vibration.EndInfo(Vibration.Status.IGNORED_FOR_EXTERNAL,
+                                        vib.getUid(), attrs.getUsage()));
+                        mCurrentVibration.notifyCancelled(
+                                new Vibration.EndInfo(Vibration.Status.CANCELLED_SUPERSEDED,
+                                        vib.getUid(), attrs.getUsage()),
                                 /* immediate= */ true);
                         waitForCompletion = true;
                     }
@@ -1597,22 +1686,27 @@
                     // Note that this doesn't support multiple concurrent external controls, as we
                     // would need to mute the old one still if it came from a different controller.
                     alreadyUnderExternalControl = true;
-                    mCurrentExternalVibration.externalVibration.mute();
-                    endExternalVibrateLocked(Vibration.Status.CANCELLED_SUPERSEDED,
+                    mCurrentExternalVibration.mute();
+                    vibHolder.stats.reportInterruptedAnotherVibration(
+                            mCurrentExternalVibration.externalVibration
+                                    .getVibrationAttributes().getUsage());
+                    endExternalVibrateLocked(
+                            new Vibration.EndInfo(Vibration.Status.CANCELLED_SUPERSEDED,
+                                    vib.getUid(), attrs.getUsage()),
                             /* continueExternalControl= */ true);
                 }
-                mCurrentExternalVibration = new ExternalVibrationHolder(vib);
-                vib.linkToDeath(mCurrentExternalVibration);
-                mCurrentExternalVibration.scale = mVibrationScaler.getExternalVibrationScale(
-                        attrs.getUsage());
-                scale = mCurrentExternalVibration.scale;
+                mCurrentExternalVibration = vibHolder;
+                vibHolder.linkToDeath();
+                vibHolder.scale = mVibrationScaler.getExternalVibrationScale(attrs.getUsage());
             }
 
             if (waitForCompletion) {
                 if (!mVibrationThread.waitForThreadIdle(VIBRATION_CANCEL_WAIT_MILLIS)) {
                     Slog.e(TAG, "Timed out waiting for vibration to cancel");
                     synchronized (mLock) {
-                        endExternalVibrateLocked(Vibration.Status.IGNORED_ERROR_CANCELLING,
+                        // Trigger endExternalVibrateLocked to unlink to death recipient.
+                        endExternalVibrateLocked(
+                                new Vibration.EndInfo(Vibration.Status.IGNORED_ERROR_CANCELLING),
                                 /* continueExternalControl= */ false);
                     }
                     return IExternalVibratorService.SCALE_MUTE;
@@ -1622,23 +1716,27 @@
                 if (DEBUG) {
                     Slog.d(TAG, "Vibrator going under external control.");
                 }
-                setExternalControl(true);
+                setExternalControl(true, vibHolder.stats);
             }
             if (DEBUG) {
                 Slog.e(TAG, "Playing external vibration: " + vib);
             }
-            return scale;
+            // Vibrator will start receiving data from external channels after this point.
+            // Report current time as the vibration start time, for debugging.
+            vibHolder.stats.reportStarted();
+            return vibHolder.scale;
         }
 
         @Override
         public void onExternalVibrationStop(ExternalVibration vib) {
             synchronized (mLock) {
                 if (mCurrentExternalVibration != null
-                        && mCurrentExternalVibration.externalVibration.equals(vib)) {
+                        && mCurrentExternalVibration.isHoldingSameVibration(vib)) {
                     if (DEBUG) {
                         Slog.e(TAG, "Stopping external vibration" + vib);
                     }
-                    endExternalVibrateLocked(Vibration.Status.FINISHED,
+                    endExternalVibrateLocked(
+                            new Vibration.EndInfo(Vibration.Status.FINISHED),
                             /* continueExternalControl= */ false);
                 }
             }
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 4b58b82..208450d 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -78,6 +78,11 @@
 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED;
 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
+import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO;
+import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE;
+import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM;
+import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY;
+import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN;
 import static android.content.pm.ActivityInfo.PERSIST_ACROSS_REBOOTS;
 import static android.content.pm.ActivityInfo.PERSIST_ROOT_ONLY;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
@@ -5644,7 +5649,7 @@
         ProtoLog.v(WM_DEBUG_ADD_REMOVE, "notifyAppResumed: wasStopped=%b %s",
                 wasStopped, this);
         mAppStopped = false;
-        // Allow the window to turn the screen on once the app is resumed again.
+        // Allow the window to turn the screen on once the app is started and resumed.
         if (mAtmService.getActivityStartController().isInExecution()) {
             setCurrentLaunchCanTurnScreenOn(true);
         }
@@ -8760,15 +8765,35 @@
     /**
      * Returns the min aspect ratio of this activity.
      */
-    private float getMinAspectRatio() {
-        return info.getMinAspectRatio(getRequestedOrientation());
+    float getMinAspectRatio() {
+        if (info.applicationInfo == null || !info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO) || (
+                info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY)
+                        && !ActivityInfo.isFixedOrientationPortrait(getRequestedOrientation()))) {
+            return info.getMinAspectRatio();
+        }
+
+        if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN)) {
+            return Math.max(mLetterboxUiController.getSplitScreenAspectRatio(),
+                    info.getMinAspectRatio());
+        }
+
+        if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_LARGE)) {
+            return Math.max(ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE,
+                    info.getMinAspectRatio());
+        }
+
+        if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_MEDIUM)) {
+            return Math.max(ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE,
+                    info.getMinAspectRatio());
+        }
+        return info.getMinAspectRatio();
     }
 
     /**
      * Returns true if the activity has maximum or minimum aspect ratio.
      */
     private boolean hasFixedAspectRatio() {
-        return info.hasFixedAspectRatio(getRequestedOrientation());
+        return info.getMaxAspectRatio() != 0 || getMinAspectRatio() != 0;
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index 9be9340..7c25b53 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -94,6 +94,7 @@
 
     boolean mCheckedForSetup = false;
 
+    /** Whether an {@link ActivityStarter} is currently executing (starting an Activity). */
     private boolean mInExecution = false;
 
     /**
@@ -129,7 +130,7 @@
         return mFactory.obtain().setIntent(intent).setReason(reason);
     }
 
-    void onExecutionStarted(ActivityStarter starter) {
+    void onExecutionStarted() {
         mInExecution = true;
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 99b34c7..f9e59c8 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -131,6 +131,7 @@
 import com.android.internal.app.HeavyWeightSwitcherActivity;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.util.FrameworkStatsLog;
 import com.android.server.am.PendingIntentRecord;
 import com.android.server.pm.InstantAppResolver;
 import com.android.server.power.ShutdownCheckPoints;
@@ -1268,7 +1269,7 @@
     }
 
     private void onExecutionStarted() {
-        mController.onExecutionStarted(this);
+        mController.onExecutionStarted();
     }
 
     private boolean isHomeApp(int uid, @Nullable String packageName) {
@@ -2100,6 +2101,49 @@
             }
         }
 
+        // Log activity starts which violate one of the following rules of the
+        // activity security model (ASM):
+        // 1. Only the top activity on a task can start activities on that task
+        // 2. Only the top activity on the top task can create new (top) tasks
+        // We don't currently block, but these checks may later become blocks
+        // TODO(b/236234252): Shift to BackgroundActivityStartController once
+        // class is ready
+        if (mSourceRecord != null) {
+            int callerUid = mSourceRecord.getUid();
+            ActivityRecord targetTopActivity =
+                    targetTask != null ? targetTask.getTopNonFinishingActivity() : null;
+            boolean passesAsmChecks = newTask
+                    ? mService.mVisibleActivityProcessTracker.hasResumedActivity(callerUid)
+                    : targetTopActivity != null && targetTopActivity.getUid() == callerUid;
+
+            if (!passesAsmChecks) {
+                Slog.i(TAG, "Launching r: " + r
+                        + " from background: " + mSourceRecord
+                        + ". New task: " + newTask);
+                boolean newOrEmptyTask = newTask || (targetTopActivity == null);
+                FrameworkStatsLog.write(FrameworkStatsLog.ACTIVITY_ACTION_BLOCKED,
+                        /* caller_uid */
+                        callerUid,
+                        /* caller_activity_class_name */
+                        mSourceRecord.info.name,
+                        /* target_task_top_activity_uid */
+                        newOrEmptyTask ? -1 : targetTopActivity.getUid(),
+                        /* target_task_top_activity_class_name */
+                        newOrEmptyTask ? null : targetTopActivity.info.name,
+                        /* target_task_is_different */
+                        newTask || !mSourceRecord.getTask().equals(targetTask),
+                        /* target_activity_uid */
+                        r.getUid(),
+                        /* target_activity_class_name */
+                        r.info.name,
+                        /* target_intent_action */
+                        r.intent.getAction(),
+                        /* target_intent_flags */
+                        r.intent.getFlags()
+                );
+            }
+        }
+
         return START_SUCCESS;
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 8878944..208b001 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -2652,12 +2652,12 @@
 
         @Override
         public void accept(ActivityRecord r) {
-            if (r.finishing) {
-                return;
-            }
             if (r.mLaunchCookie != null) {
                 mInfo.addLaunchCookie(r.mLaunchCookie);
             }
+            if (r.finishing) {
+                return;
+            }
             mInfo.numActivities++;
             mInfo.baseActivity = r.mActivityComponent;
             if (mTopRunning == null) {
diff --git a/services/core/java/com/android/server/wm/ContentRecorder.java b/services/core/java/com/android/server/wm/ContentRecorder.java
index 5d2d582..35a744f 100644
--- a/services/core/java/com/android/server/wm/ContentRecorder.java
+++ b/services/core/java/com/android/server/wm/ContentRecorder.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
 import static android.view.ContentRecordingSession.RECORD_CONTENT_DISPLAY;
 import static android.view.ContentRecordingSession.RECORD_CONTENT_TASK;
 
@@ -26,6 +27,7 @@
 import android.content.res.Configuration;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.media.projection.MediaProjectionManager;
 import android.os.IBinder;
 import android.provider.DeviceConfig;
 import android.view.ContentRecordingSession;
@@ -38,7 +40,7 @@
 /**
  * Manages content recording for a particular {@link DisplayContent}.
  */
-final class ContentRecorder {
+final class ContentRecorder implements WindowContainerListener {
 
     /**
      * The key for accessing the device config that controls if task recording is supported.
@@ -51,6 +53,8 @@
     @NonNull
     private final DisplayContent mDisplayContent;
 
+    @Nullable private final MediaProjectionManagerWrapper mMediaProjectionManager;
+
     /**
      * The session for content recording, or null if this DisplayContent is not being used for
      * recording.
@@ -73,8 +77,26 @@
      */
     @Nullable private Rect mLastRecordedBounds = null;
 
+    /**
+     * The last configuration orientation.
+     */
+    private int mLastOrientation = ORIENTATION_UNDEFINED;
+
     ContentRecorder(@NonNull DisplayContent displayContent) {
+        this(displayContent, () -> {
+            MediaProjectionManager mpm = displayContent.mWmService.mContext.getSystemService(
+                    MediaProjectionManager.class);
+            if (mpm != null) {
+                mpm.stopActiveProjection();
+            }
+        });
+    }
+
+    @VisibleForTesting
+    ContentRecorder(@NonNull DisplayContent displayContent,
+            @NonNull MediaProjectionManagerWrapper mediaProjectionManager) {
         mDisplayContent = displayContent;
+        mMediaProjectionManager = mediaProjectionManager;
     }
 
     /**
@@ -95,7 +117,7 @@
     }
 
     /**
-     * Start recording if this DisplayContent no longer has content. Stop recording if it now
+     * Start recording if this DisplayContent no longer has content. Pause recording if it now
      * has content or the display is not on.
      */
     @VisibleForTesting void updateRecording() {
@@ -187,7 +209,7 @@
     /**
      * Stops recording on this DisplayContent, and updates the session details.
      */
-    void remove() {
+    void stopRecording() {
         if (mRecordedSurface != null) {
             // Do not wait for the mirrored surface to be garbage collected, but clean up
             // immediately.
@@ -195,7 +217,20 @@
             mRecordedSurface = null;
             clearContentRecordingSession();
             // Do not need to force remove the VirtualDisplay; this is handled by the media
-            // projection service.
+            // projection service when the display is removed.
+        }
+    }
+
+
+    /**
+     * Ensure recording does not fall back to the display stack; ensure the recording is stopped
+     * and the client notified by tearing down the virtual display.
+     */
+    void stopMediaProjection() {
+        ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+                "Stop MediaProjection on virtual display %d", mDisplayContent.getDisplayId());
+        if (mMediaProjectionManager != null) {
+            mMediaProjectionManager.stopActiveProjection();
         }
     }
 
@@ -326,6 +361,8 @@
                     ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
                             "Unable to retrieve task to start recording for "
                                     + "display %d", mDisplayContent.getDisplayId());
+                } else {
+                    taskToRecord.registerWindowContainerListener(this);
                 }
                 return taskToRecord;
             default:
@@ -342,9 +379,9 @@
     /**
      * Exit this recording session.
      * <p>
-     * If this is a task session, tear down the recording entirely. Do not fall back
-     * to recording the entire display on the display stack; this would surprise the user
-     * given they selected task capture.
+     * If this is a task session, stop the recording entirely, including the MediaProjection.
+     * Do not fall back to recording the entire display on the display stack; this would surprise
+     * the user given they selected task capture.
      * </p><p>
      * If this is a display session, just stop recording by layer mirroring. Fall back to recording
      * from the display stack.
@@ -353,26 +390,15 @@
     private void handleStartRecordingFailed() {
         final boolean shouldExitTaskRecording = mContentRecordingSession != null
                 && mContentRecordingSession.getContentToRecord() == RECORD_CONTENT_TASK;
+        clearContentRecordingSession();
         if (shouldExitTaskRecording) {
-            // Clean up the cached session first, since tearing down the display will generate
-            // display
-            // events which will trickle back to here.
-            clearContentRecordingSession();
-            tearDownVirtualDisplay();
-        } else {
-            clearContentRecordingSession();
+            // Clean up the cached session first to ensure recording doesn't re-start, since
+            // tearing down the display will generate display events which will trickle back here.
+            stopMediaProjection();
         }
     }
 
     /**
-     * Ensure recording does not fall back to the display stack; ensure the recording is stopped
-     * and the client notified by tearing down the virtual display.
-     */
-    private void tearDownVirtualDisplay() {
-        // TODO(b/219761722) Clean up the VirtualDisplay if task mirroring fails
-    }
-
-    /**
      * Apply transformations to the mirrored surface to ensure the captured contents are scaled to
      * fit and centred in the output surface.
      *
@@ -442,4 +468,37 @@
         }
         return surfaceSize;
     }
+
+    // WindowContainerListener
+    @Override
+    public void onRemoved() {
+        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) {
+            return;
+        }
+        recordedTask.unregisterWindowContainerListener(this);
+        // Stop mirroring and teardown.
+        clearContentRecordingSession();
+        // Clean up the cached session first to ensure recording doesn't re-start, since
+        // tearing down the display will generate display events which will trickle back here.
+        stopMediaProjection();
+    }
+
+    // WindowContainerListener
+    @Override
+    public void onMergedOverrideConfigurationChanged(
+            Configuration mergedOverrideConfiguration) {
+        WindowContainerListener.super.onMergedOverrideConfigurationChanged(
+                mergedOverrideConfiguration);
+        onConfigurationChanged(mLastOrientation);
+        mLastOrientation = mergedOverrideConfiguration.orientation;
+    }
+
+    @VisibleForTesting interface MediaProjectionManagerWrapper {
+        void stopActiveProjection();
+    }
 }
diff --git a/services/core/java/com/android/server/wm/ContentRecordingController.java b/services/core/java/com/android/server/wm/ContentRecordingController.java
index fff7637..1efc202 100644
--- a/services/core/java/com/android/server/wm/ContentRecordingController.java
+++ b/services/core/java/com/android/server/wm/ContentRecordingController.java
@@ -56,14 +56,13 @@
      * Updates the current recording session. If a new display is taking over recording, then
      * stops the prior display from recording.
      *
-     * @param incomingSession the new recording session. Should either be {@code null}, to stop
-     *                        the current session, or a session on a new/different display than the
-     *                        current session.
+     * @param incomingSession the new recording session. Should either have a {@code null} token, to
+     *                        stop the current session, or a session on a new/different display
+     *                        than the current session.
      * @param wmService       the window manager service
      */
     void setContentRecordingSessionLocked(@Nullable ContentRecordingSession incomingSession,
             @NonNull WindowManagerService wmService) {
-        // TODO(b/219761722) handle a null session arriving due to task setup failing
         if (incomingSession != null && (!ContentRecordingSession.isValid(incomingSession)
                 || ContentRecordingSession.isSameDisplay(mSession, incomingSession))) {
             // Ignore an invalid session, or a session for the same display as currently recording.
@@ -82,8 +81,7 @@
         }
         if (mSession != null) {
             // Update the pre-existing display about the new session.
-            ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
-                    "Pause the recording session on display %s",
+            ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Pause the recording session on display %s",
                     mDisplayContent.getDisplayId());
             mDisplayContent.pauseRecording();
             mDisplayContent.setContentRecordingSession(null);
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index 863782a..0422906 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -207,6 +207,23 @@
         return false;
     }
 
+    @Override
+    public void setAlwaysOnTop(boolean alwaysOnTop) {
+        if (isAlwaysOnTop() == alwaysOnTop) {
+            return;
+        }
+        super.setAlwaysOnTop(alwaysOnTop);
+        // positionChildAtTop() must be called even when always on top gets turned off because
+        // we need to make sure that the display area is moved from among always on top containers
+        // to below other always on top containers. Since the position the display area should be
+        // inserted into is calculated properly in {@link DisplayContent#getTopInsertPosition()}
+        // in both cases, we can just request that the root task is put at top here.
+        if (getParent().asDisplayArea() != null) {
+            getParent().asDisplayArea().positionChildAt(POSITION_TOP, this,
+                    false /* includingParents */);
+        }
+    }
+
     boolean getIgnoreOrientationRequest() {
         // Adding an exception for when ignoreOrientationRequest is overridden at runtime for all
         // DisplayArea-s. For example, this is needed for the Kids Mode since many Kids apps aren't
@@ -234,6 +251,18 @@
         // The min possible position we can insert the child at.
         int minPosition = findMinPositionForChildDisplayArea(child);
 
+        // Place all non-always-on-top containers below always-on-top ones.
+        int alwaysOnTopCount = 0;
+        for (int i = minPosition; i <= maxPosition; i++) {
+            if (mChildren.get(i).isAlwaysOnTop()) {
+                alwaysOnTopCount++;
+            }
+        }
+        if (child.isAlwaysOnTop()) {
+            minPosition = maxPosition - alwaysOnTopCount + 1;
+        } else {
+            maxPosition -= alwaysOnTopCount;
+        }
         return Math.max(Math.min(requestPosition, maxPosition), minPosition);
     }
 
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e566a5b..ecb9fe3 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -53,7 +53,6 @@
 import static android.view.Surface.ROTATION_270;
 import static android.view.Surface.ROTATION_90;
 import static android.view.View.GONE;
-import static android.view.ViewRootImpl.LOCAL_LAYOUT;
 import static android.view.WindowInsets.Type.displayCutout;
 import static android.view.WindowInsets.Type.ime;
 import static android.view.WindowInsets.Type.systemBars;
@@ -2707,25 +2706,22 @@
         mCurrentPrivacyIndicatorBounds =
                 mCurrentPrivacyIndicatorBounds.updateStaticBounds(staticBounds);
         if (!Objects.equals(oldBounds, mCurrentPrivacyIndicatorBounds)) {
-            updateDisplayFrames(false /* insetsSourceMayChange */, true /* notifyInsetsChange */);
+            updateDisplayFrames(true /* notifyInsetsChange */);
         }
     }
 
     void onDisplayInfoChanged() {
-        updateDisplayFrames(LOCAL_LAYOUT, LOCAL_LAYOUT);
+        updateDisplayFrames(false /* notifyInsetsChange */);
         mMinSizeOfResizeableTaskDp = getMinimalTaskSizeDp();
         mInputMonitor.layoutInputConsumers(mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
         mDisplayPolicy.onDisplayInfoChanged(mDisplayInfo);
     }
 
-    private void updateDisplayFrames(boolean insetsSourceMayChange, boolean notifyInsetsChange) {
+    private void updateDisplayFrames(boolean notifyInsetsChange) {
         if (mDisplayFrames.update(mDisplayInfo,
                 calculateDisplayCutoutForRotation(mDisplayInfo.rotation),
                 calculateRoundedCornersForRotation(mDisplayInfo.rotation),
                 calculatePrivacyIndicatorBoundsForRotation(mDisplayInfo.rotation))) {
-            if (insetsSourceMayChange) {
-                mDisplayPolicy.updateInsetsSourceFramesExceptIme(mDisplayFrames);
-            }
             mInsetsStateController.onDisplayFramesUpdated(notifyInsetsChange);
         }
     }
@@ -6071,7 +6067,7 @@
         mRemoved = true;
 
         if (mContentRecorder != null) {
-            mContentRecorder.remove();
+            mContentRecorder.stopRecording();
         }
 
         // Only update focus/visibility for the last one because there may be many root tasks are
@@ -6352,6 +6348,15 @@
     }
 
     /**
+     * The MediaProjection instance is torn down.
+     */
+    @VisibleForTesting void stopMediaProjection() {
+        if (mContentRecorder != null) {
+            mContentRecorder.stopMediaProjection();
+        }
+    }
+
+    /**
      * Sets the incoming recording session. Should only be used when starting to record on
      * this display; stopping recording is handled separately when the display is destroyed.
      *
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 25d187f..5221072 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -1576,19 +1576,6 @@
         }
     }
 
-    void updateInsetsSourceFramesExceptIme(DisplayFrames displayFrames) {
-        sTmpClientFrames.attachedFrame = null;
-        for (int i = mInsetsSourceWindowsExceptIme.size() - 1; i >= 0; i--) {
-            final WindowState win = mInsetsSourceWindowsExceptIme.valueAt(i);
-            mWindowLayout.computeFrames(win.mAttrs.forRotation(displayFrames.mRotation),
-                    displayFrames.mInsetsState, displayFrames.mDisplayCutoutSafe,
-                    displayFrames.mUnrestricted, win.getWindowingMode(), UNSPECIFIED_LENGTH,
-                    UNSPECIFIED_LENGTH, win.getRequestedVisibilities(), win.mGlobalScale,
-                    sTmpClientFrames);
-            win.updateSourceFrame(sTmpClientFrames.frame);
-        }
-    }
-
     void onDisplayInfoChanged(DisplayInfo info) {
         mSystemGestures.onDisplayInfoChanged(info);
     }
@@ -1725,16 +1712,6 @@
                             win.mAttrs.insetsFlags.appearance & APPEARANCE_LIGHT_STATUS_BARS,
                             new Rect(win.getFrame())));
                     mStatusBarColorCheckedBounds.union(sTmpRect);
-                    // Check if current activity is letterboxed in order create a LetterboxDetails
-                    // component to be passed to SysUI for status bar treatment
-                    final ActivityRecord currentActivity = win.getActivityRecord();
-                    if (currentActivity != null) {
-                        final LetterboxDetails currentLetterboxDetails = currentActivity
-                                .mLetterboxUiController.getLetterboxDetails();
-                        if (currentLetterboxDetails != null) {
-                            mLetterboxDetails.add(currentLetterboxDetails);
-                        }
-                    }
                 }
             }
 
@@ -1752,6 +1729,17 @@
                     mNavBarBackgroundWindow = win;
                 }
             }
+
+            // Check if current activity is letterboxed in order create a LetterboxDetails
+            // component to be passed to SysUI for status bar treatment
+            final ActivityRecord currentActivity = win.getActivityRecord();
+            if (currentActivity != null) {
+                final LetterboxDetails currentLetterboxDetails = currentActivity
+                        .mLetterboxUiController.getLetterboxDetails();
+                if (currentLetterboxDetails != null) {
+                    mLetterboxDetails.add(currentLetterboxDetails);
+                }
+            }
         } else if (win.isDimming()) {
             if (mStatusBar != null) {
                 addStatusBarAppearanceRegionsForDimmingWindow(
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 3d91921..8dd5850 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -399,9 +399,8 @@
                 return false;
             }
 
-            final ScreenRotationAnimation screenRotationAnimation =
-                    mDisplayContent.getRotationAnimation();
-            if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
+            if (mDisplayContent.inTransition()
+                    && !mDisplayContent.mTransitionController.useShellTransitionsRotation()) {
                 // Rotation updates cannot be performed while the previous rotation change animation
                 // is still in progress. Skip this update. We will try updating again after the
                 // animation is finished and the display is unfrozen.
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index ec9ee29..c8ed602 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -257,6 +257,10 @@
                             : mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio();
         }
 
+        return getSplitScreenAspectRatio();
+    }
+
+    float getSplitScreenAspectRatio() {
         int dividerWindowWidth =
                 getResources().getDimensionPixelSize(R.dimen.docked_stack_divider_thickness);
         int dividerInsets =
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 0128c18..fb68fe6 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -242,16 +242,17 @@
 
     @Override
     public int relayout(IWindow window, WindowManager.LayoutParams attrs,
-            int requestedWidth, int requestedHeight, int viewFlags, int flags,
-            ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
-            SurfaceControl outSurfaceControl, InsetsState outInsetsState,
-            InsetsSourceControl[] outActiveControls, Bundle outSyncSeqIdBundle) {
+            int requestedWidth, int requestedHeight, int viewFlags, int flags, int seq,
+            int lastSyncSeqId, ClientWindowFrames outFrames,
+            MergedConfiguration mergedConfiguration, SurfaceControl outSurfaceControl,
+            InsetsState outInsetsState, InsetsSourceControl[] outActiveControls,
+            Bundle outSyncSeqIdBundle) {
         if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "
                 + Binder.getCallingPid());
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag);
         int res = mService.relayoutWindow(this, window, attrs,
-                requestedWidth, requestedHeight, viewFlags, flags,
-                outFrames, mergedConfiguration, outSurfaceControl, outInsetsState,
+                requestedWidth, requestedHeight, viewFlags, flags, seq,
+                lastSyncSeqId, outFrames, mergedConfiguration, outSurfaceControl, outInsetsState,
                 outActiveControls, outSyncSeqIdBundle);
         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to "
@@ -260,6 +261,16 @@
     }
 
     @Override
+    public void relayoutAsync(IWindow window, WindowManager.LayoutParams attrs,
+            int requestedWidth, int requestedHeight, int viewFlags, int flags, int seq,
+            int lastSyncSeqId) {
+        relayout(window, attrs, requestedWidth, requestedHeight, viewFlags, flags, seq,
+                lastSyncSeqId, null /* outFrames */, null /* mergedConfiguration */,
+                null /* outSurfaceControl */, null /* outInsetsState */,
+                null /* outActiveControls */, null /* outSyncIdBundle */);
+    }
+
+    @Override
     public boolean outOfMemory(IWindow window) {
         return mService.outOfMemoryWindow(this, window);
     }
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 2ba0e23..75552e0 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -489,6 +489,7 @@
     static final int FLAG_FORCE_HIDDEN_FOR_PINNED_TASK = 1;
     static final int FLAG_FORCE_HIDDEN_FOR_TASK_ORG = 1 << 1;
     private int mForceHiddenFlags = 0;
+    private boolean mForceTranslucent = false;
 
     // TODO(b/160201781): Revisit double invocation issue in Task#removeChild.
     /**
@@ -4348,6 +4349,10 @@
         return true;
     }
 
+    void setForceTranslucent(boolean set) {
+        mForceTranslucent = set;
+    }
+
     @Override
     public boolean isAlwaysOnTop() {
         return !isForceHidden() && super.isAlwaysOnTop();
@@ -4366,6 +4371,11 @@
     }
 
     @Override
+    protected boolean isForceTranslucent() {
+        return mForceTranslucent;
+    }
+
+    @Override
     long getProtoFieldId() {
         return TASK;
     }
@@ -5339,7 +5349,7 @@
                     abort = true;
                 }
                 if (abort) {
-                    Slog.e(TAG, "Cannot navigateUpTo, intent =" + destIntent);
+                    android.util.EventLog.writeEvent(0x534e4554, "238605611", callingUid, "");
                     foundParentInTask = false;
                 } else {
                     parent.deliverNewIntentLocked(callingUid, destIntent, destGrants,
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 8d94324..5f85a14 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -740,6 +740,10 @@
         return false;
     }
 
+    protected boolean isForceTranslucent() {
+        return false;
+    }
+
     boolean isLeafTaskFragment() {
         for (int i = mChildren.size() - 1; i >= 0; --i) {
             if (mChildren.get(i).asTaskFragment() != null) {
@@ -865,7 +869,7 @@
      */
     @VisibleForTesting
     boolean isTranslucent(ActivityRecord starting) {
-        if (!isAttached() || isForceHidden()) {
+        if (!isAttached() || isForceHidden() || isForceTranslucent()) {
             return true;
         }
         final PooledPredicate p = PooledLambda.obtainPredicate(TaskFragment::isOpaqueActivity,
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index 9bb0271..8f07bb7 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -731,7 +731,7 @@
         }
 
         // First we get the default size we want.
-        getDefaultFreeformSize(root.info, displayArea, layout, orientation, mTmpBounds);
+        getDefaultFreeformSize(root, displayArea, layout, orientation, mTmpBounds);
         if (hasInitialBounds || sizeMatches(inOutBounds, mTmpBounds)) {
             // We're here because either input parameters specified initial bounds, or the suggested
             // bounds have the same size of the default freeform size. We should use the suggested
@@ -799,7 +799,7 @@
         return orientation;
     }
 
-    private void getDefaultFreeformSize(@NonNull ActivityInfo info,
+    private void getDefaultFreeformSize(@NonNull ActivityRecord activityRecord,
             @NonNull TaskDisplayArea displayArea,
             @NonNull ActivityInfo.WindowLayout layout, int orientation, @NonNull Rect bounds) {
         // Default size, which is letterboxing/pillarboxing in displayArea. That's to say the large
@@ -807,6 +807,7 @@
         // dimension of default size is calculated to keep the same aspect ratio as the
         // displayArea's. Here we use stable bounds of displayArea because that indicates the area
         // that isn't occupied by system widgets (e.g. sysbar and navbar).
+        final ActivityInfo info = activityRecord.info;
         final Rect stableBounds = mTmpStableBounds;
         displayArea.getStableRect(stableBounds);
         final int portraitHeight = Math.min(stableBounds.width(), stableBounds.height());
@@ -832,7 +833,7 @@
         final int layoutMinHeight = (layout == null) ? -1 : layout.minHeight;
 
         // Aspect ratio requirements.
-        final float minAspectRatio = info.getMinAspectRatio(orientation);
+        final float minAspectRatio = activityRecord.getMinAspectRatio();
         final float maxAspectRatio = info.getMaxAspectRatio();
 
         final int width = Math.min(defaultWidth, Math.max(phoneWidth, layoutMinWidth));
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index bbc95a1..584a40e 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -622,9 +622,11 @@
             throw new IllegalStateException("Can't finish a non-playing transition " + mSyncId);
         }
 
+        boolean hasParticipatedDisplay = false;
         // Commit all going-invisible containers
         for (int i = 0; i < mParticipants.size(); ++i) {
-            final ActivityRecord ar = mParticipants.valueAt(i).asActivityRecord();
+            final WindowContainer<?> participant = mParticipants.valueAt(i);
+            final ActivityRecord ar = participant.asActivityRecord();
             if (ar != null) {
                 boolean visibleAtTransitionEnd = mVisibleAtTransitionEndTokens.contains(ar);
                 // We need both the expected visibility AND current requested-visibility to be
@@ -656,8 +658,13 @@
                     // Legacy dispatch relies on this (for now).
                     ar.mEnteringAnimation = visibleAtTransitionEnd;
                 }
+                continue;
             }
-            final WallpaperWindowToken wt = mParticipants.valueAt(i).asWallpaperToken();
+            if (participant.asDisplayContent() != null) {
+                hasParticipatedDisplay = true;
+                continue;
+            }
+            final WallpaperWindowToken wt = participant.asWallpaperToken();
             if (wt != null) {
                 final boolean visibleAtTransitionEnd = mVisibleAtTransitionEndTokens.contains(wt);
                 if (!visibleAtTransitionEnd && !wt.isVisibleRequested()) {
@@ -737,6 +744,12 @@
 
         mState = STATE_FINISHED;
         mController.mTransitionTracer.logState(this);
+        // Rotation change may be deferred while there is a display change transition, so check
+        // again in case there is a new pending change.
+        if (hasParticipatedDisplay && !mController.useShellTransitionsRotation()) {
+            mController.mAtm.mWindowManager.updateRotation(false /* alwaysSendConfiguration */,
+                    false /* forceRelayout */);
+        }
     }
 
     void abort() {
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 9eee7ba..7cbdf0f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -880,6 +880,8 @@
      * Must be invoked for a valid MediaProjection session.
      *
      * @param incomingSession the nullable incoming content recording session
+     * @return {@code true} if successfully set the session, or {@code false} if the session
+     * could not be prepared and the session needs to be torn down.
      */
-    public abstract void setContentRecordingSession(ContentRecordingSession incomingSession);
+    public abstract boolean setContentRecordingSession(ContentRecordingSession incomingSession);
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 296390a..1d82bfc 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2246,11 +2246,14 @@
     }
 
     public int relayoutWindow(Session session, IWindow client, LayoutParams attrs,
-            int requestedWidth, int requestedHeight, int viewVisibility, int flags,
-            ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
-            SurfaceControl outSurfaceControl, InsetsState outInsetsState,
-            InsetsSourceControl[] outActiveControls, Bundle outSyncIdBundle) {
-        Arrays.fill(outActiveControls, null);
+            int requestedWidth, int requestedHeight, int viewVisibility, int flags, int seq,
+            int lastSyncSeqId, ClientWindowFrames outFrames,
+            MergedConfiguration outMergedConfiguration, SurfaceControl outSurfaceControl,
+            InsetsState outInsetsState, InsetsSourceControl[] outActiveControls,
+            Bundle outSyncIdBundle) {
+        if (outActiveControls != null) {
+            Arrays.fill(outActiveControls, null);
+        }
         int result = 0;
         boolean configChanged;
         final int pid = Binder.getCallingPid();
@@ -2261,8 +2264,15 @@
             if (win == null) {
                 return 0;
             }
+            if (win.mRelayoutSeq < seq) {
+                win.mRelayoutSeq = seq;
+            } else if (win.mRelayoutSeq > seq) {
+                return 0;
+            }
 
-            if (win.cancelAndRedraw() && win.mPrepareSyncSeqId <= win.mLastSeqIdSentToRelayout) {
+            if (win.cancelAndRedraw() && win.mPrepareSyncSeqId <= lastSyncSeqId) {
+                // The client has reported the sync draw, but we haven't finished it yet.
+                // Don't let the client perform a non-sync draw at this time.
                 result |= RELAYOUT_RES_CANCEL_AND_REDRAW;
             }
 
@@ -2431,7 +2441,7 @@
 
             // Create surfaceControl before surface placement otherwise layout will be skipped
             // (because WS.isGoneForLayout() is true when there is no surface.
-            if (shouldRelayout) {
+            if (shouldRelayout && outSurfaceControl != null) {
                 try {
                     result = createSurfaceControl(outSurfaceControl, result, win, winAnimator);
                 } catch (Exception e) {
@@ -2470,22 +2480,25 @@
                 winAnimator.mEnterAnimationPending = false;
                 winAnimator.mEnteringAnimation = false;
 
-                if (viewVisibility == View.VISIBLE && winAnimator.hasSurface()) {
-                    // We already told the client to go invisible, but the message may not be
-                    // handled yet, or it might want to draw a last frame. If we already have a
-                    // surface, let the client use that, but don't create new surface at this point.
-                    Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: getSurface");
-                    winAnimator.mSurfaceController.getSurfaceControl(outSurfaceControl);
-                    Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
-                } else {
-                    if (DEBUG_VISIBILITY) Slog.i(TAG_WM, "Releasing surface in: " + win);
-
-                    try {
-                        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wmReleaseOutSurface_"
-                                + win.mAttrs.getTitle());
-                        outSurfaceControl.release();
-                    } finally {
+                if (outSurfaceControl != null) {
+                    if (viewVisibility == View.VISIBLE && winAnimator.hasSurface()) {
+                        // We already told the client to go invisible, but the message may not be
+                        // handled yet, or it might want to draw a last frame. If we already have a
+                        // surface, let the client use that, but don't create new surface at this
+                        // point.
+                        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: getSurface");
+                        winAnimator.mSurfaceController.getSurfaceControl(outSurfaceControl);
                         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+                    } else {
+                        if (DEBUG_VISIBILITY) Slog.i(TAG_WM, "Releasing surface in: " + win);
+
+                        try {
+                            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wmReleaseOutSurface_"
+                                    + win.mAttrs.getTitle());
+                            outSurfaceControl.release();
+                        } finally {
+                            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+                        }
                     }
                 }
 
@@ -2538,20 +2551,16 @@
                 win.mResizedWhileGone = false;
             }
 
-            win.fillClientWindowFramesAndConfiguration(outFrames, mergedConfiguration,
-                    false /* useLatestConfig */, shouldRelayout);
+            if (outFrames != null && outMergedConfiguration != null) {
+                win.fillClientWindowFramesAndConfiguration(outFrames, outMergedConfiguration,
+                        false /* useLatestConfig */, shouldRelayout);
 
-            // Set resize-handled here because the values are sent back to the client.
-            win.onResizeHandled();
+                // Set resize-handled here because the values are sent back to the client.
+                win.onResizeHandled();
+            }
 
-            outInsetsState.set(win.getCompatInsetsState(), win.isClientLocal());
-            if (DEBUG) {
-                Slog.v(TAG_WM, "Relayout given client " + client.asBinder()
-                        + ", requestedWidth=" + requestedWidth
-                        + ", requestedHeight=" + requestedHeight
-                        + ", viewVisibility=" + viewVisibility
-                        + "\nRelayout returning frame=" + outFrames.frame
-                        + ", surface=" + outSurfaceControl);
+            if (outInsetsState != null) {
+                outInsetsState.set(win.getCompatInsetsState(), win.isClientLocal());
             }
 
             ProtoLog.v(WM_DEBUG_FOCUS, "Relayout of %s: focusMayChange=%b",
@@ -2562,14 +2571,16 @@
             }
             win.mInRelayout = false;
 
-            if (mUseBLASTSync && win.useBLASTSync() && viewVisibility != View.GONE
-                    && (win.mSyncSeqId > win.mLastSeqIdSentToRelayout)) {
-                win.markRedrawForSyncReported();
-
-                win.mLastSeqIdSentToRelayout = win.mSyncSeqId;
-                outSyncIdBundle.putInt("seqid", win.mSyncSeqId);
-            } else {
-                outSyncIdBundle.putInt("seqid", -1);
+            if (outSyncIdBundle != null) {
+                final int maybeSyncSeqId;
+                if (mUseBLASTSync && win.useBLASTSync() && viewVisibility != View.GONE
+                        && win.mSyncSeqId > lastSyncSeqId) {
+                    maybeSyncSeqId = win.mSyncSeqId;
+                    win.markRedrawForSyncReported();
+                } else {
+                    maybeSyncSeqId = -1;
+                }
+                outSyncIdBundle.putInt("seqid", maybeSyncSeqId);
             }
 
             if (configChanged) {
@@ -2578,7 +2589,9 @@
                 displayContent.sendNewConfiguration();
                 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
             }
-            getInsetsSourceControls(win, outActiveControls);
+            if (outActiveControls != null) {
+                getInsetsSourceControls(win, outActiveControls);
+            }
         }
 
         Binder.restoreCallingIdentity(origId);
@@ -4290,7 +4303,9 @@
                     // Even if alwaysSend, we are waiting for a transition or remote to provide
                     // updated configuration, so we can't update configuration yet.
                     if (!pendingRemoteDisplayChange) {
-                        if (!rotationChanged || forceRelayout) {
+                        // The layout-needed flag will be set if there is a rotation change, so
+                        // only set it if the caller requests to force relayout.
+                        if (forceRelayout) {
                             displayContent.setLayoutNeeded();
                             layoutNeeded = true;
                         }
@@ -8291,14 +8306,15 @@
         }
 
         @Override
-        public void setContentRecordingSession(@Nullable ContentRecordingSession incomingSession) {
+        public boolean setContentRecordingSession(
+                @Nullable ContentRecordingSession incomingSession) {
             synchronized (mGlobalLock) {
-                // Allow the controller to handle teardown or a non-task session.
+                // Allow the controller to handle teardown of a non-task session.
                 if (incomingSession == null
                         || incomingSession.getContentToRecord() != RECORD_CONTENT_TASK) {
                     mContentRecordingController.setContentRecordingSessionLocked(incomingSession,
                             WindowManagerService.this);
-                    return;
+                    return true;
                 }
                 // For a task session, find the activity identified by the launch cookie.
                 final WindowContainerToken wct = getTaskWindowContainerTokenForLaunchCookie(
@@ -8306,15 +8322,14 @@
                 if (wct == null) {
                     Slog.w(TAG, "Handling a new recording session; unable to find the "
                             + "WindowContainerToken");
-                    mContentRecordingController.setContentRecordingSessionLocked(null,
-                            WindowManagerService.this);
-                    return;
+                    return false;
                 }
                 // Replace the launch cookie in the session details with the task's
                 // WindowContainerToken.
                 incomingSession.setTokenToRecord(wct.asBinder());
                 mContentRecordingController.setContentRecordingSessionLocked(incomingSession,
                         WindowManagerService.this);
+                return true;
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 29e407f..3b9cd36 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -37,6 +37,7 @@
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_RESTORE_TRANSIENT_ORDER;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS;
+import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
@@ -645,6 +646,12 @@
             }
         }
 
+        if ((c.getChangeMask()
+                & WindowContainerTransaction.Change.CHANGE_FORCE_TRANSLUCENT) != 0) {
+            tr.setForceTranslucent(c.getForceTranslucent());
+            effects = TRANSACT_EFFECTS_LIFECYCLE;
+        }
+
         final int childWindowingMode = c.getActivityWindowingMode();
         if (childWindowingMode > -1) {
             tr.setActivityWindowingMode(childWindowingMode);
@@ -1073,6 +1080,18 @@
                 WindowContainer.fromBinder(hop.getContainer())
                         .removeLocalInsetsSourceProvider(hop.getInsetsTypes());
                 break;
+            case HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP:
+                final WindowContainer container = WindowContainer.fromBinder(hop.getContainer());
+                if (container == null || container.asDisplayArea() == null
+                        || !container.isAttached()) {
+                    Slog.e(TAG, "Attempt to operate on unknown or detached display area: "
+                            + container);
+                    break;
+                }
+                container.setAlwaysOnTop(hop.isAlwaysOnTop());
+                effects |= TRANSACT_EFFECTS_LIFECYCLE;
+                break;
+
         }
         return effects;
     }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 86fa356..41bcbf6 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -390,7 +390,6 @@
      * examine the git commit message introducing this comment and variable.2
      */
     int mSyncSeqId = 0;
-    int mLastSeqIdSentToRelayout = 0;
 
     /** The last syncId associated with a prepareSync or 0 when no sync is active. */
     int mPrepareSyncSeqId = 0;
@@ -426,6 +425,7 @@
     boolean mHaveFrame;
     boolean mObscured;
 
+    int mRelayoutSeq = -1;
     int mLayoutSeq = -1;
 
     /**
@@ -1350,29 +1350,15 @@
         final WindowFrames windowFrames = mWindowFrames;
         mTmpRect.set(windowFrames.mParentFrame);
 
-        if (LOCAL_LAYOUT) {
-            windowFrames.mCompatFrame.set(clientWindowFrames.frame);
+        windowFrames.mDisplayFrame.set(clientWindowFrames.displayFrame);
+        windowFrames.mParentFrame.set(clientWindowFrames.parentFrame);
+        windowFrames.mFrame.set(clientWindowFrames.frame);
 
-            windowFrames.mFrame.set(clientWindowFrames.frame);
-            windowFrames.mDisplayFrame.set(clientWindowFrames.displayFrame);
-            windowFrames.mParentFrame.set(clientWindowFrames.parentFrame);
-            if (mGlobalScale != 1f) {
-                // The frames sent from the client need to be adjusted to the real coordinate space.
-                windowFrames.mFrame.scale(mGlobalScale);
-                windowFrames.mDisplayFrame.scale(mGlobalScale);
-                windowFrames.mParentFrame.scale(mGlobalScale);
-            }
-        } else {
-            windowFrames.mDisplayFrame.set(clientWindowFrames.displayFrame);
-            windowFrames.mParentFrame.set(clientWindowFrames.parentFrame);
-            windowFrames.mFrame.set(clientWindowFrames.frame);
-
-            windowFrames.mCompatFrame.set(windowFrames.mFrame);
-            if (mInvGlobalScale != 1f) {
-                // Also, the scaled frame that we report to the app needs to be adjusted to be in
-                // its coordinate space.
-                windowFrames.mCompatFrame.scale(mInvGlobalScale);
-            }
+        windowFrames.mCompatFrame.set(windowFrames.mFrame);
+        if (mInvGlobalScale != 1f) {
+            // Also, the scaled frame that we report to the app needs to be adjusted to be in
+            // its coordinate space.
+            windowFrames.mCompatFrame.scale(mInvGlobalScale);
         }
         windowFrames.setParentFrameWasClippedByDisplayCutout(
                 clientWindowFrames.isParentFrameClippedByDisplayCutout);
@@ -1416,13 +1402,6 @@
 
         updateSourceFrame(windowFrames.mFrame);
 
-        if (LOCAL_LAYOUT) {
-            if (!mHaveFrame) {
-                // The first frame should not be considered as moved.
-                updateLastFrames();
-            }
-        }
-
         if (mActivityRecord != null && !mIsChildWindow) {
             mActivityRecord.layoutLetterbox(this);
         }
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 09044e7..073b131c 100644
--- a/services/core/xsd/display-device-config/display-device-config.xsd
+++ b/services/core/xsd/display-device-config/display-device-config.xsd
@@ -45,6 +45,8 @@
                 <xs:element type="highBrightnessMode" name="highBrightnessMode" minOccurs="0"
                             maxOccurs="1"/>
                 <xs:element type="displayQuirks" name="quirks" minOccurs="0" maxOccurs="1" />
+                <xs:element type="autoBrightness" name="autoBrightness" minOccurs="0"
+                            maxOccurs="1" />
                 <xs:element type="nonNegativeDecimal" name="screenBrightnessRampFastDecrease">
                     <xs:annotation name="final"/>
                 </xs:element>
@@ -101,6 +103,21 @@
 
     <!-- Type definitions -->
 
+    <xs:complexType name="autoBrightness">
+        <xs:sequence>
+            <!-- Sets the debounce for autoBrightness brightening in millis-->
+            <xs:element name="brighteningLightDebounceMillis" type="xs:nonNegativeInteger"
+                        minOccurs="0" maxOccurs="1">
+                <xs:annotation name="final"/>
+            </xs:element>
+            <!-- Sets the debounce for autoBrightness darkening in millis-->
+            <xs:element name="darkeningLightDebounceMillis" type="xs:nonNegativeInteger"
+                        minOccurs="0" maxOccurs="1">
+                <xs:annotation name="final"/>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+
     <xs:complexType name="displayQuirks">
         <xs:sequence>
             <xs:element name="quirk" type="xs:string" minOccurs="0" maxOccurs="unbounded" />
@@ -341,5 +358,4 @@
             <xs:annotation name="final"/>
         </xs:element>
     </xs:complexType>
-
 </xs:schema>
diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt
index e8b13ca..e9a9269 100644
--- a/services/core/xsd/display-device-config/schema/current.txt
+++ b/services/core/xsd/display-device-config/schema/current.txt
@@ -1,6 +1,14 @@
 // Signature format: 2.0
 package com.android.server.display.config {
 
+  public class AutoBrightness {
+    ctor public AutoBrightness();
+    method public final java.math.BigInteger getBrighteningLightDebounceMillis();
+    method public final java.math.BigInteger getDarkeningLightDebounceMillis();
+    method public final void setBrighteningLightDebounceMillis(java.math.BigInteger);
+    method public final void setDarkeningLightDebounceMillis(java.math.BigInteger);
+  }
+
   public class BrightnessThresholds {
     ctor public BrightnessThresholds();
     method @NonNull public final java.math.BigDecimal getMinimum();
@@ -40,6 +48,7 @@
     method @NonNull public final com.android.server.display.config.Thresholds getAmbientBrightnessChangeThresholds();
     method public final java.math.BigInteger getAmbientLightHorizonLong();
     method public final java.math.BigInteger getAmbientLightHorizonShort();
+    method public com.android.server.display.config.AutoBrightness getAutoBrightness();
     method @Nullable public final com.android.server.display.config.DensityMapping getDensityMapping();
     method @NonNull public final com.android.server.display.config.Thresholds getDisplayBrightnessChangeThresholds();
     method public com.android.server.display.config.HighBrightnessMode getHighBrightnessMode();
@@ -58,6 +67,7 @@
     method public final void setAmbientBrightnessChangeThresholds(@NonNull com.android.server.display.config.Thresholds);
     method public final void setAmbientLightHorizonLong(java.math.BigInteger);
     method public final void setAmbientLightHorizonShort(java.math.BigInteger);
+    method public void setAutoBrightness(com.android.server.display.config.AutoBrightness);
     method public final void setDensityMapping(@Nullable com.android.server.display.config.DensityMapping);
     method public final void setDisplayBrightnessChangeThresholds(@NonNull com.android.server.display.config.Thresholds);
     method public void setHighBrightnessMode(com.android.server.display.config.HighBrightnessMode);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 66c9f55..8fd4b5a 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -338,6 +338,8 @@
             "com.android.server.contentcapture.ContentCaptureManagerService";
     private static final String TRANSLATION_MANAGER_SERVICE_CLASS =
             "com.android.server.translation.TranslationManagerService";
+    private static final String SELECTION_TOOLBAR_MANAGER_SERVICE_CLASS =
+            "com.android.server.selectiontoolbar.SelectionToolbarManagerService";
     private static final String MUSIC_RECOGNITION_MANAGER_SERVICE_CLASS =
             "com.android.server.musicrecognition.MusicRecognitionManagerService";
     private static final String SYSTEM_CAPTIONS_MANAGER_SERVICE_CLASS =
@@ -2634,6 +2636,11 @@
             Slog.d(TAG, "TranslationService not defined by OEM");
         }
 
+        // Selection toolbar service
+        t.traceBegin("StartSelectionToolbarManagerService");
+        mSystemServiceManager.startService(SELECTION_TOOLBAR_MANAGER_SERVICE_CLASS);
+        t.traceEnd();
+
         // NOTE: ClipboardService depends on ContentCapture and Autofill
         t.traceBegin("StartClipboardService");
         mSystemServiceManager.startService(ClipboardService.class);
diff --git a/services/selectiontoolbar/Android.bp b/services/selectiontoolbar/Android.bp
new file mode 100644
index 0000000..cc6405f
--- /dev/null
+++ b/services/selectiontoolbar/Android.bp
@@ -0,0 +1,22 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+    name: "services.selectiontoolbar-sources",
+    srcs: ["java/**/*.java"],
+    path: "java",
+    visibility: ["//frameworks/base/services"],
+}
+
+java_library_static {
+    name: "services.selectiontoolbar",
+    defaults: ["platform_service_defaults"],
+    srcs: [":services.selectiontoolbar-sources"],
+    libs: ["services.core"],
+}
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 7939303..03ea613 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
@@ -86,6 +86,8 @@
                 0.0f);
         assertEquals(mDisplayDeviceConfig.getScreenBrighteningMinThreshold(), 0.001, 0.000001f);
         assertEquals(mDisplayDeviceConfig.getScreenDarkeningMinThreshold(), 0.002, 0.000001f);
+        assertEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLightDebounce(), 2000);
+        assertEquals(mDisplayDeviceConfig.getAutoBrightnessDarkeningLightDebounce(), 1000);
 
         // Todo(brup): Add asserts for BrightnessThrottlingData, DensityMapping,
         // HighBrightnessModeData AmbientLightSensor, RefreshRateLimitations and ProximitySensor.
@@ -109,6 +111,10 @@
                 +           "<nits>800.0</nits>\n"
                 +       "</point>\n"
                 +   "</screenBrightnessMap>\n"
+                +   "<autoBrightness>\n"
+                +       "<brighteningLightDebounceMillis>2000</brighteningLightDebounceMillis>\n"
+                +       "<darkeningLightDebounceMillis>1000</darkeningLightDebounceMillis>\n"
+                +   "</autoBrightness>\n"
                 +   "<highBrightnessMode enabled=\"true\">\n"
                 +       "<transitionPoint>0.62</transitionPoint>\n"
                 +       "<minimumLux>10000</minimumLux>\n"
diff --git a/services/tests/servicestests/src/com/android/server/policy/SideFpsEventHandlerTest.java b/services/tests/servicestests/src/com/android/server/policy/SideFpsEventHandlerTest.java
index 7746bd6..0635cc4 100644
--- a/services/tests/servicestests/src/com/android/server/policy/SideFpsEventHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/policy/SideFpsEventHandlerTest.java
@@ -24,7 +24,6 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.app.AlertDialog;
 import android.content.pm.PackageManager;
 import android.hardware.biometrics.BiometricStateListener;
 import android.hardware.fingerprint.FingerprintManager;
@@ -36,10 +35,13 @@
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableContext;
+import android.testing.TestableResources;
 import android.view.Window;
 
 import androidx.test.InstrumentationRegistry;
 
+import com.android.internal.R;
+
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -47,7 +49,6 @@
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
-import org.mockito.Spy;
 
 import java.util.List;
 
@@ -68,17 +69,22 @@
                     BiometricStateListener.STATE_BP_AUTH,
                     BiometricStateListener.STATE_AUTH_OTHER);
 
+    private static final Integer AUTO_DISMISS_DIALOG = 500;
+
     @Rule
     public TestableContext mContext =
             new TestableContext(InstrumentationRegistry.getContext(), null);
 
-    @Mock private PackageManager mPackageManager;
-    @Mock private FingerprintManager mFingerprintManager;
-    @Spy private AlertDialog.Builder mDialogBuilder = new AlertDialog.Builder(mContext);
-    @Mock private AlertDialog mAlertDialog;
-    @Mock private Window mWindow;
+    @Mock
+    private PackageManager mPackageManager;
+    @Mock
+    private FingerprintManager mFingerprintManager;
+    @Mock
+    private SideFpsToast mDialog;
+    @Mock
+    private Window mWindow;
 
-    private TestLooper mLooper = new TestLooper();
+    private final TestLooper mLooper = new TestLooper();
     private SideFpsEventHandler mEventHandler;
     private BiometricStateListener mBiometricStateListener;
 
@@ -88,16 +94,17 @@
 
         mContext.addMockSystemService(PackageManager.class, mPackageManager);
         mContext.addMockSystemService(FingerprintManager.class, mFingerprintManager);
+        TestableResources resources = mContext.getOrCreateTestableResources();
+        resources.addOverride(R.integer.config_sideFpsToastTimeout, AUTO_DISMISS_DIALOG);
 
-        when(mDialogBuilder.create()).thenReturn(mAlertDialog);
-        when(mAlertDialog.getWindow()).thenReturn(mWindow);
+        when(mDialog.getWindow()).thenReturn(mWindow);
 
         mEventHandler =
                 new SideFpsEventHandler(
                         mContext,
                         new Handler(mLooper.getLooper()),
                         mContext.getSystemService(PowerManager.class),
-                        () -> mDialogBuilder);
+                        (ctx) -> mDialog);
     }
 
     @Test
@@ -108,7 +115,7 @@
         assertThat(mEventHandler.shouldConsumeSinglePress(60L)).isFalse();
 
         mLooper.dispatchAll();
-        verify(mAlertDialog, never()).show();
+        verify(mDialog, never()).show();
     }
 
     @Test
@@ -120,7 +127,7 @@
             assertThat(mEventHandler.shouldConsumeSinglePress(200L)).isFalse();
 
             mLooper.dispatchAll();
-            verify(mAlertDialog, never()).show();
+            verify(mDialog, never()).show();
         }
     }
 
@@ -133,7 +140,7 @@
             assertThat(mEventHandler.shouldConsumeSinglePress(400L)).isFalse();
 
             mLooper.dispatchAll();
-            verify(mAlertDialog, never()).show();
+            verify(mDialog, never()).show();
         }
     }
 
@@ -148,7 +155,7 @@
         assertThat(mEventHandler.shouldConsumeSinglePress(90000L)).isFalse();
 
         mLooper.dispatchAll();
-        verify(mAlertDialog, never()).show();
+        verify(mDialog, never()).show();
     }
 
     @Test
@@ -159,18 +166,18 @@
         assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isFalse();
 
         mLooper.dispatchAll();
-        verify(mAlertDialog, never()).show();
+        verify(mDialog, never()).show();
     }
 
     @Test
-    public void promptsWhenBPisActive() throws Exception {
+    public void doesNotpromptWhenBPisActive() throws Exception {
         setupWithSensor(true /* hasSideFps */, true /* initialized */);
 
         setBiometricState(BiometricStateListener.STATE_BP_AUTH);
         assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue();
 
         mLooper.dispatchAll();
-        verify(mAlertDialog, never()).show();
+        verify(mDialog, never()).show();
     }
 
     @Test
@@ -181,57 +188,40 @@
         assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue();
 
         mLooper.dispatchAll();
-        verify(mAlertDialog).show();
-        verify(mAlertDialog, never()).dismiss();
+        verify(mDialog).show();
     }
 
     @Test
-    public void dismissesDialogOnTouchWhenEnrolling() throws Exception {
+    public void dialogDismissesAfterTime() throws Exception {
         setupWithSensor(true /* hasSfps */, true /* initialized */);
 
         setBiometricState(BiometricStateListener.STATE_ENROLLING);
-        when(mAlertDialog.isShowing()).thenReturn(true);
+        when(mDialog.isShowing()).thenReturn(true);
         assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue();
 
         mLooper.dispatchAll();
-        verify(mAlertDialog).show();
-
-        mBiometricStateListener.onBiometricAction(BiometricStateListener.ACTION_SENSOR_TOUCH);
-        mLooper.moveTimeForward(10000);
+        verify(mDialog).show();
+        mLooper.moveTimeForward(AUTO_DISMISS_DIALOG);
         mLooper.dispatchAll();
-
-        verify(mAlertDialog).dismiss();
+        verify(mDialog).dismiss();
     }
 
     @Test
-    public void dismissesDialogFailsWhenPowerPressedAndDialogShowing() throws Exception {
+    public void dialogDoesNotDismissOnSensorTouch() throws Exception {
         setupWithSensor(true /* hasSfps */, true /* initialized */);
 
         setBiometricState(BiometricStateListener.STATE_ENROLLING);
-        when(mAlertDialog.isShowing()).thenReturn(true);
+        when(mDialog.isShowing()).thenReturn(true);
         assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue();
 
         mLooper.dispatchAll();
-        verify(mAlertDialog).show();
+        verify(mDialog).show();
 
         mBiometricStateListener.onBiometricAction(BiometricStateListener.ACTION_SENSOR_TOUCH);
-        assertThat(mEventHandler.shouldConsumeSinglePress(60L)).isTrue();
-
+        mLooper.moveTimeForward(AUTO_DISMISS_DIALOG - 1);
         mLooper.dispatchAll();
-        verify(mAlertDialog, never()).dismiss();
-    }
 
-    @Test
-    public void showDialogAfterTap() throws Exception {
-        setupWithSensor(true /* hasSfps */, true /* initialized */);
-
-        setBiometricState(BiometricStateListener.STATE_ENROLLING);
-        when(mAlertDialog.isShowing()).thenReturn(true);
-        mBiometricStateListener.onBiometricAction(BiometricStateListener.ACTION_SENSOR_TOUCH);
-        assertThat(mEventHandler.shouldConsumeSinglePress(60L)).isTrue();
-
-        mLooper.dispatchAll();
-        verify(mAlertDialog).show();
+        verify(mDialog, never()).dismiss();
     }
 
     private void setBiometricState(@BiometricStateListener.State int newState) {
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java b/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java
index fa3fcd9..235849c 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java
@@ -127,9 +127,17 @@
         }
 
         @Override
-        public long compose(PrimitiveSegment[] effects, long vibrationId) {
+        public long compose(PrimitiveSegment[] primitives, long vibrationId) {
+            if (mSupportedPrimitives == null) {
+                return 0;
+            }
+            for (PrimitiveSegment primitive : primitives) {
+                if (Arrays.binarySearch(mSupportedPrimitives, primitive.getPrimitiveId()) < 0) {
+                    return 0;
+                }
+            }
             long duration = 0;
-            for (PrimitiveSegment primitive : effects) {
+            for (PrimitiveSegment primitive : primitives) {
                 duration += EFFECT_DURATION + primitive.getDelay();
                 recordEffectSegment(vibrationId, primitive);
             }
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationTest.java
new file mode 100644
index 0000000..b469299
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vibrator;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static java.util.stream.Collectors.toList;
+
+import android.platform.test.annotations.Presubmit;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+
+/**
+ * Tests for {@link Vibration}.
+ *
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:VibrationTest
+ */
+@Presubmit
+public class VibrationTest {
+
+    @Test
+    public void status_hasUniqueProtoEnumValues() {
+        assertThat(
+                Arrays.stream(Vibration.Status.values())
+                        .map(Vibration.Status::getProtoEnumValue)
+                        .collect(toList()))
+                .containsNoDuplicates();
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
index de5f6ed..ca162ef 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
@@ -257,13 +257,18 @@
         assertTrue(mThread.isRunningVibrationId(vibrationId));
         assertTrue(mControllers.get(VIBRATOR_ID).isVibrating());
 
-        conductor.notifyCancelled(Vibration.Status.CANCELLED_SUPERSEDED, /* immediate= */ false);
+        Vibration.EndInfo cancelVibrationInfo = new Vibration.EndInfo(
+                Vibration.Status.CANCELLED_SUPERSEDED, /* endedByUid= */ 1,
+                /* endedByUsage= */ VibrationAttributes.USAGE_ALARM);
+        conductor.notifyCancelled(
+                cancelVibrationInfo,
+                /* immediate= */ false);
         waitForCompletion();
         assertFalse(mThread.isRunningVibrationId(vibrationId));
 
         verify(mManagerHooks).noteVibratorOn(eq(UID), anyLong());
         verify(mManagerHooks).noteVibratorOff(eq(UID));
-        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_SUPERSEDED);
+        verifyCallbacksTriggered(vibrationId, cancelVibrationInfo);
         assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
 
         List<Float> playedAmplitudes = fakeVibrator.getAmplitudes();
@@ -288,7 +293,9 @@
         VibrationStepConductor conductor = startThreadAndDispatcher(vibrationId, effect);
 
         assertTrue(waitUntil(() -> !fakeVibrator.getAmplitudes().isEmpty(), TEST_TIMEOUT_MILLIS));
-        conductor.notifyCancelled(Vibration.Status.CANCELLED_BY_USER, /* immediate= */ false);
+        conductor.notifyCancelled(
+                new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_USER),
+                /* immediate= */ false);
         waitForCompletion();
 
         verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_BY_USER);
@@ -319,7 +326,9 @@
 
         assertTrue(waitUntil(() -> !fakeVibrator.getEffectSegments(vibrationId).isEmpty(),
                 TEST_TIMEOUT_MILLIS));
-        conductor.notifyCancelled(Vibration.Status.CANCELLED_BY_USER, /* immediate= */ false);
+        conductor.notifyCancelled(
+                new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_USER),
+                /* immediate= */ false);
         waitForCompletion();
 
         // PWLE size max was used to generate a single vibrate call with 10 segments.
@@ -348,11 +357,13 @@
 
         assertTrue(waitUntil(() -> !fakeVibrator.getEffectSegments(vibrationId).isEmpty(),
                 TEST_TIMEOUT_MILLIS));
-        conductor.notifyCancelled(Vibration.Status.CANCELLED_SUPERSEDED, /* immediate= */ false);
+        conductor.notifyCancelled(
+                new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_SCREEN_OFF),
+                /* immediate= */ false);
         waitForCompletion();
 
         // Composition size max was used to generate a single vibrate call with 10 primitives.
-        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_SUPERSEDED);
+        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_BY_SCREEN_OFF);
         assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
         assertEquals(10, fakeVibrator.getEffectSegments(vibrationId).size());
     }
@@ -370,7 +381,9 @@
         VibrationStepConductor conductor = startThreadAndDispatcher(vibrationId, effect);
 
         assertTrue(waitUntil(() -> !fakeVibrator.getAmplitudes().isEmpty(), TEST_TIMEOUT_MILLIS));
-        conductor.notifyCancelled(Vibration.Status.CANCELLED_BY_USER, /* immediate= */ false);
+        conductor.notifyCancelled(
+                new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_USER),
+                /* immediate= */ false);
         waitForCompletion();
 
         verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_BY_USER);
@@ -394,7 +407,9 @@
 
         assertTrue(waitUntil(() -> fakeVibrator.getEffectSegments(vibrationId).size() > 1,
                 5000 + TEST_TIMEOUT_MILLIS));
-        conductor.notifyCancelled(Vibration.Status.CANCELLED_BY_USER, /* immediate= */ false);
+        conductor.notifyCancelled(
+                new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_USER),
+                /* immediate= */ false);
         waitForCompletion();
 
         verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_BY_USER);
@@ -414,6 +429,8 @@
     public void vibrate_singleVibratorPredefinedCancel_cancelsVibrationImmediately()
             throws Exception {
         mVibratorProviders.get(VIBRATOR_ID).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+        mVibratorProviders.get(VIBRATOR_ID).setSupportedPrimitives(
+                VibrationEffect.Composition.PRIMITIVE_CLICK);
 
         long vibrationId = 1;
         VibrationEffect effect = VibrationEffect.startComposition()
@@ -431,7 +448,9 @@
         // fail at waitForCompletion(vibrationThread) if the vibration not cancelled immediately.
         Thread cancellingThread =
                 new Thread(() -> conductor.notifyCancelled(
-                        Vibration.Status.CANCELLED_BY_SETTINGS_UPDATE, /* immediate= */ false));
+                        new Vibration.EndInfo(
+                                Vibration.Status.CANCELLED_BY_SETTINGS_UPDATE),
+                        /* immediate= */ false));
         cancellingThread.start();
 
         waitForCompletion(/* timeout= */ 50);
@@ -458,7 +477,9 @@
         // fail at waitForCompletion(vibrationThread) if the vibration not cancelled immediately.
         Thread cancellingThread =
                 new Thread(() -> conductor.notifyCancelled(
-                        Vibration.Status.CANCELLED_BY_SCREEN_OFF, /* immediate= */ false));
+                        new Vibration.EndInfo(
+                                Vibration.Status.CANCELLED_BY_SCREEN_OFF),
+                        /* immediate= */ false));
         cancellingThread.start();
 
         waitForCompletion(/* timeout= */ 50);
@@ -519,7 +540,7 @@
         startThreadAndDispatcher(vibrationId, effect);
         waitForCompletion();
 
-        verify(mManagerHooks, never()).noteVibratorOn(eq(UID), anyLong());
+        verify(mManagerHooks).noteVibratorOn(eq(UID), eq(0L));
         verify(mManagerHooks, never()).noteVibratorOff(eq(UID));
         verify(mControllerCallbacks, never()).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
         verifyCallbacksTriggered(vibrationId, Vibration.Status.IGNORED_UNSUPPORTED);
@@ -530,6 +551,8 @@
     public void vibrate_singleVibratorComposed_runsVibration() throws Exception {
         FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(VIBRATOR_ID);
         fakeVibrator.setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+        fakeVibrator.setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK,
+                VibrationEffect.Composition.PRIMITIVE_TICK);
 
         long vibrationId = 1;
         VibrationEffect effect = VibrationEffect.startComposition()
@@ -559,7 +582,7 @@
         startThreadAndDispatcher(vibrationId, effect);
         waitForCompletion();
 
-        verify(mManagerHooks, never()).noteVibratorOn(eq(UID), anyLong());
+        verify(mManagerHooks).noteVibratorOn(eq(UID), eq(0L));
         verify(mManagerHooks, never()).noteVibratorOff(eq(UID));
         verify(mControllerCallbacks, never()).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
         verifyCallbacksTriggered(vibrationId, Vibration.Status.IGNORED_UNSUPPORTED);
@@ -570,6 +593,10 @@
     public void vibrate_singleVibratorLargeComposition_splitsVibratorComposeCalls() {
         FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(VIBRATOR_ID);
         fakeVibrator.setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+        fakeVibrator.setSupportedPrimitives(
+                VibrationEffect.Composition.PRIMITIVE_CLICK,
+                VibrationEffect.Composition.PRIMITIVE_TICK,
+                VibrationEffect.Composition.PRIMITIVE_SPIN);
         fakeVibrator.setCompositionSizeMax(2);
 
         long vibrationId = 1;
@@ -809,6 +836,8 @@
         mVibratorProviders.get(2).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
         mVibratorProviders.get(3).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
         mVibratorProviders.get(4).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+        mVibratorProviders.get(4).setSupportedPrimitives(
+                VibrationEffect.Composition.PRIMITIVE_CLICK);
 
         long vibrationId = 1;
         VibrationEffect composed = VibrationEffect.startComposition()
@@ -854,6 +883,8 @@
         mockVibrators(1, 2, 3);
         mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
         mVibratorProviders.get(2).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+        mVibratorProviders.get(2).setSupportedPrimitives(
+                VibrationEffect.Composition.PRIMITIVE_CLICK);
         mVibratorProviders.get(3).setSupportedEffects(VibrationEffect.EFFECT_CLICK);
 
         long vibrationId = 1;
@@ -902,7 +933,11 @@
         long vibrationId = 1;
         mockVibrators(vibratorIds);
         mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+        mVibratorProviders.get(1).setSupportedPrimitives(
+                VibrationEffect.Composition.PRIMITIVE_CLICK);
         mVibratorProviders.get(2).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+        mVibratorProviders.get(2).setSupportedPrimitives(
+                VibrationEffect.Composition.PRIMITIVE_CLICK);
         when(mManagerHooks.prepareSyncedVibration(anyLong(), eq(vibratorIds))).thenReturn(true);
         when(mManagerHooks.triggerSyncedVibration(eq(vibrationId))).thenReturn(true);
 
@@ -939,6 +974,8 @@
         mockVibrators(vibratorIds);
         mVibratorProviders.get(1).setSupportedEffects(VibrationEffect.EFFECT_CLICK);
         mVibratorProviders.get(4).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+        mVibratorProviders.get(4).setSupportedPrimitives(
+                VibrationEffect.Composition.PRIMITIVE_CLICK);
         when(mManagerHooks.prepareSyncedVibration(anyLong(), any())).thenReturn(true);
         when(mManagerHooks.triggerSyncedVibration(anyLong())).thenReturn(true);
 
@@ -1125,7 +1162,9 @@
         // fail at waitForCompletion(cancellingThread).
         Thread cancellingThread = new Thread(
                 () -> conductor.notifyCancelled(
-                        Vibration.Status.CANCELLED_BY_USER, /* immediate= */ false));
+                        new Vibration.EndInfo(
+                                Vibration.Status.CANCELLED_BY_USER),
+                        /* immediate= */ false));
         cancellingThread.start();
 
         // Cancelling the vibration should be fast and return right away, even if the thread is
@@ -1143,6 +1182,8 @@
         mockVibrators(1, 2);
         mVibratorProviders.get(1).setSupportedEffects(VibrationEffect.EFFECT_CLICK);
         mVibratorProviders.get(2).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+        mVibratorProviders.get(2).setSupportedPrimitives(
+                VibrationEffect.Composition.PRIMITIVE_CLICK);
 
         long vibrationId = 1;
         CombinedVibration effect = CombinedVibration.startParallel()
@@ -1163,13 +1204,15 @@
         // fail at waitForCompletion(vibrationThread) if the vibration not cancelled immediately.
         Thread cancellingThread = new Thread(
                 () -> conductor.notifyCancelled(
-                        Vibration.Status.CANCELLED_SUPERSEDED, /* immediate= */ false));
+                        new Vibration.EndInfo(
+                                Vibration.Status.CANCELLED_BY_SCREEN_OFF),
+                        /* immediate= */ false));
         cancellingThread.start();
 
         waitForCompletion(/* timeout= */ 50);
         cancellingThread.join();
 
-        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_SUPERSEDED);
+        verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_BY_SCREEN_OFF);
         assertFalse(mControllers.get(1).isVibrating());
         assertFalse(mControllers.get(2).isVibrating());
     }
@@ -1195,9 +1238,11 @@
 
         // Run cancel in a separate thread so if VibrationThread.cancel blocks then this test should
         // fail at waitForCompletion(vibrationThread) if the vibration not cancelled immediately.
-        Thread cancellingThread =
-                new Thread(() -> conductor.notifyCancelled(
-                        Vibration.Status.CANCELLED_BY_SCREEN_OFF, /* immediate= */ false));
+        Thread cancellingThread = new Thread(
+                () -> conductor.notifyCancelled(
+                        new Vibration.EndInfo(
+                                Vibration.Status.CANCELLED_BY_SCREEN_OFF),
+                        /* immediate= */ false));
         cancellingThread.start();
 
         waitForCompletion(/* timeout= */ 50);
@@ -1266,7 +1311,7 @@
 
         // Vibration completed but vibrator not yet released.
         verify(mManagerHooks, timeout(TEST_TIMEOUT_MILLIS)).onVibrationCompleted(eq(vibrationId),
-                eq(Vibration.Status.FINISHED));
+                eq(new Vibration.EndInfo(Vibration.Status.FINISHED)));
         verify(mManagerHooks, never()).onVibrationThreadReleased(anyLong());
 
         // Thread still running ramp down.
@@ -1278,12 +1323,13 @@
 
         // Will stop the ramp down right away.
         conductor.notifyCancelled(
-                Vibration.Status.CANCELLED_BY_SETTINGS_UPDATE, /* immediate= */ true);
+                new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_SETTINGS_UPDATE),
+                /* immediate= */ true);
         waitForCompletion();
 
         // Does not cancel already finished vibration, but releases vibrator.
         verify(mManagerHooks, never()).onVibrationCompleted(eq(vibrationId),
-                eq(Vibration.Status.CANCELLED_BY_SETTINGS_UPDATE));
+                eq(new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_SETTINGS_UPDATE)));
         verify(mManagerHooks).onVibrationThreadReleased(vibrationId);
     }
 
@@ -1299,7 +1345,9 @@
         VibrationStepConductor conductor = startThreadAndDispatcher(vibrationId, effect);
         assertTrue(waitUntil(() -> mControllers.get(VIBRATOR_ID).isVibrating(),
                 TEST_TIMEOUT_MILLIS));
-        conductor.notifyCancelled(Vibration.Status.CANCELLED_BY_USER, /* immediate= */ false);
+        conductor.notifyCancelled(
+                new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_USER),
+                /* immediate= */ false);
         waitForCompletion();
 
         verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_BY_USER);
@@ -1422,7 +1470,9 @@
         VibrationStepConductor conductor2 = startThreadAndDispatcher(vibrationId2, effect2);
         // Effect2 won't complete on its own. Cancel it after a couple of repeats.
         Thread.sleep(150);  // More than two TICKs.
-        conductor2.notifyCancelled(Vibration.Status.CANCELLED_BY_USER, /* immediate= */ false);
+        conductor2.notifyCancelled(
+                new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_USER),
+                /* immediate= */ false);
         waitForCompletion();
 
         startThreadAndDispatcher(vibrationId3, effect3);
@@ -1431,7 +1481,9 @@
         // Effect4 is a long oneshot, but it gets cancelled as fast as possible.
         long start4 = System.currentTimeMillis();
         VibrationStepConductor conductor4 = startThreadAndDispatcher(vibrationId4, effect4);
-        conductor4.notifyCancelled(Vibration.Status.CANCELLED_SUPERSEDED, /* immediate= */ true);
+        conductor4.notifyCancelled(
+                new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_SCREEN_OFF),
+                /* immediate= */ true);
         waitForCompletion();
         long duration4 = System.currentTimeMillis() - start4;
 
@@ -1469,7 +1521,7 @@
                 fakeVibrator.getEffectSegments(vibrationId3));
 
         // Effect4: cancelled quickly.
-        verifyCallbacksTriggered(vibrationId4, Vibration.Status.CANCELLED_SUPERSEDED);
+        verifyCallbacksTriggered(vibrationId4, Vibration.Status.CANCELLED_BY_SCREEN_OFF);
         assertTrue("Tested duration=" + duration4, duration4 < 2000);
 
         // Effect5: normal oneshot. Don't worry about amplitude, as effect4 may or may not have
@@ -1580,7 +1632,11 @@
     }
 
     private void verifyCallbacksTriggered(long vibrationId, Vibration.Status expectedStatus) {
-        verify(mManagerHooks).onVibrationCompleted(eq(vibrationId), eq(expectedStatus));
+        verifyCallbacksTriggered(vibrationId, new Vibration.EndInfo(expectedStatus));
+    }
+
+    private void verifyCallbacksTriggered(long vibrationId, Vibration.EndInfo expectedEndInfo) {
+        verify(mManagerHooks).onVibrationCompleted(eq(vibrationId), eq(expectedEndInfo));
         verify(mManagerHooks).onVibrationThreadReleased(vibrationId);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibratorFrameworkStatsLoggerTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorFrameworkStatsLoggerTest.java
new file mode 100644
index 0000000..c1ab1db
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorFrameworkStatsLoggerTest.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vibrator;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Handler;
+import android.os.test.TestLooper;
+import android.platform.test.annotations.Presubmit;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+/**
+ * Tests for {@link VibratorFrameworkStatsLogger}.
+ *
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:VibratorFrameworkStatsLoggerTest
+ */
+@Presubmit
+public class VibratorFrameworkStatsLoggerTest {
+
+    @Rule public MockitoRule rule = MockitoJUnit.rule();
+
+    private TestLooper mTestLooper;
+    private VibratorFrameworkStatsLogger mLogger;
+
+    @Before
+    public void setUp() {
+        mTestLooper = new TestLooper();
+    }
+
+    @Test
+    public void writeVibrationReportedAsync_afterMinInterval_writesRightAway() {
+        setUpLogger(/* minIntervalMillis= */ 10, /* queueMaxSize= */ 10);
+
+        VibrationStats.StatsInfo firstStats = newEmptyStatsInfo();
+        assertFalse(firstStats.isWritten());
+
+        mLogger.writeVibrationReportedAsync(firstStats);
+        mTestLooper.dispatchAll();
+        assertTrue(firstStats.isWritten());
+    }
+
+    @Test
+    public void writeVibrationReportedAsync_rightAfterLogging_schedulesToRunAfterRemainingDelay() {
+        setUpLogger(/* minIntervalMillis= */ 100, /* queueMaxSize= */ 10);
+
+        VibrationStats.StatsInfo firstStats = newEmptyStatsInfo();
+        VibrationStats.StatsInfo secondStats = newEmptyStatsInfo();
+        assertFalse(firstStats.isWritten());
+        assertFalse(secondStats.isWritten());
+
+        // Write first message at current SystemClock.uptimeMillis
+        mLogger.writeVibrationReportedAsync(firstStats);
+        mTestLooper.dispatchAll();
+        assertTrue(firstStats.isWritten());
+
+        // Second message is not written right away, it needs to wait the configured interval.
+        mLogger.writeVibrationReportedAsync(secondStats);
+        mTestLooper.dispatchAll();
+        assertFalse(secondStats.isWritten());
+
+        // Second message is written after delay passes.
+        mTestLooper.moveTimeForward(100);
+        mTestLooper.dispatchAll();
+        assertTrue(secondStats.isWritten());
+    }
+
+    @Test
+    public void writeVibrationReportedAsync_tooFast_logsUsingIntervalAndDropsMessagesFromQueue() {
+        setUpLogger(/* minIntervalMillis= */ 100, /* queueMaxSize= */ 2);
+
+        VibrationStats.StatsInfo firstStats = newEmptyStatsInfo();
+        VibrationStats.StatsInfo secondStats = newEmptyStatsInfo();
+        VibrationStats.StatsInfo thirdStats = newEmptyStatsInfo();
+
+        mLogger.writeVibrationReportedAsync(firstStats);
+        mLogger.writeVibrationReportedAsync(secondStats);
+        mLogger.writeVibrationReportedAsync(thirdStats);
+
+        // Only first message is logged.
+        mTestLooper.dispatchAll();
+        assertTrue(firstStats.isWritten());
+        assertFalse(secondStats.isWritten());
+        assertFalse(thirdStats.isWritten());
+
+        // Wait one interval to check only the second one is logged.
+        mTestLooper.moveTimeForward(100);
+        mTestLooper.dispatchAll();
+        assertTrue(secondStats.isWritten());
+        assertFalse(thirdStats.isWritten());
+
+        // Wait a long interval to check the third one was dropped and will never be logged.
+        mTestLooper.moveTimeForward(1_000);
+        mTestLooper.dispatchAll();
+        assertFalse(thirdStats.isWritten());
+    }
+
+    private void setUpLogger(int minIntervalMillis, int queueMaxSize) {
+        mLogger = new VibratorFrameworkStatsLogger(new Handler(mTestLooper.getLooper()),
+                minIntervalMillis, queueMaxSize);
+    }
+
+    private static VibrationStats.StatsInfo newEmptyStatsInfo() {
+        return new VibrationStats.StatsInfo(
+                0, 0, 0, Vibration.Status.FINISHED, new VibrationStats(), 0L);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
index 8a96feb..36bec75 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -34,6 +34,7 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -75,11 +76,13 @@
 import android.os.vibrator.VibrationEffectSegment;
 import android.platform.test.annotations.Presubmit;
 import android.provider.Settings;
+import android.util.SparseBooleanArray;
 import android.view.InputDevice;
 
 import androidx.test.InstrumentationRegistry;
 
 import com.android.internal.app.IBatteryStats;
+import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.test.FakeSettingsProvider;
 import com.android.internal.util.test.FakeSettingsProviderRule;
 import com.android.server.LocalServices;
@@ -148,6 +151,8 @@
     private IInputManager mIInputManagerMock;
     @Mock
     private IBatteryStats mBatteryStatsMock;
+    @Mock
+    private VibratorFrameworkStatsLogger mVibratorFrameworkStatsLoggerMock;
 
     private final Map<Integer, FakeVibratorControllerProvider> mVibratorProviders = new HashMap<>();
 
@@ -233,6 +238,11 @@
                     }
 
                     @Override
+                    VibratorFrameworkStatsLogger getFrameworkStatsLogger(Handler handler) {
+                        return mVibratorFrameworkStatsLoggerMock;
+                    }
+
+                    @Override
                     VibratorController createVibratorController(int vibratorId,
                             VibratorController.OnVibrationCompleteListener listener) {
                         return mVibratorProviders.get(vibratorId)
@@ -806,11 +816,11 @@
                 service, TEST_TIMEOUT_MILLIS));
 
         VibrationEffect repeatingEffect = VibrationEffect.createWaveform(
-                new long[]{10_000, 10_000}, new int[]{128, 255}, 1);
+                new long[]{10, 10}, new int[]{128, 255}, 1);
         vibrate(service, repeatingEffect, NOTIFICATION_ATTRS);
 
         // VibrationThread will start this vibration async, so wait before checking it started.
-        assertTrue(waitUntil(s -> mVibratorProviders.get(1).getAllEffectSegments().size() > 1,
+        assertTrue(waitUntil(s -> mVibratorProviders.get(1).getAllEffectSegments().size() > 2,
                 service, TEST_TIMEOUT_MILLIS));
 
         // The second vibration should have recorded that the vibrators were turned on.
@@ -916,7 +926,11 @@
         mockCapabilities(IVibratorManager.CAP_SYNC, IVibratorManager.CAP_PREPARE_COMPOSE);
         mockVibrators(1, 2);
         mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+        mVibratorProviders.get(1).setSupportedPrimitives(
+                VibrationEffect.Composition.PRIMITIVE_CLICK);
         mVibratorProviders.get(2).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+        mVibratorProviders.get(2).setSupportedPrimitives(
+                VibrationEffect.Composition.PRIMITIVE_CLICK);
         // Mock alarm intensity equals to default value to avoid scaling in this test.
         setUserSetting(Settings.System.ALARM_VIBRATION_INTENSITY,
                 mVibrator.getDefaultVibrationIntensity(VibrationAttributes.USAGE_ALARM));
@@ -1078,6 +1092,8 @@
         FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1);
         fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL,
                 IVibrator.CAP_COMPOSE_EFFECTS);
+        fakeVibrator.setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK,
+                VibrationEffect.Composition.PRIMITIVE_TICK);
         VibratorManagerService service = createSystemReadyService();
 
         vibrate(service, VibrationEffect.startComposition()
@@ -1380,6 +1396,373 @@
         assertEquals(IExternalVibratorService.SCALE_MUTE, scale);
     }
 
+    @Test
+    public void frameworkStats_externalVibration_reportsAllMetrics() throws Exception {
+        mockVibrators(1);
+        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL);
+        createSystemReadyService();
+
+        AudioAttributes audioAttrs = new AudioAttributes.Builder()
+                .setUsage(AudioAttributes.USAGE_ALARM)
+                .build();
+
+        ExternalVibration vib = new ExternalVibration(UID, PACKAGE_NAME, audioAttrs,
+                mock(IExternalVibrationController.class));
+        mExternalVibratorService.onExternalVibrationStart(vib);
+
+        Thread.sleep(10);
+        mExternalVibratorService.onExternalVibrationStop(vib);
+
+        ArgumentCaptor<VibrationStats.StatsInfo> argumentCaptor =
+                ArgumentCaptor.forClass(VibrationStats.StatsInfo.class);
+        verify(mVibratorFrameworkStatsLoggerMock, timeout(TEST_TIMEOUT_MILLIS))
+                .writeVibrationReportedAsync(argumentCaptor.capture());
+
+        VibrationStats.StatsInfo statsInfo = argumentCaptor.getValue();
+        assertEquals(UID, statsInfo.uid);
+        assertEquals(FrameworkStatsLog.VIBRATION_REPORTED__VIBRATION_TYPE__EXTERNAL,
+                statsInfo.vibrationType);
+        assertEquals(VibrationAttributes.USAGE_ALARM, statsInfo.usage);
+        assertEquals(Vibration.Status.FINISHED.getProtoEnumValue(), statsInfo.status);
+        assertTrue(statsInfo.totalDurationMillis > 0);
+        assertTrue(
+                "Expected vibrator ON for at least 10ms, got " + statsInfo.vibratorOnMillis + "ms",
+                statsInfo.vibratorOnMillis >= 10);
+        assertEquals(2, statsInfo.halSetExternalControlCount);
+    }
+
+    @Test
+    public void frameworkStats_waveformVibration_reportsAllMetrics() throws Exception {
+        mockVibrators(1);
+        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+
+        VibratorManagerService service = createSystemReadyService();
+        vibrateAndWaitUntilFinished(service,
+                VibrationEffect.createWaveform(new long[] {0, 10, 20, 10}, -1), RINGTONE_ATTRS);
+
+        verify(mVibratorFrameworkStatsLoggerMock, timeout(TEST_TIMEOUT_MILLIS))
+                .writeVibratorStateOnAsync(eq(UID), anyLong());
+        verify(mVibratorFrameworkStatsLoggerMock, timeout(TEST_TIMEOUT_MILLIS))
+                .writeVibratorStateOffAsync(eq(UID));
+
+        ArgumentCaptor<VibrationStats.StatsInfo> argumentCaptor =
+                ArgumentCaptor.forClass(VibrationStats.StatsInfo.class);
+        verify(mVibratorFrameworkStatsLoggerMock, timeout(TEST_TIMEOUT_MILLIS))
+                .writeVibrationReportedAsync(argumentCaptor.capture());
+
+        VibrationStats.StatsInfo metrics = argumentCaptor.getValue();
+        assertEquals(UID, metrics.uid);
+        assertEquals(FrameworkStatsLog.VIBRATION_REPORTED__VIBRATION_TYPE__SINGLE,
+                metrics.vibrationType);
+        assertEquals(VibrationAttributes.USAGE_RINGTONE, metrics.usage);
+        assertEquals(Vibration.Status.FINISHED.getProtoEnumValue(), metrics.status);
+        assertTrue("Total duration was too low, " + metrics.totalDurationMillis + "ms",
+                metrics.totalDurationMillis >= 20);
+        assertTrue("Vibrator ON duration was too low, " + metrics.vibratorOnMillis + "ms",
+                metrics.vibratorOnMillis >= 20);
+
+        // All unrelated metrics are empty.
+        assertEquals(0, metrics.repeatCount);
+        assertEquals(0, metrics.halComposeCount);
+        assertEquals(0, metrics.halComposePwleCount);
+        assertEquals(0, metrics.halPerformCount);
+        assertEquals(0, metrics.halSetExternalControlCount);
+        assertEquals(0, metrics.halCompositionSize);
+        assertEquals(0, metrics.halPwleSize);
+        assertNull(metrics.halSupportedCompositionPrimitivesUsed);
+        assertNull(metrics.halSupportedEffectsUsed);
+        assertNull(metrics.halUnsupportedCompositionPrimitivesUsed);
+        assertNull(metrics.halUnsupportedEffectsUsed);
+
+        // Accommodate for ramping off config that might add extra setAmplitudes.
+        assertEquals(2, metrics.halOnCount);
+        assertTrue(metrics.halOffCount > 0);
+        assertTrue(metrics.halSetAmplitudeCount >= 2);
+    }
+
+    @Test
+    public void frameworkStats_repeatingVibration_reportsAllMetrics() throws Exception {
+        mockVibrators(1);
+        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+
+        VibratorManagerService service = createSystemReadyService();
+        vibrate(service, VibrationEffect.createWaveform(new long[] {10, 100}, 1), RINGTONE_ATTRS);
+
+        verify(mVibratorFrameworkStatsLoggerMock, timeout(TEST_TIMEOUT_MILLIS))
+                .writeVibratorStateOnAsync(eq(UID), anyLong());
+
+        // Wait for at least one loop before cancelling it.
+        Thread.sleep(100);
+        service.cancelVibrate(VibrationAttributes.USAGE_RINGTONE, service);
+
+        verify(mVibratorFrameworkStatsLoggerMock, timeout(TEST_TIMEOUT_MILLIS))
+                .writeVibratorStateOffAsync(eq(UID));
+
+        ArgumentCaptor<VibrationStats.StatsInfo> argumentCaptor =
+                ArgumentCaptor.forClass(VibrationStats.StatsInfo.class);
+        verify(mVibratorFrameworkStatsLoggerMock, timeout(TEST_TIMEOUT_MILLIS))
+                .writeVibrationReportedAsync(argumentCaptor.capture());
+
+        VibrationStats.StatsInfo metrics = argumentCaptor.getValue();
+        assertEquals(UID, metrics.uid);
+        assertEquals(FrameworkStatsLog.VIBRATION_REPORTED__VIBRATION_TYPE__REPEATED,
+                metrics.vibrationType);
+        assertEquals(VibrationAttributes.USAGE_RINGTONE, metrics.usage);
+        assertEquals(Vibration.Status.CANCELLED_BY_USER.getProtoEnumValue(), metrics.status);
+        assertTrue("Total duration was too low, " + metrics.totalDurationMillis + "ms",
+                metrics.totalDurationMillis >= 100);
+        assertTrue("Vibrator ON duration was too low, " + metrics.vibratorOnMillis + "ms",
+                metrics.vibratorOnMillis >= 100);
+
+        // All unrelated metrics are empty.
+        assertTrue(metrics.repeatCount > 0);
+        assertEquals(0, metrics.halComposeCount);
+        assertEquals(0, metrics.halComposePwleCount);
+        assertEquals(0, metrics.halPerformCount);
+        assertEquals(0, metrics.halSetExternalControlCount);
+        assertEquals(0, metrics.halCompositionSize);
+        assertEquals(0, metrics.halPwleSize);
+        assertNull(metrics.halSupportedCompositionPrimitivesUsed);
+        assertNull(metrics.halSupportedEffectsUsed);
+        assertNull(metrics.halUnsupportedCompositionPrimitivesUsed);
+        assertNull(metrics.halUnsupportedEffectsUsed);
+
+        // Accommodate for ramping off config that might add extra setAmplitudes.
+        assertTrue(metrics.halOnCount > 0);
+        assertTrue(metrics.halOffCount > 0);
+        assertTrue(metrics.halSetAmplitudeCount > 0);
+    }
+
+    @Test
+    public void frameworkStats_prebakedAndComposedVibrations_reportsAllMetrics() throws Exception {
+        mockVibrators(1);
+        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+        mVibratorProviders.get(1).setSupportedEffects(VibrationEffect.EFFECT_CLICK);
+        mVibratorProviders.get(1).setSupportedPrimitives(
+                VibrationEffect.Composition.PRIMITIVE_TICK);
+
+        VibratorManagerService service = createSystemReadyService();
+        vibrateAndWaitUntilFinished(service,
+                VibrationEffect.startComposition()
+                        .addEffect(VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK))
+                        .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK)
+                        .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK)
+                        .addEffect(VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK))
+                        .addEffect(VibrationEffect.createPredefined(VibrationEffect.EFFECT_TICK))
+                        .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK)
+                        .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK)
+                        .compose(),
+                ALARM_ATTRS);
+
+        verify(mVibratorFrameworkStatsLoggerMock, timeout(TEST_TIMEOUT_MILLIS))
+                .writeVibratorStateOnAsync(eq(UID), anyLong());
+        verify(mVibratorFrameworkStatsLoggerMock, timeout(TEST_TIMEOUT_MILLIS))
+                .writeVibratorStateOffAsync(eq(UID));
+
+        ArgumentCaptor<VibrationStats.StatsInfo> argumentCaptor =
+                ArgumentCaptor.forClass(VibrationStats.StatsInfo.class);
+        verify(mVibratorFrameworkStatsLoggerMock, timeout(TEST_TIMEOUT_MILLIS))
+                .writeVibrationReportedAsync(argumentCaptor.capture());
+
+        VibrationStats.StatsInfo metrics = argumentCaptor.getValue();
+        assertEquals(UID, metrics.uid);
+        assertEquals(FrameworkStatsLog.VIBRATION_REPORTED__VIBRATION_TYPE__SINGLE,
+                metrics.vibrationType);
+        assertEquals(VibrationAttributes.USAGE_ALARM, metrics.usage);
+        assertEquals(Vibration.Status.FINISHED.getProtoEnumValue(), metrics.status);
+
+        // At least 4 effect/primitive played, 20ms each, plus configured fallback.
+        assertTrue("Total duration was too low, " + metrics.totalDurationMillis + "ms",
+                metrics.totalDurationMillis >= 80);
+        assertTrue("Vibrator ON duration was too low, " + metrics.vibratorOnMillis + "ms",
+                metrics.vibratorOnMillis >= 80);
+
+        // Related metrics were collected.
+        assertEquals(2, metrics.halComposeCount); // TICK+TICK, then CLICK+CLICK
+        assertEquals(3, metrics.halPerformCount); // CLICK, TICK, then CLICK
+        assertEquals(4, metrics.halCompositionSize); // 2*TICK + 2*CLICK
+        // No repetitions in reported effect/primitive IDs.
+        assertArrayEquals(new int[] {VibrationEffect.Composition.PRIMITIVE_TICK},
+                metrics.halSupportedCompositionPrimitivesUsed);
+        assertArrayEquals(new int[] {VibrationEffect.Composition.PRIMITIVE_CLICK},
+                metrics.halUnsupportedCompositionPrimitivesUsed);
+        assertArrayEquals(new int[] {VibrationEffect.EFFECT_CLICK},
+                metrics.halSupportedEffectsUsed);
+        assertArrayEquals(new int[] {VibrationEffect.EFFECT_TICK},
+                metrics.halUnsupportedEffectsUsed);
+
+        // All unrelated metrics are empty.
+        assertEquals(0, metrics.repeatCount);
+        assertEquals(0, metrics.halComposePwleCount);
+        assertEquals(0, metrics.halSetExternalControlCount);
+        assertEquals(0, metrics.halPwleSize);
+
+        // Accommodate for ramping off config that might add extra setAmplitudes
+        // for the effect that plays the fallback instead of "perform".
+        assertTrue(metrics.halOnCount > 0);
+        assertTrue(metrics.halOffCount > 0);
+        assertTrue(metrics.halSetAmplitudeCount > 0);
+    }
+
+    @Test
+    public void frameworkStats_interruptingVibrations_reportsAllMetrics() throws Exception {
+        mockVibrators(1);
+        VibratorManagerService service = createSystemReadyService();
+
+        vibrate(service, VibrationEffect.createOneShot(1_000, 128), HAPTIC_FEEDBACK_ATTRS);
+
+        // VibrationThread will start this vibration async, so wait until vibration is triggered.
+        assertTrue(waitUntil(s -> !mVibratorProviders.get(1).getAllEffectSegments().isEmpty(),
+                service, TEST_TIMEOUT_MILLIS));
+
+        vibrateAndWaitUntilFinished(service, VibrationEffect.createOneShot(10, 255), ALARM_ATTRS);
+
+        ArgumentCaptor<VibrationStats.StatsInfo> argumentCaptor =
+                ArgumentCaptor.forClass(VibrationStats.StatsInfo.class);
+        verify(mVibratorFrameworkStatsLoggerMock, timeout(TEST_TIMEOUT_MILLIS).times(2))
+                .writeVibrationReportedAsync(argumentCaptor.capture());
+
+        VibrationStats.StatsInfo touchMetrics = argumentCaptor.getAllValues().get(0);
+        assertEquals(UID, touchMetrics.uid);
+        assertEquals(VibrationAttributes.USAGE_TOUCH, touchMetrics.usage);
+        assertEquals(Vibration.Status.CANCELLED_SUPERSEDED.getProtoEnumValue(),
+                touchMetrics.status);
+        assertTrue(touchMetrics.endedBySameUid);
+        assertEquals(VibrationAttributes.USAGE_ALARM, touchMetrics.endedByUsage);
+        assertEquals(-1, touchMetrics.interruptedUsage);
+
+        VibrationStats.StatsInfo alarmMetrics = argumentCaptor.getAllValues().get(1);
+        assertEquals(UID, alarmMetrics.uid);
+        assertEquals(VibrationAttributes.USAGE_ALARM, alarmMetrics.usage);
+        assertEquals(Vibration.Status.FINISHED.getProtoEnumValue(), alarmMetrics.status);
+        assertFalse(alarmMetrics.endedBySameUid);
+        assertEquals(-1, alarmMetrics.endedByUsage);
+        assertEquals(VibrationAttributes.USAGE_TOUCH, alarmMetrics.interruptedUsage);
+    }
+
+    @Test
+    public void frameworkStats_ignoredVibration_reportsStatus() throws Exception {
+        setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
+                Vibrator.VIBRATION_INTENSITY_OFF);
+
+        mockVibrators(1);
+        VibratorManagerService service = createSystemReadyService();
+        mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE);
+
+        // Haptic feedback ignored in low power state
+        vibrateAndWaitUntilFinished(service, VibrationEffect.createOneShot(100, 128),
+                HAPTIC_FEEDBACK_ATTRS);
+        // Ringtone vibration user settings are off
+        vibrateAndWaitUntilFinished(service, VibrationEffect.createOneShot(200, 128),
+                RINGTONE_ATTRS);
+
+        ArgumentCaptor<VibrationStats.StatsInfo> argumentCaptor =
+                ArgumentCaptor.forClass(VibrationStats.StatsInfo.class);
+        verify(mVibratorFrameworkStatsLoggerMock, timeout(TEST_TIMEOUT_MILLIS).times(2))
+                .writeVibrationReportedAsync(argumentCaptor.capture());
+
+        VibrationStats.StatsInfo touchMetrics = argumentCaptor.getAllValues().get(0);
+        assertEquals(UID, touchMetrics.uid);
+        assertEquals(VibrationAttributes.USAGE_TOUCH, touchMetrics.usage);
+        assertEquals(Vibration.Status.IGNORED_FOR_POWER.getProtoEnumValue(), touchMetrics.status);
+
+        VibrationStats.StatsInfo ringtoneMetrics = argumentCaptor.getAllValues().get(1);
+        assertEquals(UID, ringtoneMetrics.uid);
+        assertEquals(VibrationAttributes.USAGE_RINGTONE, ringtoneMetrics.usage);
+        assertEquals(Vibration.Status.IGNORED_FOR_SETTINGS.getProtoEnumValue(),
+                ringtoneMetrics.status);
+
+        for (VibrationStats.StatsInfo metrics : argumentCaptor.getAllValues()) {
+            // Latencies are empty since vibrations never started
+            assertEquals(0, metrics.startLatencyMillis);
+            assertEquals(0, metrics.endLatencyMillis);
+            assertEquals(0, metrics.vibratorOnMillis);
+
+            // All unrelated metrics are empty.
+            assertEquals(0, metrics.repeatCount);
+            assertEquals(0, metrics.halComposeCount);
+            assertEquals(0, metrics.halComposePwleCount);
+            assertEquals(0, metrics.halOffCount);
+            assertEquals(0, metrics.halOnCount);
+            assertEquals(0, metrics.halPerformCount);
+            assertEquals(0, metrics.halSetExternalControlCount);
+            assertEquals(0, metrics.halCompositionSize);
+            assertEquals(0, metrics.halPwleSize);
+            assertNull(metrics.halSupportedCompositionPrimitivesUsed);
+            assertNull(metrics.halSupportedEffectsUsed);
+            assertNull(metrics.halUnsupportedCompositionPrimitivesUsed);
+            assertNull(metrics.halUnsupportedEffectsUsed);
+        }
+    }
+
+    @Test
+    public void frameworkStats_multiVibrators_reportsAllMetrics() throws Exception {
+        mockVibrators(1, 2);
+        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+        mVibratorProviders.get(1).setSupportedPrimitives(
+                VibrationEffect.Composition.PRIMITIVE_TICK);
+        mVibratorProviders.get(2).setSupportedEffects(VibrationEffect.EFFECT_TICK);
+
+        VibratorManagerService service = createSystemReadyService();
+        vibrateAndWaitUntilFinished(service,
+                CombinedVibration.startParallel()
+                        .addVibrator(1,
+                                VibrationEffect.startComposition()
+                                        .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK)
+                                        .compose())
+                        .addVibrator(2,
+                                VibrationEffect.createPredefined(VibrationEffect.EFFECT_TICK))
+                        .combine(),
+                NOTIFICATION_ATTRS);
+
+        SparseBooleanArray expectedEffectsUsed = new SparseBooleanArray();
+        expectedEffectsUsed.put(VibrationEffect.EFFECT_TICK, true);
+
+        SparseBooleanArray expectedPrimitivesUsed = new SparseBooleanArray();
+        expectedPrimitivesUsed.put(VibrationEffect.Composition.PRIMITIVE_TICK, true);
+
+        verify(mVibratorFrameworkStatsLoggerMock, timeout(TEST_TIMEOUT_MILLIS))
+                .writeVibratorStateOnAsync(eq(UID), anyLong());
+        verify(mVibratorFrameworkStatsLoggerMock, timeout(TEST_TIMEOUT_MILLIS))
+                .writeVibratorStateOffAsync(eq(UID));
+
+        ArgumentCaptor<VibrationStats.StatsInfo> argumentCaptor =
+                ArgumentCaptor.forClass(VibrationStats.StatsInfo.class);
+        verify(mVibratorFrameworkStatsLoggerMock, timeout(TEST_TIMEOUT_MILLIS))
+                .writeVibrationReportedAsync(argumentCaptor.capture());
+
+        VibrationStats.StatsInfo metrics = argumentCaptor.getValue();
+        assertEquals(UID, metrics.uid);
+        assertEquals(FrameworkStatsLog.VIBRATION_REPORTED__VIBRATION_TYPE__SINGLE,
+                metrics.vibrationType);
+        assertEquals(VibrationAttributes.USAGE_NOTIFICATION, metrics.usage);
+        assertEquals(Vibration.Status.FINISHED.getProtoEnumValue(), metrics.status);
+        assertTrue(metrics.totalDurationMillis >= 20);
+
+        // vibratorOnMillis accumulates both vibrators, it's 20 for each constant.
+        assertEquals(40, metrics.vibratorOnMillis);
+
+        // Related metrics were collected.
+        assertEquals(1, metrics.halComposeCount);
+        assertEquals(1, metrics.halPerformCount);
+        assertEquals(1, metrics.halCompositionSize);
+        assertEquals(2, metrics.halOffCount);
+        assertArrayEquals(new int[] {VibrationEffect.Composition.PRIMITIVE_TICK},
+                metrics.halSupportedCompositionPrimitivesUsed);
+        assertArrayEquals(new int[] {VibrationEffect.EFFECT_TICK},
+                metrics.halSupportedEffectsUsed);
+
+        // All unrelated metrics are empty.
+        assertEquals(0, metrics.repeatCount);
+        assertEquals(0, metrics.halComposePwleCount);
+        assertEquals(0, metrics.halOnCount);
+        assertEquals(0, metrics.halSetAmplitudeCount);
+        assertEquals(0, metrics.halSetExternalControlCount);
+        assertEquals(0, metrics.halPwleSize);
+        assertNull(metrics.halUnsupportedCompositionPrimitivesUsed);
+        assertNull(metrics.halUnsupportedEffectsUsed);
+    }
+
     private VibrationEffectSegment expectedPrebaked(int effectId) {
         return expectedPrebaked(effectId, VibrationEffect.EFFECT_STRENGTH_MEDIUM);
     }
@@ -1429,6 +1812,20 @@
                 mContextSpy.getContentResolver(), settingName, value, UserHandle.USER_CURRENT);
     }
 
+    private void vibrateAndWaitUntilFinished(VibratorManagerService service, VibrationEffect effect,
+            VibrationAttributes attrs) throws InterruptedException {
+        vibrateAndWaitUntilFinished(service, CombinedVibration.createParallel(effect), attrs);
+    }
+
+    private void vibrateAndWaitUntilFinished(VibratorManagerService service,
+            CombinedVibration effect, VibrationAttributes attrs) throws InterruptedException {
+        Vibration vib =
+                service.vibrateInternal(UID, PACKAGE_NAME, effect, attrs, "some reason", service);
+        if (vib != null) {
+            vib.waitForEnd();
+        }
+    }
+
     private void vibrate(VibratorManagerService service, VibrationEffect effect,
             VibrationAttributes attrs) {
         vibrate(service, CombinedVibration.createParallel(effect), attrs);
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 7c46fd6..8b350f4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -2314,6 +2314,8 @@
 
         assertEquals(launchCookie, activity2.mLaunchCookie);
         assertNull(activity1.mLaunchCookie);
+        activity2.makeFinishingLocked();
+        assertTrue(activity1.getTask().getTaskInfo().launchCookies.contains(launchCookie));
     }
 
     private void verifyProcessInfoUpdate(ActivityRecord activity, State state,
@@ -2464,6 +2466,7 @@
         activity.addWindow(appWindow);
         spyOn(appWindow);
         doNothing().when(appWindow).onStartFreezingScreen();
+        doNothing().when(mWm).startFreezingDisplay(anyInt(), anyInt(), any(), anyInt());
 
         // Set initial orientation and update.
         performRotation(displayRotation, Surface.ROTATION_90);
@@ -2472,8 +2475,6 @@
         // Update the rotation to perform 180 degree rotation and check that resize was reported.
         performRotation(displayRotation, Surface.ROTATION_270);
         assertTrue(appWindow.mResizeReported);
-
-        appWindow.removeImmediately();
     }
 
     private void performRotation(DisplayRotation spiedRotation, int rotationToReport) {
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 c5117bb..7fbf6bb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
@@ -31,9 +31,11 @@
 import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.never;
 
+import android.content.res.Configuration;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.hardware.display.VirtualDisplay;
@@ -53,6 +55,8 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 import java.util.concurrent.CountDownLatch;
 
@@ -68,17 +72,21 @@
 public class ContentRecorderTests extends WindowTestsBase {
     private static final IBinder TEST_TOKEN = new RecordingTestToken();
     private static IBinder sTaskWindowContainerToken;
+    private Task mTask;
     private final ContentRecordingSession mDisplaySession =
             ContentRecordingSession.createDisplaySession(TEST_TOKEN);
     private ContentRecordingSession mTaskSession;
     private static Point sSurfaceSize;
     private ContentRecorder mContentRecorder;
+    @Mock private ContentRecorder.MediaProjectionManagerWrapper mMediaProjectionManagerWrapper;
     private SurfaceControl mRecordedSurface;
     // Handle feature flag.
     private ConfigListener mConfigListener;
     private CountDownLatch mLatch;
 
     @Before public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
         // GIVEN SurfaceControl can successfully mirror the provided surface.
         sSurfaceSize = new Point(
                 mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().width(),
@@ -92,7 +100,8 @@
         final int displayId = virtualDisplay.getDisplay().getDisplayId();
         mWm.mRoot.onDisplayAdded(displayId);
         final DisplayContent virtualDisplayContent = mWm.mRoot.getDisplayContent(displayId);
-        mContentRecorder = new ContentRecorder(virtualDisplayContent);
+        mContentRecorder = new ContentRecorder(virtualDisplayContent,
+                mMediaProjectionManagerWrapper);
         spyOn(virtualDisplayContent);
 
         // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
@@ -179,7 +188,7 @@
         mContentRecorder.setContentRecordingSession(session);
         mContentRecorder.updateRecording();
         assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
-        // TODO(b/219761722) validate VirtualDisplay is torn down when can't set up task recording.
+        verify(mMediaProjectionManagerWrapper).stopActiveProjection();
     }
 
     @Test
@@ -190,7 +199,7 @@
         mContentRecorder.setContentRecordingSession(invalidTaskSession);
         mContentRecorder.updateRecording();
         assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
-        // TODO(b/219761722) validate VirtualDisplay is torn down when can't set up task recording.
+        verify(mMediaProjectionManagerWrapper).stopActiveProjection();
     }
 
     @Test
@@ -218,9 +227,24 @@
         mContentRecorder.updateRecording();
         mContentRecorder.onConfigurationChanged(ORIENTATION_PORTRAIT);
 
-        verify(mTransaction, atLeastOnce()).setPosition(eq(mRecordedSurface), anyFloat(),
+        verify(mTransaction, atLeast(2)).setPosition(eq(mRecordedSurface), anyFloat(),
                 anyFloat());
-        verify(mTransaction, atLeastOnce()).setMatrix(eq(mRecordedSurface), anyFloat(), anyFloat(),
+        verify(mTransaction, atLeast(2)).setMatrix(eq(mRecordedSurface), anyFloat(), anyFloat(),
+                anyFloat(), anyFloat());
+    }
+
+    @Test
+    public void testOnTaskConfigurationChanged_resizesSurface() {
+        mContentRecorder.setContentRecordingSession(mTaskSession);
+        mContentRecorder.updateRecording();
+
+        Configuration config = mTask.getConfiguration();
+        config.orientation = ORIENTATION_PORTRAIT;
+        mTask.onConfigurationChanged(config);
+
+        verify(mTransaction, atLeast(2)).setPosition(eq(mRecordedSurface), anyFloat(),
+                anyFloat());
+        verify(mTransaction, atLeast(2)).setMatrix(eq(mRecordedSurface), anyFloat(), anyFloat(),
                 anyFloat(), anyFloat());
     }
 
@@ -240,21 +264,31 @@
     }
 
     @Test
-    public void testRemove_stopsRecording() {
+    public void testStopRecording_stopsRecording() {
         mContentRecorder.setContentRecordingSession(mDisplaySession);
         mContentRecorder.updateRecording();
 
-        mContentRecorder.remove();
+        mContentRecorder.stopRecording();
         assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
     }
 
     @Test
-    public void testRemove_neverRecording() {
-        mContentRecorder.remove();
+    public void testStopRecording_neverRecording() {
+        mContentRecorder.stopRecording();
         assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
     }
 
     @Test
+    public void testRemoveTask_stopsRecording() {
+        mContentRecorder.setContentRecordingSession(mTaskSession);
+        mContentRecorder.updateRecording();
+
+        mTask.removeImmediately();
+
+        verify(mMediaProjectionManagerWrapper).stopActiveProjection();
+    }
+
+    @Test
     public void testUpdateMirroredSurface_capturedAreaResized() {
         mContentRecorder.setContentRecordingSession(mDisplaySession);
         mContentRecorder.updateRecording();
@@ -297,10 +331,10 @@
      */
     private IBinder setUpTaskWindowContainerToken(DisplayContent displayContent) {
         final Task rootTask = createTask(displayContent);
-        final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
+        mTask = createTaskInRootTask(rootTask, 0 /* userId */);
         // Ensure the task is not empty.
-        createActivityRecord(displayContent, task);
-        return task.getTaskInfo().token.asBinder();
+        createActivityRecord(displayContent, mTask);
+        return mTask.getTaskInfo().token.asBinder();
     }
 
     /**
diff --git a/services/tests/wmtests/src/com/android/server/wm/ContentRecordingControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/ContentRecordingControllerTests.java
index 7698033d..342d68b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ContentRecordingControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ContentRecordingControllerTests.java
@@ -87,7 +87,7 @@
     @Test
     public void testSetContentRecordingSessionLocked_invalidToken_notAccepted() {
         ContentRecordingController controller = new ContentRecordingController();
-        // GIVEN an invalid display session (null token).
+        // GIVEN a session with a null token.
         ContentRecordingSession session = ContentRecordingSession.createDisplaySession(null);
         session.setDisplayId(DEFAULT_DISPLAY);
         // WHEN updating the session.
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
index d94e6c9..b87c5a3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -399,9 +400,9 @@
                 parentBounds.right / 2, parentBounds.bottom);
         final Rect childBounds2 = new Rect(parentBounds.right / 2, parentBounds.top,
                 parentBounds.right, parentBounds.bottom);
-        TestDisplayArea parentDa = new TestDisplayArea(mWm, parentBounds);
-        TestDisplayArea childDa1 = new TestDisplayArea(mWm, childBounds1);
-        TestDisplayArea childDa2 = new TestDisplayArea(mWm, childBounds2);
+        TestDisplayArea parentDa = new TestDisplayArea(mWm, parentBounds, "Parent");
+        TestDisplayArea childDa1 = new TestDisplayArea(mWm, childBounds1, "Child1");
+        TestDisplayArea childDa2 = new TestDisplayArea(mWm, childBounds2, "Child2");
         parentDa.addChild(childDa1, 0);
         parentDa.addChild(childDa2, 1);
 
@@ -619,9 +620,67 @@
         controller.registerOrganizer(mockDisplayAreaOrganizer, FEATURE_VENDOR_FIRST);
     }
 
+    @Test
+    public void testSetAlwaysOnTop_movesDisplayAreaToTop() {
+        final Rect bounds = new Rect(0, 0, 100, 100);
+        DisplayArea<WindowContainer> parent = new TestDisplayArea(mWm, bounds, "Parent");
+        parent.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+        DisplayArea<WindowContainer> child1 = new TestDisplayArea(mWm, bounds, "Child1");
+        child1.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+        DisplayArea<WindowContainer> child2 = new TestDisplayArea(mWm, bounds, "Child2");
+        child2.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+        parent.addChild(child2, 0);
+        parent.addChild(child1, 1);
+
+        child2.setAlwaysOnTop(true);
+
+        assertEquals(parent.getChildAt(1), child2);
+        assertThat(child2.isAlwaysOnTop()).isTrue();
+    }
+
+    @Test
+    public void testDisplayAreaRequestsTopPosition_alwaysOnTopSiblingExists_doesNotMoveToTop() {
+        final Rect bounds = new Rect(0, 0, 100, 100);
+        DisplayArea<WindowContainer> parent = new TestDisplayArea(mWm, bounds, "Parent");
+        parent.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+        DisplayArea<WindowContainer> alwaysOnTopChild = new TestDisplayArea(mWm, bounds,
+                "AlwaysOnTopChild");
+        alwaysOnTopChild.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+        DisplayArea<WindowContainer> child = new TestDisplayArea(mWm, bounds, "Child");
+        child.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+        parent.addChild(alwaysOnTopChild, 0);
+        parent.addChild(child, 1);
+        alwaysOnTopChild.setAlwaysOnTop(true);
+
+        parent.positionChildAt(POSITION_TOP, child, false /* includingParents */);
+
+        assertEquals(parent.getChildAt(1), alwaysOnTopChild);
+        assertEquals(parent.getChildAt(0), child);
+    }
+
+    @Test
+    public void testAlwaysOnTopDisplayArea_requestsNonTopLocation_doesNotMove() {
+        final Rect bounds = new Rect(0, 0, 100, 100);
+        DisplayArea<WindowContainer> parent = new TestDisplayArea(mWm, bounds, "Parent");
+        parent.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+        DisplayArea<WindowContainer> alwaysOnTopChild = new TestDisplayArea(mWm, bounds,
+                "AlwaysOnTopChild");
+        alwaysOnTopChild.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+        DisplayArea<WindowContainer> child = new TestDisplayArea(mWm, bounds, "Child");
+        child.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+        parent.addChild(alwaysOnTopChild, 0);
+        parent.addChild(child, 1);
+        alwaysOnTopChild.setAlwaysOnTop(true);
+
+        parent.positionChildAt(POSITION_BOTTOM, alwaysOnTopChild, false /* includingParents */);
+
+        assertEquals(parent.getChildAt(1), alwaysOnTopChild);
+        assertEquals(parent.getChildAt(0), child);
+    }
+
     private static class TestDisplayArea<T extends WindowContainer> extends DisplayArea<T> {
-        private TestDisplayArea(WindowManagerService wms, Rect bounds) {
-            super(wms, ANY, "half display area");
+        private TestDisplayArea(WindowManagerService wms, Rect bounds, String name) {
+            super(wms, ANY, name);
             setBounds(bounds);
         }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index d6b807f..600881e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1820,19 +1820,18 @@
 
     @Test
     public void testRemoteRotation() {
-        DisplayContent dc = createNewDisplay();
-
+        final DisplayContent dc = mDisplayContent;
         final DisplayRotation dr = dc.getDisplayRotation();
-        doCallRealMethod().when(dr).updateRotationUnchecked(anyBoolean());
+        spyOn(dr);
         // Rotate 180 degree so the display doesn't have configuration change. This condition is
         // used for the later verification of stop-freezing (without setting mWaitingForConfig).
         doReturn((dr.getRotation() + 2) % 4).when(dr).rotationForOrientation(anyInt(), anyInt());
         final boolean[] continued = new boolean[1];
-        doAnswer(
-                invocation -> {
-                    continued[0] = true;
-                    return true;
-                }).when(dc).updateDisplayOverrideConfigurationLocked();
+        doAnswer(invocation -> {
+            continued[0] = true;
+            mAtm.addWindowLayoutReasons(ActivityTaskManagerService.LAYOUT_REASON_CONFIG_CHANGED);
+            return true;
+        }).when(dc).updateDisplayOverrideConfigurationLocked();
         final boolean[] called = new boolean[1];
         mWm.mDisplayChangeController =
                 new IDisplayChangeWindowController.Stub() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 21839aa..85f85f1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -97,12 +97,12 @@
 import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
 
 import org.junit.After;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TestRule;
 import org.junit.runner.RunWith;
-import org.mockito.Mockito;
 
 /**
  * Tests for Size Compatibility mode.
@@ -663,7 +663,7 @@
         final ActivityRecord activity = new ActivityBuilder(mAtm)
                 .setTask(mTask)
                 .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE)
-                .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
+                .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
                 .build();
         assertFalse(activity.shouldCreateCompatDisplayInsets());
 
@@ -1538,6 +1538,108 @@
     }
 
     @Test
+    @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
+            ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN})
+    public void testOverrideSplitScreenAspectRatioForUnresizablePortraitApps() {
+        final int displayWidth = 1400;
+        final int displayHeight = 1600;
+        setUpDisplaySizeWithApp(displayWidth, displayHeight);
+        final ActivityRecord activity = new ActivityBuilder(mAtm)
+                .setTask(mTask)
+                .setComponent(ComponentName.createRelative(mContext,
+                        SizeCompatTests.class.getName()))
+                .setMinAspectRatio(1.1f)
+                .setUid(android.os.Process.myUid())
+                .build();
+        // Setup Letterbox Configuration
+        activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+        activity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(1.5f);
+        // Non-resizable portrait activity
+        prepareUnresizable(activity, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+        float expectedAspectRatio = 1f * displayWidth / getExpectedSplitSize(displayHeight);
+        final Rect afterBounds = activity.getBounds();
+        final float afterAspectRatio = (float) (afterBounds.height()) / afterBounds.width();
+        Assert.assertEquals(expectedAspectRatio, afterAspectRatio, 0.001f);
+    }
+
+    @Test
+    @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
+            ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN})
+    public void testOverrideSplitScreenAspectRatioForUnresizablePortraitAppsFromLandscape() {
+        final int displayWidth = 1600;
+        final int displayHeight = 1400;
+        setUpDisplaySizeWithApp(displayWidth, displayHeight);
+        final ActivityRecord activity = new ActivityBuilder(mAtm)
+                .setTask(mTask)
+                .setComponent(ComponentName.createRelative(mContext,
+                        SizeCompatTests.class.getName()))
+                .setMinAspectRatio(1.1f)
+                .setUid(android.os.Process.myUid())
+                .build();
+        // Setup Letterbox Configuration
+        activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+        activity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(1.5f);
+        // Non-resizable portrait activity
+        prepareUnresizable(activity, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+        float expectedAspectRatio = 1f * displayHeight / getExpectedSplitSize(displayWidth);
+        final Rect afterBounds = activity.getBounds();
+        final float afterAspectRatio = (float) (afterBounds.height()) / afterBounds.width();
+        Assert.assertEquals(expectedAspectRatio, afterAspectRatio, 0.001f);
+    }
+
+    @Test
+    @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
+            ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN})
+    @DisableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY})
+    public void testOverrideSplitScreenAspectRatioForUnresizableLandscapeApps() {
+        final int displayWidth = 1400;
+        final int displayHeight = 1600;
+        setUpDisplaySizeWithApp(displayWidth, displayHeight);
+        final ActivityRecord activity = new ActivityBuilder(mAtm)
+                .setTask(mTask)
+                .setComponent(ComponentName.createRelative(mContext,
+                        SizeCompatTests.class.getName()))
+                .setMinAspectRatio(1.1f)
+                .setUid(android.os.Process.myUid())
+                .build();
+        // Setup Letterbox Configuration
+        activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+        activity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(1.5f);
+        // Non-resizable portrait activity
+        prepareUnresizable(activity, ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
+        float expectedAspectRatio = 1f * displayWidth / getExpectedSplitSize(displayHeight);
+        final Rect afterBounds = activity.getBounds();
+        final float afterAspectRatio = (float) (afterBounds.width()) / afterBounds.height();
+        Assert.assertEquals(expectedAspectRatio, afterAspectRatio, 0.001f);
+    }
+
+    @Test
+    @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
+            ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN})
+    @DisableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY})
+    public void testOverrideSplitScreenAspectRatioForUnresizableLandscapeAppsFromLandscape() {
+        final int displayWidth = 1600;
+        final int displayHeight = 1400;
+        setUpDisplaySizeWithApp(displayWidth, displayHeight);
+        final ActivityRecord activity = new ActivityBuilder(mAtm)
+                .setTask(mTask)
+                .setComponent(ComponentName.createRelative(mContext,
+                        SizeCompatTests.class.getName()))
+                .setMinAspectRatio(1.1f)
+                .setUid(android.os.Process.myUid())
+                .build();
+        // Setup Letterbox Configuration
+        activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+        activity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(1.5f);
+        // Non-resizable portrait activity
+        prepareUnresizable(activity, ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
+        float expectedAspectRatio = 1f * displayHeight / getExpectedSplitSize(displayWidth);
+        final Rect afterBounds = activity.getBounds();
+        final float afterAspectRatio = (float) (afterBounds.width()) / afterBounds.height();
+        Assert.assertEquals(expectedAspectRatio, afterAspectRatio, 0.001f);
+    }
+
+    @Test
     public void testSplitAspectRatioForUnresizableLandscapeApps() {
         // Set up a display in portrait and ignoring orientation request.
         int screenWidth = 1400;
@@ -2165,6 +2267,40 @@
     }
 
     @Test
+    public void testLetterboxDetailsForStatusBar_letterboxNotOverlappingStatusBar() {
+        final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1000, 2800)
+                .setNotch(100)
+                .build();
+        setUpApp(display);
+        TestWindowState statusBar = addStatusBar(mActivity.mDisplayContent);
+        spyOn(statusBar);
+        doReturn(new Rect(0, 0, statusBar.mRequestedWidth, statusBar.mRequestedHeight))
+                .when(statusBar).getFrame();
+        addWindowToActivity(mActivity); // Add a window to the activity so that we can get an
+        // appearance inside letterboxDetails
+        // Prepare unresizable activity with max aspect ratio
+        prepareUnresizable(mActivity, /* maxAspect */ 1.1f, SCREEN_ORIENTATION_UNSPECIFIED);
+        // Refresh the letterbox
+        mActivity.mRootWindowContainer.performSurfacePlacement();
+
+        Rect mBounds = new Rect(mActivity.getWindowConfiguration().getBounds());
+        assertEquals(mBounds, new Rect(0, 750, 1000, 1950));
+
+        DisplayPolicy displayPolicy = mActivity.getDisplayContent().getDisplayPolicy();
+        LetterboxDetails[] expectedLetterboxDetails = {new LetterboxDetails(
+                mBounds,
+                mActivity.getDisplayContent().getBounds(),
+                mActivity.findMainWindow().mAttrs.insetsFlags.appearance
+        )};
+
+        // Check that letterboxDetails actually gets passed to SysUI
+        StatusBarManagerInternal statusBarManager = displayPolicy.getStatusBarManagerInternal();
+        verify(statusBarManager).onSystemBarAttributesChanged(anyInt(), anyInt(),
+                any(), anyBoolean(), anyInt(),
+                any(InsetsVisibilities.class), isNull(), eq(expectedLetterboxDetails));
+    }
+
+    @Test
     public void testSplitScreenLetterboxDetailsForStatusBar_twoLetterboxedApps() {
         mAtm.mDevEnableNonResizableMultiWindow = true;
         setUpDisplaySizeWithApp(2800, 1000);
@@ -2785,7 +2921,7 @@
         return w;
     }
 
-    private static void addStatusBar(DisplayContent displayContent) {
+    private static TestWindowState addStatusBar(DisplayContent displayContent) {
         final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
         doReturn(true).when(displayPolicy).hasStatusBar();
         displayPolicy.onConfigurationChanged();
@@ -2806,6 +2942,7 @@
 
         displayPolicy.addWindowLw(statusBar, attrs);
         displayPolicy.layoutWindowLw(statusBar, null, displayContent.mDisplayFrames);
+        return statusBar;
     }
 
     /**
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index 84c2c55..7d4e6fa 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -578,6 +578,22 @@
     }
 
     @Test
+    public void testContainerTranslucentChanges() {
+        removeGlobalMinSizeRestriction();
+        final Task rootTask = new TaskBuilder(mSupervisor).setCreateActivity(true)
+                .setWindowingMode(WINDOWING_MODE_FULLSCREEN).build();
+        final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(rootTask).build();
+        WindowContainerTransaction t = new WindowContainerTransaction();
+        assertFalse(rootTask.isTranslucent(activity));
+        t.setForceTranslucent(rootTask.mRemoteToken.toWindowContainerToken(), true);
+        mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
+        assertTrue(rootTask.isTranslucent(activity));
+        t.setForceTranslucent(rootTask.mRemoteToken.toWindowContainerToken(), false);
+        mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
+        assertFalse(rootTask.isTranslucent(activity));
+    }
+
+    @Test
     public void testSetIgnoreOrientationRequest_taskDisplayArea() {
         removeGlobalMinSizeRestriction();
         final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea();
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 3ed87e1..f794a79 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -24,7 +24,6 @@
 import android.database.Cursor;
 import android.hardware.radio.V1_5.ApnTypes;
 import android.net.Uri;
-import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.provider.Telephony;
@@ -964,7 +963,7 @@
                 ServiceState.convertBearerBitmaskToNetworkTypeBitmask(bearerBitmask);
         }
         int mtuV4 = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU_V4));
-        if (mtuV4 == -1) {
+        if (mtuV4 == UNSET_MTU) {
             mtuV4 = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU));
         }
 
diff --git a/tests/ApkVerityTest/Android.bp b/tests/ApkVerityTest/Android.bp
index 62e16a5..f026bea 100644
--- a/tests/ApkVerityTest/Android.bp
+++ b/tests/ApkVerityTest/Android.bp
@@ -37,8 +37,8 @@
         "general-tests",
         "vts",
     ],
-    target_required: [
-        "block_device_writer_module",
+    data_device_bins_both: [
+        "block_device_writer",
     ],
     data: [
         ":ApkVerityTestCertDer",
diff --git a/tests/ApkVerityTest/AndroidTest.xml b/tests/ApkVerityTest/AndroidTest.xml
index 55704ed..39b75cc 100644
--- a/tests/ApkVerityTest/AndroidTest.xml
+++ b/tests/ApkVerityTest/AndroidTest.xml
@@ -31,10 +31,18 @@
 
     <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
         <option name="cleanup" value="true" />
-        <option name="push" value="block_device_writer->/data/local/tmp/block_device_writer" />
         <option name="push" value="ApkVerityTestCert.der->/data/local/tmp/ApkVerityTestCert.der" />
     </target_preparer>
 
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+        <!-- The build system produces both 32 and 64 bit variants with bitness suffix. Let
+             FilePusher find the filename with bitness and push to a remote name without bitness.
+        -->
+        <option name="append-bitness" value="true" />
+        <option name="cleanup" value="true" />
+        <option name="push" value="block_device_writer->/data/local/tmp/block_device_writer" />
+    </target_preparer>
+
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="ApkVerityTest.jar" />
     </test>
diff --git a/tests/ApkVerityTest/block_device_writer/Android.bp b/tests/ApkVerityTest/block_device_writer/Android.bp
index fdfa41f..0002447d 100644
--- a/tests/ApkVerityTest/block_device_writer/Android.bp
+++ b/tests/ApkVerityTest/block_device_writer/Android.bp
@@ -24,12 +24,7 @@
 }
 
 cc_test {
-    // Depending on how the test runs, the executable may be uploaded to different location.
-    // Before the bug in the file pusher is fixed, workaround by making the name unique.
-    // See b/124718249#comment12.
-    name: "block_device_writer_module",
-    stem: "block_device_writer",
-
+    name: "block_device_writer",
     srcs: ["block_device_writer.cpp"],
     cflags: [
         "-D_FILE_OFFSET_BITS=64",
@@ -42,20 +37,13 @@
         "libbase",
         "libutils",
     ],
-    // For some reasons, cuttlefish (x86) uses x86_64 test suites for testing. Unfortunately, when
-    // the uploader does not pick up the executable from correct output location. The following
-    // workaround allows the test to:
-    //  * upload the 32-bit exectuable for both 32 and 64 bits devices to use
-    //  * refer to the same executable name in Java
-    //  * no need to force the Java test to be archiecture specific.
-    //
-    // See b/145573317 for details.
+    compile_multilib: "both",
     multilib: {
         lib32: {
-            suffix: "",
+            suffix: "32",
         },
         lib64: {
-            suffix: "64", // not really used
+            suffix: "64",
         },
     },
 
diff --git a/tests/ApkVerityTest/block_device_writer/src/com/android/blockdevicewriter/BlockDeviceWriter.java b/tests/ApkVerityTest/block_device_writer/src/com/android/blockdevicewriter/BlockDeviceWriter.java
index 5c2c15b..9be02ec 100644
--- a/tests/ApkVerityTest/block_device_writer/src/com/android/blockdevicewriter/BlockDeviceWriter.java
+++ b/tests/ApkVerityTest/block_device_writer/src/com/android/blockdevicewriter/BlockDeviceWriter.java
@@ -32,11 +32,12 @@
  * <p>To use this class, please push block_device_writer binary to /data/local/tmp.
  * 1. In Android.bp, add:
  * <pre>
- *     target_required: ["block_device_writer_module"],
+ *      data_device_bins_both: ["block_device_writer"],
  * </pre>
  * 2. In AndroidText.xml, add:
  * <pre>
- *     <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ *     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ *         <option name="append-bitness" value="true" />
  *         <option name="push" value="block_device_writer->/data/local/tmp/block_device_writer" />
  *     </target_preparer>
  * </pre>