Merge "Fix black screen while animating a closing and changing TF" into tm-qpr-dev
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index c0e89d2..14bf532 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -797,6 +797,7 @@
     field public static final long OVERRIDE_MIN_ASPECT_RATIO_MEDIUM = 180326845L; // 0xabf91bdL
     field public static final float OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE = 1.5f;
     field public static final long OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY = 203647190L; // 0xc2368d6L
+    field public static final long OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS = 237531167L; // 0xe28701fL
     field public static final int RESIZE_MODE_RESIZEABLE = 2; // 0x2
   }
 
@@ -2917,7 +2918,9 @@
   }
 
   @UiThread public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback {
+    method public void getBoundsOnScreen(@NonNull android.graphics.Rect, boolean);
     method public android.view.View getTooltipView();
+    method public void getWindowDisplayFrame(@NonNull android.graphics.Rect);
     method public boolean isAutofilled();
     method public static boolean isDefaultFocusHighlightEnabled();
     method public boolean isDefaultFocusHighlightNeeded(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 0fd80c5..7f48e39 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -6965,8 +6965,10 @@
     /**
      * Returns whether an app can colorize due to the android.permission.USE_COLORIZED_NOTIFICATIONS
      * permission. The permission is checked when a notification is enqueued.
+     *
+     * @hide
      */
-    private boolean hasColorizedPermission() {
+    public boolean hasColorizedPermission() {
         return (flags & Notification.FLAG_CAN_COLORIZE) != 0;
     }
 
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index 8ee23aa..23f2bdb 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -49,6 +49,12 @@
     private static final String TAG = "TaskInfo";
 
     /**
+     * The value to use when the property has not a specific value.
+     * @hide
+     */
+    public static final int PROPERTY_VALUE_UNSET = -1;
+
+    /**
      * The id of the user the task was running as if this is a leaf task. The id of the current
      * running user of the system otherwise.
      * @hide
@@ -188,6 +194,14 @@
     public int launchIntoPipHostTaskId;
 
     /**
+     * The task id of the parent Task of the launch-into-pip Activity, i.e., if task have more than
+     * one activity it will create new task for this activity, this id is the origin task id and
+     * the pip activity will be reparent to origin task when it exit pip mode.
+     * @hide
+     */
+    public int lastParentTaskIdBeforePip;
+
+    /**
      * The {@link Rect} copied from {@link DisplayCutout#getSafeInsets()} if the cutout is not of
      * (LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES, LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS),
      * {@code null} otherwise.
@@ -222,6 +236,40 @@
     public boolean topActivityEligibleForLetterboxEducation;
 
     /**
+     * Whether the double tap is enabled
+     * @hide
+     */
+    public boolean isLetterboxDoubleTapEnabled;
+
+    /**
+     * If {@link isLetterboxDoubleTapEnabled} it contains the current letterbox vertical position or
+     * {@link TaskInfo.PROPERTY_VALUE_UNSET} otherwise.
+     * @hide
+     */
+    public int topActivityLetterboxVerticalPosition;
+
+    /**
+     * If {@link isLetterboxDoubleTapEnabled} it contains the current letterbox vertical position or
+     * {@link TaskInfo.PROPERTY_VALUE_UNSET} otherwise.
+     * @hide
+     */
+    public int topActivityLetterboxHorizontalPosition;
+
+    /**
+     * If {@link isLetterboxDoubleTapEnabled} it contains the current width of the letterboxed
+     * activity or {@link TaskInfo.PROPERTY_VALUE_UNSET} otherwise
+     * @hide
+     */
+    public int topActivityLetterboxWidth;
+
+    /**
+     * If {@link isLetterboxDoubleTapEnabled} it contains the current height of the letterboxed
+     * activity or {@link TaskInfo.PROPERTY_VALUE_UNSET} otherwise
+     * @hide
+     */
+    public int topActivityLetterboxHeight;
+
+    /**
      * Whether this task is resizable. Unlike {@link #resizeMode} (which is what the top activity
      * supports), this is what the system actually uses for resizability based on other policy and
      * developer options.
@@ -399,7 +447,8 @@
     /** @hide */
     public boolean hasCompatUI() {
         return hasCameraCompatControl() || topActivityInSizeCompat
-                || topActivityEligibleForLetterboxEducation;
+                || topActivityEligibleForLetterboxEducation
+                || isLetterboxDoubleTapEnabled;
     }
 
     /**
@@ -439,6 +488,12 @@
                 && isResizeable == that.isResizeable
                 && supportsMultiWindow == that.supportsMultiWindow
                 && displayAreaFeatureId == that.displayAreaFeatureId
+                && isLetterboxDoubleTapEnabled == that.isLetterboxDoubleTapEnabled
+                && topActivityLetterboxVerticalPosition == that.topActivityLetterboxVerticalPosition
+                && topActivityLetterboxWidth == that.topActivityLetterboxWidth
+                && topActivityLetterboxHeight == that.topActivityLetterboxHeight
+                && topActivityLetterboxHorizontalPosition
+                    == that.topActivityLetterboxHorizontalPosition
                 && Objects.equals(positionInParent, that.positionInParent)
                 && Objects.equals(pictureInPictureParams, that.pictureInPictureParams)
                 && Objects.equals(shouldDockBigOverlays, that.shouldDockBigOverlays)
@@ -467,6 +522,12 @@
                 && topActivityInSizeCompat == that.topActivityInSizeCompat
                 && topActivityEligibleForLetterboxEducation
                     == that.topActivityEligibleForLetterboxEducation
+                && isLetterboxDoubleTapEnabled == that.isLetterboxDoubleTapEnabled
+                && topActivityLetterboxVerticalPosition == that.topActivityLetterboxVerticalPosition
+                && topActivityLetterboxHorizontalPosition
+                    == that.topActivityLetterboxHorizontalPosition
+                && topActivityLetterboxWidth == that.topActivityLetterboxWidth
+                && topActivityLetterboxHeight == that.topActivityLetterboxHeight
                 && cameraCompatControlState == that.cameraCompatControlState
                 // Bounds are important if top activity has compat controls.
                 && (!hasCompatUI() || configuration.windowConfiguration.getBounds()
@@ -503,6 +564,7 @@
         pictureInPictureParams = source.readTypedObject(PictureInPictureParams.CREATOR);
         shouldDockBigOverlays = source.readBoolean();
         launchIntoPipHostTaskId = source.readInt();
+        lastParentTaskIdBeforePip = source.readInt();
         displayCutoutInsets = source.readTypedObject(Rect.CREATOR);
         topActivityInfo = source.readTypedObject(ActivityInfo.CREATOR);
         isResizeable = source.readBoolean();
@@ -520,6 +582,11 @@
         mTopActivityLocusId = source.readTypedObject(LocusId.CREATOR);
         displayAreaFeatureId = source.readInt();
         cameraCompatControlState = source.readInt();
+        isLetterboxDoubleTapEnabled = source.readBoolean();
+        topActivityLetterboxVerticalPosition = source.readInt();
+        topActivityLetterboxHorizontalPosition = source.readInt();
+        topActivityLetterboxWidth = source.readInt();
+        topActivityLetterboxHeight = source.readInt();
     }
 
     /**
@@ -549,6 +616,7 @@
         dest.writeTypedObject(pictureInPictureParams, flags);
         dest.writeBoolean(shouldDockBigOverlays);
         dest.writeInt(launchIntoPipHostTaskId);
+        dest.writeInt(lastParentTaskIdBeforePip);
         dest.writeTypedObject(displayCutoutInsets, flags);
         dest.writeTypedObject(topActivityInfo, flags);
         dest.writeBoolean(isResizeable);
@@ -566,6 +634,11 @@
         dest.writeTypedObject(mTopActivityLocusId, flags);
         dest.writeInt(displayAreaFeatureId);
         dest.writeInt(cameraCompatControlState);
+        dest.writeBoolean(isLetterboxDoubleTapEnabled);
+        dest.writeInt(topActivityLetterboxVerticalPosition);
+        dest.writeInt(topActivityLetterboxHorizontalPosition);
+        dest.writeInt(topActivityLetterboxWidth);
+        dest.writeInt(topActivityLetterboxHeight);
     }
 
     @Override
@@ -589,6 +662,7 @@
                 + " pictureInPictureParams=" + pictureInPictureParams
                 + " shouldDockBigOverlays=" + shouldDockBigOverlays
                 + " launchIntoPipHostTaskId=" + launchIntoPipHostTaskId
+                + " lastParentTaskIdBeforePip=" + lastParentTaskIdBeforePip
                 + " displayCutoutSafeInsets=" + displayCutoutInsets
                 + " topActivityInfo=" + topActivityInfo
                 + " launchCookies=" + launchCookies
@@ -600,6 +674,12 @@
                 + " topActivityInSizeCompat=" + topActivityInSizeCompat
                 + " topActivityEligibleForLetterboxEducation= "
                         + topActivityEligibleForLetterboxEducation
+                + " topActivityLetterboxed= " + isLetterboxDoubleTapEnabled
+                + " topActivityLetterboxVerticalPosition= " + topActivityLetterboxVerticalPosition
+                + " topActivityLetterboxHorizontalPosition= "
+                        + topActivityLetterboxHorizontalPosition
+                + " topActivityLetterboxWidth=" + topActivityLetterboxWidth
+                + " topActivityLetterboxHeight=" + topActivityLetterboxHeight
                 + " locusId=" + mTopActivityLocusId
                 + " displayAreaFeatureId=" + displayAreaFeatureId
                 + " cameraCompatControlState="
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index fe10b7f..27f6a26 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -31,6 +31,7 @@
 import android.content.pm.LauncherApps;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
+import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.PointF;
 import android.graphics.Rect;
@@ -311,20 +312,27 @@
             super.onLayout(changed, left, top, right, bottom);
         } catch (final RuntimeException e) {
             Log.e(TAG, "Remote provider threw runtime exception, using error view instead.", e);
-            removeViewInLayout(mView);
-            View child = getErrorView();
-            prepareView(child);
-            addViewInLayout(child, 0, child.getLayoutParams());
-            measureChild(child, MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY),
-                    MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY));
-            child.layout(0, 0, child.getMeasuredWidth() + mPaddingLeft + mPaddingRight,
-                    child.getMeasuredHeight() + mPaddingTop + mPaddingBottom);
-            mView = child;
-            mViewMode = VIEW_MODE_ERROR;
+            handleViewError();
         }
     }
 
     /**
+     * Remove bad view and replace with error message view
+     */
+    private void handleViewError() {
+        removeViewInLayout(mView);
+        View child = getErrorView();
+        prepareView(child);
+        addViewInLayout(child, 0, child.getLayoutParams());
+        measureChild(child, MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY),
+                MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY));
+        child.layout(0, 0, child.getMeasuredWidth() + mPaddingLeft + mPaddingRight,
+                child.getMeasuredHeight() + mPaddingTop + mPaddingBottom);
+        mView = child;
+        mViewMode = VIEW_MODE_ERROR;
+    }
+
+    /**
      * Provide guidance about the size of this widget to the AppWidgetManager. The widths and
      * heights should correspond to the full area the AppWidgetHostView is given. Padding added by
      * the framework will be accounted for automatically. This information gets embedded into the
@@ -953,4 +961,15 @@
             reapplyLastRemoteViews();
         }
     }
+
+    @Override
+    protected void dispatchDraw(@NonNull Canvas canvas) {
+        try {
+            super.dispatchDraw(canvas);
+        } catch (Exception e) {
+            // Catch draw exceptions that may be caused by RemoteViews
+            Log.e(TAG, "Drawing view failed: " + e);
+            post(this::handleViewError);
+        }
+    }
 }
diff --git a/core/java/android/content/ContentCaptureOptions.java b/core/java/android/content/ContentCaptureOptions.java
index 7707289..856bde8 100644
--- a/core/java/android/content/ContentCaptureOptions.java
+++ b/core/java/android/content/ContentCaptureOptions.java
@@ -70,6 +70,12 @@
     public final int logHistorySize;
 
     /**
+     * Disable flush when receiving a VIEW_TREE_APPEARING event.
+     * @hide
+     */
+    public final boolean disableFlushForViewTreeAppearing;
+
+    /**
      * List of activities explicitly allowlisted for content capture (or {@code null} if allowlisted
      * for all acitivites in the package).
      */
@@ -90,7 +96,8 @@
     public ContentCaptureOptions(int loggingLevel) {
         this(/* lite= */ true, loggingLevel, /* maxBufferSize= */ 0,
                 /* idleFlushingFrequencyMs= */ 0, /* textChangeFlushingFrequencyMs= */ 0,
-                /* logHistorySize= */ 0, /* whitelistedComponents= */ null);
+                /* logHistorySize= */ 0, /* disableFlushForViewTreeAppearing= */ false,
+                /* whitelistedComponents= */ null);
     }
 
     /**
@@ -98,10 +105,23 @@
      */
     public ContentCaptureOptions(int loggingLevel, int maxBufferSize, int idleFlushingFrequencyMs,
             int textChangeFlushingFrequencyMs, int logHistorySize,
-            @SuppressLint("NullableCollection")
+            @SuppressLint({"ConcreteCollection", "NullableCollection"})
             @Nullable ArraySet<ComponentName> whitelistedComponents) {
         this(/* lite= */ false, loggingLevel, maxBufferSize, idleFlushingFrequencyMs,
-                textChangeFlushingFrequencyMs, logHistorySize, whitelistedComponents);
+                textChangeFlushingFrequencyMs, logHistorySize,
+                ContentCaptureManager.DEFAULT_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING,
+                whitelistedComponents);
+    }
+
+    /** @hide */
+    public ContentCaptureOptions(int loggingLevel, int maxBufferSize, int idleFlushingFrequencyMs,
+            int textChangeFlushingFrequencyMs, int logHistorySize,
+            boolean disableFlushForViewTreeAppearing,
+            @SuppressLint({"ConcreteCollection", "NullableCollection"})
+            @Nullable ArraySet<ComponentName> whitelistedComponents) {
+        this(/* lite= */ false, loggingLevel, maxBufferSize, idleFlushingFrequencyMs,
+                textChangeFlushingFrequencyMs, logHistorySize, disableFlushForViewTreeAppearing,
+                whitelistedComponents);
     }
 
     /** @hide */
@@ -111,11 +131,14 @@
                 ContentCaptureManager.DEFAULT_MAX_BUFFER_SIZE,
                 ContentCaptureManager.DEFAULT_IDLE_FLUSHING_FREQUENCY_MS,
                 ContentCaptureManager.DEFAULT_TEXT_CHANGE_FLUSHING_FREQUENCY_MS,
-                ContentCaptureManager.DEFAULT_LOG_HISTORY_SIZE, whitelistedComponents);
+                ContentCaptureManager.DEFAULT_LOG_HISTORY_SIZE,
+                ContentCaptureManager.DEFAULT_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING,
+                whitelistedComponents);
     }
 
     private ContentCaptureOptions(boolean lite, int loggingLevel, int maxBufferSize,
             int idleFlushingFrequencyMs, int textChangeFlushingFrequencyMs, int logHistorySize,
+            boolean disableFlushForViewTreeAppearing,
             @Nullable ArraySet<ComponentName> whitelistedComponents) {
         this.lite = lite;
         this.loggingLevel = loggingLevel;
@@ -123,6 +146,7 @@
         this.idleFlushingFrequencyMs = idleFlushingFrequencyMs;
         this.textChangeFlushingFrequencyMs = textChangeFlushingFrequencyMs;
         this.logHistorySize = logHistorySize;
+        this.disableFlushForViewTreeAppearing = disableFlushForViewTreeAppearing;
         this.whitelistedComponents = whitelistedComponents;
     }
 
@@ -171,7 +195,8 @@
             .append(", maxBufferSize=").append(maxBufferSize)
             .append(", idleFlushingFrequencyMs=").append(idleFlushingFrequencyMs)
             .append(", textChangeFlushingFrequencyMs=").append(textChangeFlushingFrequencyMs)
-            .append(", logHistorySize=").append(logHistorySize);
+            .append(", logHistorySize=").append(logHistorySize)
+            .append(", disableFlushForViewTreeAppearing=").append(disableFlushForViewTreeAppearing);
         if (whitelistedComponents != null) {
             string.append(", whitelisted=").append(whitelistedComponents);
         }
@@ -189,6 +214,7 @@
         pw.print(", idle="); pw.print(idleFlushingFrequencyMs);
         pw.print(", textIdle="); pw.print(textChangeFlushingFrequencyMs);
         pw.print(", logSize="); pw.print(logHistorySize);
+        pw.print(", disableFlushForViewTreeAppearing="); pw.print(disableFlushForViewTreeAppearing);
         if (whitelistedComponents != null) {
             pw.print(", whitelisted="); pw.print(whitelistedComponents);
         }
@@ -209,6 +235,7 @@
         parcel.writeInt(idleFlushingFrequencyMs);
         parcel.writeInt(textChangeFlushingFrequencyMs);
         parcel.writeInt(logHistorySize);
+        parcel.writeBoolean(disableFlushForViewTreeAppearing);
         parcel.writeArraySet(whitelistedComponents);
     }
 
@@ -226,12 +253,13 @@
                     final int idleFlushingFrequencyMs = parcel.readInt();
                     final int textChangeFlushingFrequencyMs = parcel.readInt();
                     final int logHistorySize = parcel.readInt();
+                    final boolean disableFlushForViewTreeAppearing = parcel.readBoolean();
                     @SuppressWarnings("unchecked")
                     final ArraySet<ComponentName> whitelistedComponents =
                             (ArraySet<ComponentName>) parcel.readArraySet(null);
                     return new ContentCaptureOptions(loggingLevel, maxBufferSize,
                             idleFlushingFrequencyMs, textChangeFlushingFrequencyMs, logHistorySize,
-                            whitelistedComponents);
+                            disableFlushForViewTreeAppearing, whitelistedComponents);
                 }
 
                 @Override
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index bbe99f5..319f129 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1035,6 +1035,20 @@
             254631730L; // buganizer id
 
     /**
+     * This change id enables compat policy that ignores app requested orientation in
+     * response to an app calling {@link android.app.Activity#setRequestedOrientation} more
+     * than twice in one second if an activity is not letterboxed for fixed orientation.
+     * See com.android.server.wm.LetterboxUiController#shouldIgnoreRequestedOrientation
+     * for details.
+     * @hide
+     */
+    @ChangeId
+    @Overridable
+    @Disabled
+    public static final long OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED =
+            273509367L; // buganizer id
+
+    /**
      * This change id forces the packages it is applied to never have Display API sandboxing
      * applied for a letterbox or SCM activity. The Display APIs will continue to provide
      * DisplayArea bounds.
@@ -1104,6 +1118,34 @@
             264301586L; // buganizer id
 
     /**
+     * This change id forces the packages it is applied to sandbox {@link android.view.View} API to
+     * an activity bounds for:
+     *
+     * <p>{@link android.view.View#getLocationOnScreen},
+     * {@link android.view.View#getWindowVisibleDisplayFrame},
+     * {@link android.view.View}#getWindowDisplayFrame,
+     * {@link android.view.View}#getBoundsOnScreen.
+     *
+     * <p>For {@link android.view.View#getWindowVisibleDisplayFrame} and
+     * {@link android.view.View}#getWindowDisplayFrame this sandboxing is happening indirectly
+     * through
+     * {@link android.view.ViewRootImpl}#getWindowVisibleDisplayFrame,
+     * {@link android.view.ViewRootImpl}#getDisplayFrame respectively.
+     *
+     * <p>Some applications assume that they occupy the whole screen and therefore use the display
+     * coordinates in their calculations as if an activity is  positioned in the top-left corner of
+     * the screen, with left coordinate equal to 0. This may not be the case of applications in
+     * multi-window and in letterbox modes. This can lead to shifted or out of bounds UI elements in
+     * case the activity is Letterboxed or is in multi-window mode.
+     * @hide
+     */
+    @ChangeId
+    @Overridable
+    @Disabled
+    @TestApi
+    public static final long OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS = 237531167L; // buganizer id
+
+    /**
      * This change id is the gatekeeper for all treatments that force a given min aspect ratio.
      * Enabling this change will allow the following min aspect ratio treatments to be applied:
      * OVERRIDE_MIN_ASPECT_RATIO_MEDIUM
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 7ccf07a..ccc39b6 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -17,12 +17,7 @@
 package android.hardware;
 
 import static android.system.OsConstants.EACCES;
-import static android.system.OsConstants.EBUSY;
-import static android.system.OsConstants.EINVAL;
 import static android.system.OsConstants.ENODEV;
-import static android.system.OsConstants.ENOSYS;
-import static android.system.OsConstants.EOPNOTSUPP;
-import static android.system.OsConstants.EUSERS;
 
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
@@ -56,6 +51,7 @@
 import android.view.Surface;
 import android.view.SurfaceHolder;
 
+import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IAppOpsCallback;
 import com.android.internal.app.IAppOpsService;
@@ -491,8 +487,22 @@
 
         boolean overrideToPortrait = CameraManager.shouldOverrideToPortrait(
                 ActivityThread.currentApplication().getApplicationContext());
+        boolean forceSlowJpegMode = shouldForceSlowJpegMode();
         return native_setup(new WeakReference<Camera>(this), cameraId,
-                ActivityThread.currentOpPackageName(), overrideToPortrait);
+                ActivityThread.currentOpPackageName(), overrideToPortrait, forceSlowJpegMode);
+    }
+
+    private boolean shouldForceSlowJpegMode() {
+        Context applicationContext = ActivityThread.currentApplication().getApplicationContext();
+        String[] slowJpegPackageNames = applicationContext.getResources().getStringArray(
+                R.array.config_forceSlowJpegModeList);
+        String callingPackageName = applicationContext.getPackageName();
+        for (String packageName : slowJpegPackageNames) {
+            if (TextUtils.equals(packageName, callingPackageName)) {
+                return true;
+            }
+        }
+        return false;
     }
 
     /** used by Camera#open, Camera#open(int) */
@@ -563,7 +573,7 @@
 
     @UnsupportedAppUsage
     private native int native_setup(Object cameraThis, int cameraId, String packageName,
-            boolean overrideToPortrait);
+            boolean overrideToPortrait, boolean forceSlowJpegMode);
 
     private native final void native_release();
 
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 32cf0a7..56592ab 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -1189,8 +1189,8 @@
             PackageManager packageManager = context.getPackageManager();
 
             try {
-                return packageManager.getProperty(context.getOpPackageName(),
-                            PROPERTY_COMPAT_OVERRIDE_LANDSCAPE_TO_PORTRAIT).getBoolean();
+                return packageManager.getProperty(PROPERTY_COMPAT_OVERRIDE_LANDSCAPE_TO_PORTRAIT,
+                        context.getOpPackageName()).getBoolean();
             } catch (PackageManager.NameNotFoundException e) {
                 // No such property
             }
diff --git a/core/java/android/hardware/camera2/extension/CameraOutputConfig.aidl b/core/java/android/hardware/camera2/extension/CameraOutputConfig.aidl
index 34d016a..7c54a9b 100644
--- a/core/java/android/hardware/camera2/extension/CameraOutputConfig.aidl
+++ b/core/java/android/hardware/camera2/extension/CameraOutputConfig.aidl
@@ -36,4 +36,5 @@
     int surfaceGroupId;
     String physicalCameraId;
     List<CameraOutputConfig> sharedSurfaceConfigs;
+    boolean isMultiResolutionOutput;
 }
diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
index c8dc2d0..77def20 100644
--- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -226,6 +226,9 @@
             OutputConfiguration cameraOutput = new OutputConfiguration(output.surfaceGroupId,
                     outputSurface);
 
+            if (output.isMultiResolutionOutput) {
+                cameraOutput.setMultiResolutionOutput();
+            }
             if ((output.sharedSurfaceConfigs != null) && !output.sharedSurfaceConfigs.isEmpty()) {
                 cameraOutput.enableSurfaceSharing();
                 for (CameraOutputConfig sharedOutputConfig : output.sharedSurfaceConfigs) {
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index 90e92db..9868d87 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -421,7 +421,7 @@
      *         call, or no non-negative group ID has been set.
      * @hide
      */
-    void setMultiResolutionOutput() {
+    public void setMultiResolutionOutput() {
         if (mIsShared) {
             throw new IllegalStateException("Multi-resolution output flag must not be set for " +
                     "configuration with surface sharing");
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 63dc7c7..aef2ae2 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -40,6 +40,7 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.Trace;
 import android.util.Log;
 import android.util.Pair;
 import android.util.SparseArray;
@@ -1006,7 +1007,8 @@
         @Override
         public void onDisplayEvent(int displayId, @DisplayEvent int event) {
             if (DEBUG) {
-                Log.d(TAG, "onDisplayEvent: displayId=" + displayId + ", event=" + event);
+                Log.d(TAG, "onDisplayEvent: displayId=" + displayId + ", event=" + eventToString(
+                        event));
             }
             handleDisplayEvent(displayId, event);
         }
@@ -1040,6 +1042,12 @@
 
         @Override
         public void handleMessage(Message msg) {
+            if (DEBUG) {
+                Trace.beginSection(
+                        "DisplayListenerDelegate(" + eventToString(msg.what)
+                                + ", display=" + msg.arg1
+                                + ", listener=" + mListener.getClass() + ")");
+            }
             switch (msg.what) {
                 case EVENT_DISPLAY_ADDED:
                     if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_ADDED) != 0) {
@@ -1066,6 +1074,9 @@
                     }
                     break;
             }
+            if (DEBUG) {
+                Trace.endSection();
+            }
         }
     }
 
@@ -1172,4 +1183,18 @@
             updateCallbackIfNeededLocked();
         }
     }
+
+    private static String eventToString(@DisplayEvent int event) {
+        switch (event) {
+            case EVENT_DISPLAY_ADDED:
+                return "ADDED";
+            case EVENT_DISPLAY_CHANGED:
+                return "CHANGED";
+            case EVENT_DISPLAY_REMOVED:
+                return "REMOVED";
+            case EVENT_DISPLAY_BRIGHTNESS_CHANGED:
+                return "BRIGHTNESS_CHANGED";
+        }
+        return "UNKNOWN";
+    }
 }
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 76475f2..4f49f12 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -2808,6 +2808,15 @@
     public abstract long getMobileRadioMeasuredBatteryConsumptionUC();
 
     /**
+     * Returns the battery consumption (in microcoulombs) of the phone calls, derived from on device
+     * power measurement data.
+     * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable.
+     *
+     * {@hide}
+     */
+    public abstract long getPhoneEnergyConsumptionUC();
+
+    /**
      * Returns the battery consumption (in microcoulombs) of the screen while on, derived from on
      * device power measurement data.
      * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable.
diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java
index 36e0dc3..b02e123 100644
--- a/core/java/android/preference/SeekBarVolumizer.java
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -141,12 +141,15 @@
     private int mRingerMode;
     private int mZenMode;
     private boolean mPlaySample;
+    private final boolean mDeviceHasProductStrategies;
 
     private static final int MSG_SET_STREAM_VOLUME = 0;
     private static final int MSG_START_SAMPLE = 1;
     private static final int MSG_STOP_SAMPLE = 2;
     private static final int MSG_INIT_SAMPLE = 3;
+    private static final int MSG_UPDATE_SLIDER_MAYBE_LATER = 4;
     private static final int CHECK_RINGTONE_PLAYBACK_DELAY_MS = 1000;
+    private static final int CHECK_UPDATE_SLIDER_LATER_MS = 500;
     private static final long SET_STREAM_VOLUME_DELAY_MS = TimeUnit.MILLISECONDS.toMillis(500);
     private static final long START_SAMPLE_DELAY_MS = TimeUnit.MILLISECONDS.toMillis(500);
     private static final long DURATION_TO_START_DELAYING = TimeUnit.MILLISECONDS.toMillis(2000);
@@ -170,6 +173,7 @@
             boolean playSample) {
         mContext = context;
         mAudioManager = context.getSystemService(AudioManager.class);
+        mDeviceHasProductStrategies = hasAudioProductStrategies();
         mNotificationManager = context.getSystemService(NotificationManager.class);
         mNotificationPolicy = mNotificationManager.getConsolidatedNotificationPolicy();
         mAllowAlarms = (mNotificationPolicy.priorityCategories & NotificationManager.Policy
@@ -186,7 +190,7 @@
         }
         mZenMode = mNotificationManager.getZenMode();
 
-        if (hasAudioProductStrategies()) {
+        if (mDeviceHasProductStrategies) {
             mVolumeGroupId = getVolumeGroupIdForLegacyStreamType(mStreamType);
             mAttributes = getAudioAttributesForLegacyStreamType(
                     mStreamType);
@@ -213,6 +217,12 @@
         mDefaultUri = defaultUri;
     }
 
+    /**
+     * DO NOT CALL every time this is needed, use once in constructor,
+     * read mDeviceHasProductStrategies instead
+     * @return true if stream types are used for volume management, false if volume groups are
+     *     used for volume management
+     */
     private boolean hasAudioProductStrategies() {
         return AudioManager.getAudioProductStrategies().size() > 0;
     }
@@ -330,6 +340,9 @@
                     onInitSample();
                 }
                 break;
+            case MSG_UPDATE_SLIDER_MAYBE_LATER:
+                onUpdateSliderMaybeLater();
+                break;
             default:
                 Log.e(TAG, "invalid SeekBarVolumizer message: "+msg.what);
         }
@@ -353,6 +366,21 @@
                         : isDelay() ? START_SAMPLE_DELAY_MS : 0);
     }
 
+    private void onUpdateSliderMaybeLater() {
+        if (isDelay()) {
+            postUpdateSliderMaybeLater();
+            return;
+        }
+        updateSlider();
+    }
+
+    private void postUpdateSliderMaybeLater() {
+        if (mHandler == null) return;
+        mHandler.removeMessages(MSG_UPDATE_SLIDER_MAYBE_LATER);
+        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_UPDATE_SLIDER_MAYBE_LATER),
+                CHECK_UPDATE_SLIDER_LATER_MS);
+    }
+
     // After stop volume it needs to add a small delay when playing volume or set stream.
     // It is because the call volume is from the earpiece and the alarm/ring/media
     // is from the speaker. If play the alarm volume or set alarm stream right after stop
@@ -422,7 +450,7 @@
         postStopSample();
         mContext.getContentResolver().unregisterContentObserver(mVolumeObserver);
         mReceiver.setListening(false);
-        if (hasAudioProductStrategies()) {
+        if (mDeviceHasProductStrategies) {
             unregisterVolumeGroupCb();
         }
         mSeekBar.setOnSeekBarChangeListener(null);
@@ -442,7 +470,7 @@
                 System.getUriFor(System.VOLUME_SETTINGS_INT[mStreamType]),
                 false, mVolumeObserver);
         mReceiver.setListening(true);
-        if (hasAudioProductStrategies()) {
+        if (mDeviceHasProductStrategies) {
             registerVolumeGroupCb();
         }
     }
@@ -466,6 +494,7 @@
         mLastProgress = progress;
         mHandler.removeMessages(MSG_SET_STREAM_VOLUME);
         mHandler.removeMessages(MSG_START_SAMPLE);
+        mHandler.removeMessages(MSG_UPDATE_SLIDER_MAYBE_LATER);
         mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SET_STREAM_VOLUME),
                 isDelay() ? SET_STREAM_VOLUME_DELAY_MS : 0);
     }
@@ -608,7 +637,7 @@
             if (AudioManager.VOLUME_CHANGED_ACTION.equals(action)) {
                 int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
                 int streamValue = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1);
-                if (hasAudioProductStrategies() && !isDelay()) {
+                if (mDeviceHasProductStrategies && !isDelay()) {
                     updateVolumeSlider(streamType, streamValue);
                 }
             } else if (AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION.equals(action)) {
@@ -620,9 +649,16 @@
                 }
             } else if (AudioManager.STREAM_DEVICES_CHANGED_ACTION.equals(action)) {
                 int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
-                if (hasAudioProductStrategies() && !isDelay()) {
-                    int streamVolume = mAudioManager.getStreamVolume(streamType);
-                    updateVolumeSlider(streamType, streamVolume);
+
+                if (mDeviceHasProductStrategies) {
+                    if (isDelay()) {
+                        // not the right time to update the sliders, try again later
+                        postUpdateSliderMaybeLater();
+                    } else {
+                        int streamVolume = mAudioManager.getStreamVolume(streamType);
+                        updateVolumeSlider(streamType, streamVolume);
+                    }
+
                 } else {
                     int volumeGroup = getVolumeGroupIdForLegacyStreamType(streamType);
                     if (volumeGroup != AudioVolumeGroup.DEFAULT_VOLUME_GROUP
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 10e1633..8d83798 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8001,6 +8001,15 @@
                 "accessibility_display_inversion_enabled";
 
         /**
+         * Flag that specifies whether font size has been changed. The flag will
+         * be set when users change the scaled value of font size for the first time.
+         * @hide
+         */
+        @Readable
+        public static final String ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED =
+                "accessibility_font_scaling_has_been_changed";
+
+        /**
          * Setting that specifies whether display color space adjustment is
          * enabled.
          *
@@ -9200,6 +9209,14 @@
         public static final String SCREENSAVER_COMPLICATIONS_ENABLED =
                 "screensaver_complications_enabled";
 
+        /**
+         * Whether home controls are enabled to be shown over the screensaver by the user.
+         *
+         * @hide
+         */
+        public static final String SCREENSAVER_HOME_CONTROLS_ENABLED =
+                "screensaver_home_controls_enabled";
+
 
         /**
          * Default, indicates that the user has not yet started the dock setup flow.
@@ -10980,21 +10997,46 @@
         public @interface DeviceStateRotationLockSetting {
         }
 
+        /** @hide */
+        public static final int DEVICE_STATE_ROTATION_KEY_UNKNOWN = -1;
+        /** @hide */
+        public static final int DEVICE_STATE_ROTATION_KEY_FOLDED = 0;
+        /** @hide */
+        public static final int DEVICE_STATE_ROTATION_KEY_HALF_FOLDED = 1;
+        /** @hide */
+        public static final int DEVICE_STATE_ROTATION_KEY_UNFOLDED = 2;
+
+        /**
+         * The different postures that can be used as keys with
+         * {@link #DEVICE_STATE_ROTATION_LOCK}.
+         * @hide
+         */
+        @IntDef(prefix = {"DEVICE_STATE_ROTATION_KEY_"}, value = {
+                DEVICE_STATE_ROTATION_KEY_UNKNOWN,
+                DEVICE_STATE_ROTATION_KEY_FOLDED,
+                DEVICE_STATE_ROTATION_KEY_HALF_FOLDED,
+                DEVICE_STATE_ROTATION_KEY_UNFOLDED,
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface DeviceStateRotationLockKey {
+        }
+
         /**
          * Rotation lock setting keyed on device state.
          *
-         * This holds a serialized map using int keys that represent Device States and value of
+         * This holds a serialized map using int keys that represent postures in
+         * {@link DeviceStateRotationLockKey} and value of
          * {@link DeviceStateRotationLockSetting} representing the rotation lock setting for that
-         * device state.
+         * posture.
          *
          * Serialized as key0:value0:key1:value1:...:keyN:valueN.
          *
          * Example: "0:1:1:2:2:1"
          * This example represents a map of:
          * <ul>
-         *     <li>0 -> DEVICE_STATE_ROTATION_LOCK_LOCKED</li>
-         *     <li>1 -> DEVICE_STATE_ROTATION_LOCK_UNLOCKED</li>
-         *     <li>2 -> DEVICE_STATE_ROTATION_LOCK_IGNORED</li>
+         *     <li>DEVICE_STATE_ROTATION_KEY_FOLDED -> DEVICE_STATE_ROTATION_LOCK_LOCKED</li>
+         *     <li>DEVICE_STATE_ROTATION_KEY_HALF_FOLDED -> DEVICE_STATE_ROTATION_LOCK_UNLOCKED</li>
+         *     <li>DEVICE_STATE_ROTATION_KEY_UNFOLDED -> DEVICE_STATE_ROTATION_LOCK_IGNORED</li>
          * </ul>
          *
          * @hide
diff --git a/core/java/android/service/dreams/DreamOverlayConnectionHandler.java b/core/java/android/service/dreams/DreamOverlayConnectionHandler.java
new file mode 100644
index 0000000..cafe02a
--- /dev/null
+++ b/core/java/android/service/dreams/DreamOverlayConnectionHandler.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.dreams;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ObservableServiceConnection;
+import com.android.internal.util.PersistentServiceConnection;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+/**
+ * Handles the service connection to {@link IDreamOverlay}
+ *
+ * @hide
+ */
+@VisibleForTesting
+public final class DreamOverlayConnectionHandler {
+    private static final String TAG = "DreamOverlayConnection";
+
+    private static final int MSG_ADD_CONSUMER = 1;
+    private static final int MSG_REMOVE_CONSUMER = 2;
+    private static final int MSG_OVERLAY_CLIENT_READY = 3;
+
+    private final Handler mHandler;
+    private final PersistentServiceConnection<IDreamOverlay> mConnection;
+    // Retrieved Client
+    private IDreamOverlayClient mClient;
+    // A list of pending requests to execute on the overlay.
+    private final List<Consumer<IDreamOverlayClient>> mConsumers = new ArrayList<>();
+    private final OverlayConnectionCallback mCallback;
+
+    DreamOverlayConnectionHandler(
+            Context context,
+            Looper looper,
+            Intent serviceIntent,
+            int minConnectionDurationMs,
+            int maxReconnectAttempts,
+            int baseReconnectDelayMs) {
+        this(context, looper, serviceIntent, minConnectionDurationMs, maxReconnectAttempts,
+                baseReconnectDelayMs, new Injector());
+    }
+
+    @VisibleForTesting
+    public DreamOverlayConnectionHandler(
+            Context context,
+            Looper looper,
+            Intent serviceIntent,
+            int minConnectionDurationMs,
+            int maxReconnectAttempts,
+            int baseReconnectDelayMs,
+            Injector injector) {
+        mCallback = new OverlayConnectionCallback();
+        mHandler = new Handler(looper, new OverlayHandlerCallback());
+        mConnection = injector.buildConnection(
+                context,
+                mHandler,
+                serviceIntent,
+                minConnectionDurationMs,
+                maxReconnectAttempts,
+                baseReconnectDelayMs
+        );
+    }
+
+    /**
+     * Bind to the overlay service. If binding fails, we automatically call unbind to clean
+     * up resources.
+     *
+     * @return true if binding was successful, false otherwise.
+     */
+    public boolean bind() {
+        mConnection.addCallback(mCallback);
+        final boolean success = mConnection.bind();
+        if (!success) {
+            unbind();
+        }
+        return success;
+    }
+
+    /**
+     * Unbind from the overlay service, clearing any pending callbacks.
+     */
+    public void unbind() {
+        mConnection.removeCallback(mCallback);
+        // Remove any pending messages.
+        mHandler.removeCallbacksAndMessages(null);
+        mClient = null;
+        mConsumers.clear();
+        mConnection.unbind();
+    }
+
+    /**
+     * Adds a consumer to run once the overlay service has connected. If the overlay service
+     * disconnects (eg binding dies) and then reconnects, this consumer will be re-run unless
+     * removed.
+     *
+     * @param consumer The consumer to run. This consumer is always executed asynchronously.
+     */
+    public void addConsumer(Consumer<IDreamOverlayClient> consumer) {
+        final Message msg = mHandler.obtainMessage(MSG_ADD_CONSUMER, consumer);
+        mHandler.sendMessage(msg);
+    }
+
+    /**
+     * Removes the consumer, preventing this consumer from being called again.
+     *
+     * @param consumer The consumer to remove.
+     */
+    public void removeConsumer(Consumer<IDreamOverlayClient> consumer) {
+        final Message msg = mHandler.obtainMessage(MSG_REMOVE_CONSUMER, consumer);
+        mHandler.sendMessage(msg);
+        // Clear any pending messages to add this consumer
+        mHandler.removeMessages(MSG_ADD_CONSUMER, consumer);
+    }
+
+    private final class OverlayHandlerCallback implements Handler.Callback {
+        @Override
+        public boolean handleMessage(@NonNull Message msg) {
+            switch (msg.what) {
+                case MSG_OVERLAY_CLIENT_READY:
+                    onOverlayClientReady((IDreamOverlayClient) msg.obj);
+                    break;
+                case MSG_ADD_CONSUMER:
+                    onAddConsumer((Consumer<IDreamOverlayClient>) msg.obj);
+                    break;
+                case MSG_REMOVE_CONSUMER:
+                    onRemoveConsumer((Consumer<IDreamOverlayClient>) msg.obj);
+                    break;
+            }
+            return true;
+        }
+    }
+
+    private void onOverlayClientReady(IDreamOverlayClient client) {
+        mClient = client;
+        for (Consumer<IDreamOverlayClient> consumer : mConsumers) {
+            consumer.accept(mClient);
+        }
+    }
+
+    private void onAddConsumer(Consumer<IDreamOverlayClient> consumer) {
+        if (mClient != null) {
+            consumer.accept(mClient);
+        }
+        mConsumers.add(consumer);
+    }
+
+    private void onRemoveConsumer(Consumer<IDreamOverlayClient> consumer) {
+        mConsumers.remove(consumer);
+    }
+
+    private final class OverlayConnectionCallback implements
+            ObservableServiceConnection.Callback<IDreamOverlay> {
+
+        private final IDreamOverlayClientCallback mClientCallback =
+                new IDreamOverlayClientCallback.Stub() {
+                    @Override
+                    public void onDreamOverlayClient(IDreamOverlayClient client) {
+                        final Message msg =
+                                mHandler.obtainMessage(MSG_OVERLAY_CLIENT_READY, client);
+                        mHandler.sendMessage(msg);
+                    }
+                };
+
+        @Override
+        public void onConnected(
+                ObservableServiceConnection<IDreamOverlay> connection,
+                IDreamOverlay service) {
+            try {
+                service.getClient(mClientCallback);
+            } catch (RemoteException e) {
+                Log.e(TAG, "could not get DreamOverlayClient", e);
+            }
+        }
+
+        @Override
+        public void onDisconnected(ObservableServiceConnection<IDreamOverlay> connection,
+                int reason) {
+            mClient = null;
+            // Cancel any pending messages about the overlay being ready, since it is no
+            // longer ready.
+            mHandler.removeMessages(MSG_OVERLAY_CLIENT_READY);
+        }
+    }
+
+    /**
+     * Injector for testing
+     */
+    @VisibleForTesting
+    public static class Injector {
+        /**
+         * Returns milliseconds since boot, not counting time spent in deep sleep. Can be overridden
+         * in tests with a fake clock.
+         */
+        public PersistentServiceConnection<IDreamOverlay> buildConnection(
+                Context context,
+                Handler handler,
+                Intent serviceIntent,
+                int minConnectionDurationMs,
+                int maxReconnectAttempts,
+                int baseReconnectDelayMs) {
+            final Executor executor = handler::post;
+            final int flags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE;
+            return new PersistentServiceConnection<>(
+                    context,
+                    executor,
+                    handler,
+                    IDreamOverlay.Stub::asInterface,
+                    serviceIntent,
+                    flags,
+                    minConnectionDurationMs,
+                    maxReconnectAttempts,
+                    baseReconnectDelayMs
+            );
+        }
+    }
+}
diff --git a/core/java/android/service/dreams/DreamOverlayService.java b/core/java/android/service/dreams/DreamOverlayService.java
index 6e4535b..5469916 100644
--- a/core/java/android/service/dreams/DreamOverlayService.java
+++ b/core/java/android/service/dreams/DreamOverlayService.java
@@ -27,6 +27,8 @@
 import android.util.Log;
 import android.view.WindowManager;
 
+import java.util.concurrent.Executor;
+
 
 /**
  * Basic implementation of for {@link IDreamOverlay} for testing.
@@ -40,6 +42,12 @@
     // The last client that started dreaming and hasn't ended
     private OverlayClient mCurrentClient;
 
+    /**
+     * Executor used to run callbacks that subclasses will implement. Any calls coming over Binder
+     * from {@link OverlayClient} should perform the work they need to do on this executor.
+     */
+    private Executor mExecutor;
+
     // An {@link IDreamOverlayClient} implementation that identifies itself when forwarding
     // requests to the {@link DreamOverlayService}
     private static class OverlayClient extends IDreamOverlayClient.Stub {
@@ -61,8 +69,6 @@
             mService.startDream(this, params);
         }
 
-
-
         @Override
         public void wakeUp() {
             mService.wakeUp(this, () -> {
@@ -97,12 +103,20 @@
     }
 
     private void startDream(OverlayClient client, WindowManager.LayoutParams params) {
-        endDream(mCurrentClient);
-        mCurrentClient = client;
-        onStartDream(params);
+        // Run on executor as this is a binder call from OverlayClient.
+        mExecutor.execute(() -> {
+            endDreamInternal(mCurrentClient);
+            mCurrentClient = client;
+            onStartDream(params);
+        });
     }
 
     private void endDream(OverlayClient client) {
+        // Run on executor as this is a binder call from OverlayClient.
+        mExecutor.execute(() -> endDreamInternal(client));
+    }
+
+    private void endDreamInternal(OverlayClient client) {
         if (client == null || client != mCurrentClient) {
             return;
         }
@@ -112,11 +126,14 @@
     }
 
     private void wakeUp(OverlayClient client, Runnable callback) {
-        if (mCurrentClient != client) {
-            return;
-        }
+        // Run on executor as this is a binder call from OverlayClient.
+        mExecutor.execute(() -> {
+            if (mCurrentClient != client) {
+                return;
+            }
 
-        onWakeUp(callback);
+            onWakeUp(callback);
+        });
     }
 
     private IDreamOverlay mDreamOverlay = new IDreamOverlay.Stub() {
@@ -134,6 +151,25 @@
     public DreamOverlayService() {
     }
 
+    /**
+     * This constructor allows providing an executor to run callbacks on.
+     *
+     * @hide
+     */
+    public DreamOverlayService(@NonNull Executor executor) {
+        mExecutor = executor;
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        if (mExecutor == null) {
+            // If no executor was provided, use the main executor. onCreate is the earliest time
+            // getMainExecutor is available.
+            mExecutor = getMainExecutor();
+        }
+    }
+
     @Nullable
     @Override
     public final IBinder onBind(@NonNull Intent intent) {
@@ -143,6 +179,10 @@
     /**
      * This method is overridden by implementations to handle when the dream has started and the
      * window is ready to be interacted with.
+     *
+     * This callback will be run on the {@link Executor} provided in the constructor if provided, or
+     * on the main executor if none was provided.
+     *
      * @param layoutParams The {@link android.view.WindowManager.LayoutParams} associated with the
      *                     dream window.
      */
@@ -153,6 +193,9 @@
      * to wakeup. This allows any overlay animations to run. By default, the method will invoke
      * the callback immediately.
      *
+     * This callback will be run on the {@link Executor} provided in the constructor if provided, or
+     * on the main executor if none was provided.
+     *
      * @param onCompleteCallback The callback to trigger to notify the dream service that the
      *                           overlay has completed waking up.
      * @hide
@@ -164,6 +207,9 @@
     /**
      * This method is overridden by implementations to handle when the dream has ended. There may
      * be earlier signals leading up to this step, such as @{@link #onWakeUp(Runnable)}.
+     *
+     * This callback will be run on the {@link Executor} provided in the constructor if provided, or
+     * on the main executor if none was provided.
      */
     public void onEndDream() {
     }
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index d79ea89..9107c5f 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -68,8 +68,6 @@
 
 import com.android.internal.R;
 import com.android.internal.util.DumpUtils;
-import com.android.internal.util.ObservableServiceConnection;
-import com.android.internal.util.PersistentServiceConnection;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -77,8 +75,6 @@
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 
 /**
@@ -234,7 +230,6 @@
     private boolean mCanDoze;
     private boolean mDozing;
     private boolean mWindowless;
-    private boolean mOverlayFinishing;
     private int mDozeScreenState = Display.STATE_UNKNOWN;
     private int mDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
 
@@ -246,88 +241,7 @@
     private DreamServiceWrapper mDreamServiceWrapper;
     private Runnable mDispatchAfterOnAttachedToWindow;
 
-    private OverlayConnection mOverlayConnection;
-
-    private static class OverlayConnection extends PersistentServiceConnection<IDreamOverlay> {
-        // Retrieved Client
-        private IDreamOverlayClient mClient;
-
-        // A list of pending requests to execute on the overlay.
-        private final ArrayList<Consumer<IDreamOverlayClient>> mConsumers = new ArrayList<>();
-
-        private final IDreamOverlayClientCallback mClientCallback =
-                new IDreamOverlayClientCallback.Stub() {
-            @Override
-            public void onDreamOverlayClient(IDreamOverlayClient client) {
-                mClient = client;
-
-                for (Consumer<IDreamOverlayClient> consumer : mConsumers) {
-                    consumer.accept(mClient);
-                }
-            }
-        };
-
-        private final Callback<IDreamOverlay> mCallback = new Callback<IDreamOverlay>() {
-            @Override
-            public void onConnected(ObservableServiceConnection<IDreamOverlay> connection,
-                    IDreamOverlay service) {
-                try {
-                    service.getClient(mClientCallback);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "could not get DreamOverlayClient", e);
-                }
-            }
-
-            @Override
-            public void onDisconnected(ObservableServiceConnection<IDreamOverlay> connection,
-                    int reason) {
-                mClient = null;
-            }
-        };
-
-        OverlayConnection(Context context,
-                Executor executor,
-                Handler handler,
-                ServiceTransformer<IDreamOverlay> transformer,
-                Intent serviceIntent,
-                int flags,
-                int minConnectionDurationMs,
-                int maxReconnectAttempts,
-                int baseReconnectDelayMs) {
-            super(context, executor, handler, transformer, serviceIntent, flags,
-                    minConnectionDurationMs,
-                    maxReconnectAttempts, baseReconnectDelayMs);
-        }
-
-        @Override
-        public boolean bind() {
-            addCallback(mCallback);
-            return super.bind();
-        }
-
-        @Override
-        public void unbind() {
-            removeCallback(mCallback);
-            super.unbind();
-        }
-
-        public void addConsumer(Consumer<IDreamOverlayClient> consumer) {
-            execute(() -> {
-                mConsumers.add(consumer);
-                if (mClient != null) {
-                    consumer.accept(mClient);
-                }
-            });
-        }
-
-        public void removeConsumer(Consumer<IDreamOverlayClient> consumer) {
-            execute(() -> mConsumers.remove(consumer));
-        }
-
-        public void clearConsumers() {
-            execute(() -> mConsumers.clear());
-        }
-    }
+    private DreamOverlayConnectionHandler mOverlayConnection;
 
     private final IDreamOverlayCallback mOverlayCallback = new IDreamOverlayCallback.Stub() {
         @Override
@@ -1030,18 +944,18 @@
             final Resources resources = getResources();
             final Intent overlayIntent = new Intent().setComponent(overlayComponent);
 
-            mOverlayConnection = new OverlayConnection(
+            mOverlayConnection = new DreamOverlayConnectionHandler(
                     /* context= */ this,
-                    getMainExecutor(),
-                    mHandler,
-                    IDreamOverlay.Stub::asInterface,
+                    Looper.getMainLooper(),
                     overlayIntent,
-                    /* flags= */ Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
                     resources.getInteger(R.integer.config_minDreamOverlayDurationMs),
                     resources.getInteger(R.integer.config_dreamOverlayMaxReconnectAttempts),
                     resources.getInteger(R.integer.config_dreamOverlayReconnectTimeoutMs));
 
-            mOverlayConnection.bind();
+            if (!mOverlayConnection.bind()) {
+                // Binding failed.
+                mOverlayConnection = null;
+            }
         }
 
         return mDreamServiceWrapper;
@@ -1069,9 +983,7 @@
         // If there is an active overlay connection, signal that the dream is ending before
         // continuing. Note that the overlay cannot rely on the unbound state, since another dream
         // might have bound to it in the meantime.
-        if (mOverlayConnection != null && !mOverlayFinishing) {
-            // Set mOverlayFinish to true to only allow this consumer to be added once.
-            mOverlayFinishing = true;
+        if (mOverlayConnection != null) {
             mOverlayConnection.addConsumer(overlay -> {
                 try {
                     overlay.endDream();
@@ -1082,7 +994,6 @@
                     Log.e(mTag, "could not inform overlay of dream end:" + e);
                 }
             });
-            mOverlayConnection.clearConsumers();
             return;
         }
 
@@ -1362,6 +1273,11 @@
                 if (!ActivityTaskManager.getService().startDreamActivity(i)) {
                     detach();
                 }
+            } catch (SecurityException e) {
+                Log.w(mTag,
+                        "Received SecurityException trying to start DreamActivity. "
+                        + "Aborting dream start.");
+                detach();
             } catch (RemoteException e) {
                 Log.w(mTag, "Could not connect to activity task manager to start dream activity");
                 e.rethrowFromSystemServer();
@@ -1409,6 +1325,10 @@
                             // Request the DreamOverlay be told to dream with dream's window
                             // parameters once the window has been attached.
                             mDreamStartOverlayConsumer = overlay -> {
+                                if (mWindow == null) {
+                                    Slog.d(TAG, "mWindow is null");
+                                    return;
+                                }
                                 try {
                                     overlay.startDream(mWindow.getAttributes(), mOverlayCallback,
                                             mDreamComponent.flattenToString(),
diff --git a/core/java/android/service/quicksettings/TileService.java b/core/java/android/service/quicksettings/TileService.java
index 506b3b8..81c5796 100644
--- a/core/java/android/service/quicksettings/TileService.java
+++ b/core/java/android/service/quicksettings/TileService.java
@@ -506,7 +506,7 @@
      *     the calling package or if the calling user cannot act on behalf of the user from the
      *     {@code context}.</li>
      *     <li> {@link IllegalArgumentException} if the user of the {@code context} is not the
-     *     current user.</li>
+     *     current user. Only thrown for apps targeting {@link Build.VERSION_CODES#TIRAMISU}</li>
      * </ul>
      */
     public static final void requestListeningState(Context context, ComponentName component) {
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index e27af17..2887d1f 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -61,6 +61,7 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
@@ -96,6 +97,7 @@
 import android.view.WindowManagerGlobal;
 import android.window.ClientWindowFrames;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.HandlerCaller;
 import com.android.internal.view.BaseIWindow;
@@ -104,9 +106,10 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
+import java.util.Set;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.function.Supplier;
@@ -166,11 +169,12 @@
     private static final int MSG_RESIZE_PREVIEW = 10110;
     private static final int MSG_REPORT_SHOWN = 10150;
     private static final int MSG_UPDATE_DIMMING = 10200;
-    private static final List<Float> PROHIBITED_STEPS = Arrays.asList(0f, Float.POSITIVE_INFINITY,
-            Float.NEGATIVE_INFINITY);
 
+    /** limit calls to {@link Engine#onComputeColors} to at most once per second */
     private static final int NOTIFY_COLORS_RATE_LIMIT_MS = 1000;
-    private static final int PROCESS_LOCAL_COLORS_INTERVAL_MS = 1000;
+
+    /** limit calls to {@link Engine#processLocalColorsInternal} to at most once per 2 seconds */
+    private static final int PROCESS_LOCAL_COLORS_INTERVAL_MS = 2000;
 
     private static final boolean ENABLE_WALLPAPER_DIMMING =
             SystemProperties.getBoolean("persist.debug.enable_wallpaper_dimming", true);
@@ -180,6 +184,9 @@
     private final ArrayList<Engine> mActiveEngines
             = new ArrayList<Engine>();
 
+    private Handler mBackgroundHandler;
+    private HandlerThread mBackgroundThread;
+
     static final class WallpaperCommand {
         String action;
         int x;
@@ -198,14 +205,6 @@
      */
     public class Engine {
         IWallpaperEngineWrapper mIWallpaperEngine;
-        final ArraySet<RectF> mLocalColorAreas = new ArraySet<>(4);
-        final ArraySet<RectF> mLocalColorsToAdd = new ArraySet<>(4);
-
-        // 2D matrix [x][y] to represent a page of a portion of a window
-        EngineWindowPage[] mWindowPages = new EngineWindowPage[0];
-        Bitmap mLastScreenshot;
-        int mLastWindowPage = -1;
-        private boolean mResetWindowPages;
 
         // Copies from mIWallpaperEngine.
         HandlerCaller mCaller;
@@ -267,11 +266,34 @@
 
         final Object mLock = new Object();
         boolean mOffsetMessageEnqueued;
+
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
-        float mPendingXOffset;
-        float mPendingYOffset;
-        float mPendingXOffsetStep;
-        float mPendingYOffsetStep;
+        @GuardedBy("mLock")
+        private float mPendingXOffset;
+        @GuardedBy("mLock")
+        private float mPendingYOffset;
+        @GuardedBy("mLock")
+        private float mPendingXOffsetStep;
+        @GuardedBy("mLock")
+        private float mPendingYOffsetStep;
+
+        /**
+         * local color extraction related fields. When a user calls `addLocalColorAreas`
+         */
+        @GuardedBy("mLock")
+        private final ArraySet<RectF> mLocalColorAreas = new ArraySet<>(4);
+
+        @GuardedBy("mLock")
+        private final ArraySet<RectF> mLocalColorsToAdd = new ArraySet<>(4);
+        private long mLastProcessLocalColorsTimestamp;
+        private AtomicBoolean mProcessLocalColorsPending = new AtomicBoolean(false);
+        private int mPixelCopyCount = 0;
+        // 2D matrix [x][y] to represent a page of a portion of a window
+        @GuardedBy("mLock")
+        private EngineWindowPage[] mWindowPages = new EngineWindowPage[0];
+        private Bitmap mLastScreenshot;
+        private boolean mResetWindowPages;
+
         boolean mPendingSync;
         MotionEvent mPendingMove;
         boolean mIsInAmbientMode;
@@ -280,12 +302,8 @@
         private long mLastColorInvalidation;
         private final Runnable mNotifyColorsChanged = this::notifyColorsChanged;
 
-        // used to throttle processLocalColors
-        private long mLastProcessLocalColorsTimestamp;
-        private AtomicBoolean mProcessLocalColorsPending = new AtomicBoolean(false);
         private final Supplier<Long> mClockFunction;
         private final Handler mHandler;
-
         private Display mDisplay;
         private Context mDisplayContext;
         private int mDisplayState;
@@ -825,7 +843,7 @@
                             + "was not established.");
                 }
                 mResetWindowPages = true;
-                processLocalColors(mPendingXOffset, mPendingXOffsetStep);
+                processLocalColors();
             } catch (RemoteException e) {
                 Log.w(TAG, "Can't notify system because wallpaper connection was lost.", e);
             }
@@ -1361,10 +1379,9 @@
                         mIsCreating = false;
                         mSurfaceCreated = true;
                         if (redrawNeeded) {
-                            resetWindowPages();
                             mSession.finishDrawing(mWindow, null /* postDrawTransaction */,
                                                    Integer.MAX_VALUE);
-                            processLocalColors(mPendingXOffset, mPendingXOffsetStep);
+                            processLocalColors();
                         }
                         reposition();
                         reportEngineShown(shouldWaitForEngineShown());
@@ -1430,7 +1447,7 @@
                     com.android.internal.R.dimen.config_wallpaperDimAmount);
             mWallpaperDimAmount = mDefaultDimAmount;
             mPreviousWallpaperDimAmount = mWallpaperDimAmount;
-            mDisplayState = mDisplay.getState();
+            mDisplayState = mDisplay.getCommittedState();
             mDisplayInstallOrientation = mDisplay.getInstallOrientation();
 
             if (DEBUG) Log.v(TAG, "onCreate(): " + this);
@@ -1509,7 +1526,7 @@
             if (!mDestroyed) {
                 mVisible = visible;
                 reportVisibility();
-                if (mReportedVisible) processLocalColors(mPendingXOffset, mPendingXOffsetStep);
+                if (mReportedVisible) processLocalColors();
             } else {
                 AnimationHandler.requestAnimatorsEnabled(visible, this);
             }
@@ -1521,7 +1538,8 @@
                 return;
             }
             if (!mDestroyed) {
-                mDisplayState = mDisplay == null ? Display.STATE_UNKNOWN : mDisplay.getState();
+                mDisplayState = mDisplay == null ? Display.STATE_UNKNOWN :
+                        mDisplay.getCommittedState();
                 boolean visible = mVisible && mDisplayState != Display.STATE_OFF;
                 if (mReportedVisible != visible) {
                     mReportedVisible = visible;
@@ -1593,14 +1611,14 @@
             }
 
             // setup local color extraction data
-            processLocalColors(xOffset, xOffsetStep);
+            processLocalColors();
         }
 
         /**
          * Thread-safe util to call {@link #processLocalColorsInternal} with a minimum interval of
          * {@link #PROCESS_LOCAL_COLORS_INTERVAL_MS} between two calls.
          */
-        private void processLocalColors(float xOffset, float xOffsetStep) {
+        private void processLocalColors() {
             if (mProcessLocalColorsPending.compareAndSet(false, true)) {
                 final long now = mClockFunction.get();
                 final long timeSinceLastColorProcess = now - mLastProcessLocalColorsTimestamp;
@@ -1610,80 +1628,98 @@
                 mHandler.postDelayed(() -> {
                     mLastProcessLocalColorsTimestamp = now + timeToWait;
                     mProcessLocalColorsPending.set(false);
-                    processLocalColorsInternal(xOffset, xOffsetStep);
+                    processLocalColorsInternal();
                 }, timeToWait);
             }
         }
 
-        private void processLocalColorsInternal(float xOffset, float xOffsetStep) {
-            // implemented by the wallpaper
+        /**
+         * Default implementation of the local color extraction.
+         * This will take a screenshot of the whole wallpaper on the main thread.
+         * Then, in a background thread, for each launcher page, for each area that needs color
+         * extraction in this page, creates a sub-bitmap and call {@link WallpaperColors#fromBitmap}
+         * to extract the colors. Every time a launcher page has been processed, call
+         * {@link #notifyLocalColorsChanged} with the color and areas of this page.
+         */
+        private void processLocalColorsInternal() {
             if (supportsLocalColorExtraction()) return;
-            if (DEBUG) {
-                Log.d(TAG, "processLocalColors " + xOffset + " of step "
-                        + xOffsetStep);
-            }
-            //below is the default implementation
-            if (xOffset % xOffsetStep > MIN_PAGE_ALLOWED_MARGIN
-                    || !mSurfaceHolder.getSurface().isValid()) return;
-            int xCurrentPage;
+            float xOffset;
+            float xOffsetStep;
+            float wallpaperDimAmount;
+            int xPage;
             int xPages;
-            if (!validStep(xOffsetStep)) {
-                if (DEBUG) {
-                    Log.w(TAG, "invalid offset step " + xOffsetStep);
-                }
-                xOffset = 0;
-                xOffsetStep = 1;
-                xCurrentPage = 0;
-                xPages = 1;
-            } else {
-                xPages = Math.round(1 / xOffsetStep) + 1;
-                xOffsetStep = (float) 1 / (float) xPages;
-                float shrink = (float) (xPages - 1) / (float) xPages;
-                xOffset *= shrink;
-                xCurrentPage = Math.round(xOffset / xOffsetStep);
-            }
-            if (DEBUG) {
-                Log.d(TAG, "xPages " + xPages + " xPage " + xCurrentPage);
-                Log.d(TAG, "xOffsetStep " + xOffsetStep + " xOffset " + xOffset);
-            }
-
-            float finalXOffsetStep = xOffsetStep;
-            float finalXOffset = xOffset;
-
-            Trace.beginSection("WallpaperService#processLocalColors");
-            resetWindowPages();
-            int xPage = xCurrentPage;
+            Set<RectF> areas;
             EngineWindowPage current;
-            if (mWindowPages.length == 0 || (mWindowPages.length != xPages)) {
-                mWindowPages = new EngineWindowPage[xPages];
-                initWindowPages(mWindowPages, finalXOffsetStep);
-            }
-            if (mLocalColorsToAdd.size() != 0) {
-                for (RectF colorArea : mLocalColorsToAdd) {
-                    if (!isValid(colorArea)) continue;
-                    mLocalColorAreas.add(colorArea);
-                    int colorPage = getRectFPage(colorArea, finalXOffsetStep);
-                    EngineWindowPage currentPage = mWindowPages[colorPage];
-                    currentPage.setLastUpdateTime(0);
-                    currentPage.removeColor(colorArea);
-                }
-                mLocalColorsToAdd.clear();
-            }
-            if (xPage >= mWindowPages.length) {
+
+            synchronized (mLock) {
+                xOffset = mPendingXOffset;
+                xOffsetStep = mPendingXOffsetStep;
+                wallpaperDimAmount = mWallpaperDimAmount;
+
                 if (DEBUG) {
-                    Log.e(TAG, "error xPage >= mWindowPages.length page: " + xPage);
-                    Log.e(TAG, "error on page " + xPage + " out of " + xPages);
-                    Log.e(TAG,
-                            "error on xOffsetStep " + finalXOffsetStep
-                                    + " xOffset " + finalXOffset);
+                    Log.d(TAG, "processLocalColors " + xOffset + " of step "
+                            + xOffsetStep);
                 }
-                xPage = mWindowPages.length - 1;
+                if (xOffset % xOffsetStep > MIN_PAGE_ALLOWED_MARGIN
+                        || !mSurfaceHolder.getSurface().isValid()) return;
+                int xCurrentPage;
+                if (!validStep(xOffsetStep)) {
+                    if (DEBUG) {
+                        Log.w(TAG, "invalid offset step " + xOffsetStep);
+                    }
+                    xOffset = 0;
+                    xOffsetStep = 1;
+                    xCurrentPage = 0;
+                    xPages = 1;
+                } else {
+                    xPages = Math.round(1 / xOffsetStep) + 1;
+                    xOffsetStep = (float) 1 / (float) xPages;
+                    float shrink = (float) (xPages - 1) / (float) xPages;
+                    xOffset *= shrink;
+                    xCurrentPage = Math.round(xOffset / xOffsetStep);
+                }
+                if (DEBUG) {
+                    Log.d(TAG, "xPages " + xPages + " xPage " + xCurrentPage);
+                    Log.d(TAG, "xOffsetStep " + xOffsetStep + " xOffset " + xOffset);
+                }
+
+                float finalXOffsetStep = xOffsetStep;
+                float finalXOffset = xOffset;
+
+                resetWindowPages();
+                xPage = xCurrentPage;
+                if (mWindowPages.length == 0 || (mWindowPages.length != xPages)) {
+                    mWindowPages = new EngineWindowPage[xPages];
+                    initWindowPages(mWindowPages, finalXOffsetStep);
+                }
+                if (mLocalColorsToAdd.size() != 0) {
+                    for (RectF colorArea : mLocalColorsToAdd) {
+                        if (!isValid(colorArea)) continue;
+                        mLocalColorAreas.add(colorArea);
+                        int colorPage = getRectFPage(colorArea, finalXOffsetStep);
+                        EngineWindowPage currentPage = mWindowPages[colorPage];
+                        currentPage.setLastUpdateTime(0);
+                        currentPage.removeColor(colorArea);
+                    }
+                    mLocalColorsToAdd.clear();
+                }
+                if (xPage >= mWindowPages.length) {
+                    if (DEBUG) {
+                        Log.e(TAG, "error xPage >= mWindowPages.length page: " + xPage);
+                        Log.e(TAG, "error on page " + xPage + " out of " + xPages);
+                        Log.e(TAG,
+                                "error on xOffsetStep " + finalXOffsetStep
+                                        + " xOffset " + finalXOffset);
+                    }
+                    xPage = mWindowPages.length - 1;
+                }
+                current = mWindowPages[xPage];
+                areas = new HashSet<>(current.getAreas());
             }
-            current = mWindowPages[xPage];
-            updatePage(current, xPage, xPages, finalXOffsetStep);
-            Trace.endSection();
+            updatePage(current, areas, xPage, xPages, wallpaperDimAmount);
         }
 
+        @GuardedBy("mLock")
         private void initWindowPages(EngineWindowPage[] windowPages, float step) {
             for (int i = 0; i < windowPages.length; i++) {
                 windowPages[i] = new EngineWindowPage();
@@ -1700,16 +1736,16 @@
             }
         }
 
-        void updatePage(EngineWindowPage currentPage, int pageIndx, int numPages,
-                float xOffsetStep) {
+        void updatePage(EngineWindowPage currentPage, Set<RectF> areas, int pageIndx, int numPages,
+                float wallpaperDimAmount) {
+
             // in case the clock is zero, we start with negative time
             long current = SystemClock.elapsedRealtime() - DEFAULT_UPDATE_SCREENSHOT_DURATION;
             long lapsed = current - currentPage.getLastUpdateTime();
             // Always update the page when the last update time is <= 0
             // This is important especially when the device first boots
-            if (lapsed < DEFAULT_UPDATE_SCREENSHOT_DURATION) {
-                return;
-            }
+            if (lapsed < DEFAULT_UPDATE_SCREENSHOT_DURATION) return;
+
             Surface surface = mSurfaceHolder.getSurface();
             if (!surface.isValid()) return;
             boolean widthIsLarger = mSurfaceSize.x > mSurfaceSize.y;
@@ -1722,43 +1758,59 @@
                 Log.e(TAG, "wrong width and height values of bitmap " + width + " " + height);
                 return;
             }
+            final String pixelCopySectionName = "WallpaperService#pixelCopy";
+            final int pixelCopyCount = mPixelCopyCount++;
+            Trace.beginAsyncSection(pixelCopySectionName, pixelCopyCount);
             Bitmap screenShot = Bitmap.createBitmap(width, height,
                     Bitmap.Config.ARGB_8888);
             final Bitmap finalScreenShot = screenShot;
-            Trace.beginSection("WallpaperService#pixelCopy");
-            PixelCopy.request(surface, screenShot, (res) -> {
-                Trace.endSection();
-                if (DEBUG) Log.d(TAG, "result of pixel copy is " + res);
-                if (res != PixelCopy.SUCCESS) {
-                    Bitmap lastBitmap = currentPage.getBitmap();
-                    // assign the last bitmap taken for now
-                    currentPage.setBitmap(mLastScreenshot);
-                    Bitmap lastScreenshot = mLastScreenshot;
-                    if (lastScreenshot != null && !lastScreenshot.isRecycled()
-                            && !Objects.equals(lastBitmap, lastScreenshot)) {
-                        updatePageColors(currentPage, pageIndx, numPages, xOffsetStep);
+            try {
+                // TODO(b/274427458) check if this can be done in the background.
+                PixelCopy.request(surface, screenShot, (res) -> {
+                    Trace.endAsyncSection(pixelCopySectionName, pixelCopyCount);
+                    if (DEBUG) {
+                        Log.d(TAG, "result of pixel copy is: "
+                                + (res == PixelCopy.SUCCESS ? "SUCCESS" : "FAILURE"));
                     }
-                } else {
-                    mLastScreenshot = finalScreenShot;
-                    // going to hold this lock for a while
-                    currentPage.setBitmap(finalScreenShot);
-                    currentPage.setLastUpdateTime(current);
-                    updatePageColors(currentPage, pageIndx, numPages, xOffsetStep);
-                }
-            }, mHandler);
-
+                    if (res != PixelCopy.SUCCESS) {
+                        Bitmap lastBitmap = currentPage.getBitmap();
+                        // assign the last bitmap taken for now
+                        currentPage.setBitmap(mLastScreenshot);
+                        Bitmap lastScreenshot = mLastScreenshot;
+                        if (lastScreenshot != null && !Objects.equals(lastBitmap, lastScreenshot)) {
+                            updatePageColors(
+                                    currentPage, areas, pageIndx, numPages, wallpaperDimAmount);
+                        }
+                    } else {
+                        mLastScreenshot = finalScreenShot;
+                        currentPage.setBitmap(finalScreenShot);
+                        currentPage.setLastUpdateTime(current);
+                        updatePageColors(
+                                currentPage, areas, pageIndx, numPages, wallpaperDimAmount);
+                    }
+                }, mBackgroundHandler);
+            } catch (IllegalArgumentException e) {
+                // this can potentially happen if the surface is invalidated right between the
+                // surface.isValid() check and the PixelCopy operation.
+                // in this case, stop: we'll compute colors on the next processLocalColors call.
+                Log.w(TAG, "Cancelling processLocalColors: exception caught during PixelCopy");
+            }
         }
         // locked by the passed page
-        private void updatePageColors(EngineWindowPage page, int pageIndx, int numPages,
-                float xOffsetStep) {
+        private void updatePageColors(EngineWindowPage page, Set<RectF> areas,
+                int pageIndx, int numPages, float wallpaperDimAmount) {
             if (page.getBitmap() == null) return;
+            if (!mBackgroundHandler.getLooper().isCurrentThread()) {
+                throw new IllegalStateException(
+                        "ProcessLocalColors should be called from the background thread");
+            }
             Trace.beginSection("WallpaperService#updatePageColors");
             if (DEBUG) {
                 Log.d(TAG, "updatePageColorsLocked for page " + pageIndx + " with areas "
                         + page.getAreas().size() + " and bitmap size of "
                         + page.getBitmap().getWidth() + " x " + page.getBitmap().getHeight());
             }
-            for (RectF area: page.getAreas()) {
+            for (RectF area: areas) {
                 if (area == null) continue;
                 RectF subArea = generateSubRect(area, pageIndx, numPages);
                 Bitmap b = page.getBitmap();
@@ -1768,12 +1820,12 @@
                 int height = Math.round(b.getHeight() * subArea.height());
                 Bitmap target;
                 try {
-                    target = Bitmap.createBitmap(page.getBitmap(), x, y, width, height);
+                    target = Bitmap.createBitmap(b, x, y, width, height);
                 } catch (Exception e) {
                     Log.e(TAG, "Error creating page local color bitmap", e);
                     continue;
                 }
-                WallpaperColors color = WallpaperColors.fromBitmap(target, mWallpaperDimAmount);
+                WallpaperColors color = WallpaperColors.fromBitmap(target, wallpaperDimAmount);
                 target.recycle();
                 WallpaperColors currentColor = page.getColors(area);
 
@@ -1790,12 +1842,14 @@
                                 + " local color callback for area" + area + " for page " + pageIndx
                                 + " of " + numPages);
                     }
-                    try {
-                        mConnection.onLocalWallpaperColorsChanged(area, color,
-                                mDisplayContext.getDisplayId());
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Error calling Connection.onLocalWallpaperColorsChanged", e);
-                    }
+                    mHandler.post(() -> {
+                        try {
+                            mConnection.onLocalWallpaperColorsChanged(area, color,
+                                    mDisplayContext.getDisplayId());
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "Error calling Connection.onLocalWallpaperColorsChanged", e);
+                        }
+                    });
                 }
             }
             Trace.endSection();
@@ -1821,16 +1875,17 @@
             return new RectF(left, in.top, right, in.bottom);
         }
 
+        @GuardedBy("mLock")
         private void resetWindowPages() {
             if (supportsLocalColorExtraction()) return;
             if (!mResetWindowPages) return;
             mResetWindowPages = false;
-            mLastWindowPage = -1;
             for (int i = 0; i < mWindowPages.length; i++) {
                 mWindowPages[i].setLastUpdateTime(0L);
             }
         }
 
+        @GuardedBy("mLock")
         private int getRectFPage(RectF area, float step) {
             if (!isValid(area)) return 0;
             if (!validStep(step)) return 0;
@@ -1851,12 +1906,12 @@
             if (DEBUG) {
                 Log.d(TAG, "addLocalColorsAreas adding local color areas " + regions);
             }
-            mHandler.post(() -> {
-                mLocalColorsToAdd.addAll(regions);
-                processLocalColors(mPendingXOffset, mPendingYOffset);
+            mBackgroundHandler.post(() -> {
+                synchronized (mLock) {
+                    mLocalColorsToAdd.addAll(regions);
+                }
+                processLocalColors();
             });
-
-
         }
 
         /**
@@ -1866,16 +1921,18 @@
          */
         public void removeLocalColorsAreas(@NonNull List<RectF> regions) {
             if (supportsLocalColorExtraction()) return;
-            mHandler.post(() -> {
-                float step = mPendingXOffsetStep;
-                mLocalColorsToAdd.removeAll(regions);
-                mLocalColorAreas.removeAll(regions);
-                if (!validStep(step)) {
-                    return;
-                }
-                for (int i = 0; i < mWindowPages.length; i++) {
-                    for (int j = 0; j < regions.size(); j++) {
-                        mWindowPages[i].removeArea(regions.get(j));
+            mBackgroundHandler.post(() -> {
+                synchronized (mLock) {
+                    float step = mPendingXOffsetStep;
+                    mLocalColorsToAdd.removeAll(regions);
+                    mLocalColorAreas.removeAll(regions);
+                    if (!validStep(step)) {
+                        return;
+                    }
+                    for (int i = 0; i < mWindowPages.length; i++) {
+                        for (int j = 0; j < regions.size(); j++) {
+                            mWindowPages[i].removeArea(regions.get(j));
+                        }
                     }
                 }
             });
@@ -1893,7 +1950,7 @@
         }
 
         private boolean validStep(float step) {
-            return !PROHIBITED_STEPS.contains(step) && step > 0. && step <= 1.;
+            return !Float.isNaN(step) && step > 0f && step <= 1f;
         }
 
         void doCommand(WallpaperCommand cmd) {
@@ -2497,6 +2554,9 @@
     @Override
     public void onCreate() {
         Trace.beginSection("WPMS.onCreate");
+        mBackgroundThread = new HandlerThread("DefaultWallpaperLocalColorExtractor");
+        mBackgroundThread.start();
+        mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
         super.onCreate();
         Trace.endSection();
     }
@@ -2509,6 +2569,7 @@
             mActiveEngines.get(i).detach();
         }
         mActiveEngines.clear();
+        mBackgroundThread.quitSafely();
         Trace.endSection();
     }
 
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 52d222b..f85f906 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -1600,6 +1600,21 @@
     }
 
     /**
+     * Returns the committed state of the display.
+     *
+     * @return The latest committed display state, such as {@link #STATE_ON}. The display state
+     * {@link Display#getState()} is set as committed only after power state changes finish.
+     *
+     * @hide
+     */
+    public int getCommittedState() {
+        synchronized (mLock) {
+            updateDisplayInfoLocked();
+            return mIsValid ? mDisplayInfo.committedState : STATE_UNKNOWN;
+        }
+    }
+
+    /**
      * Returns true if the specified UID has access to this display.
      * @hide
      */
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 12ce8ee..f65a69a 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -253,6 +253,12 @@
     public int state;
 
     /**
+     * The current committed state of the display. For example, this becomes
+     * {@link android.view.Display#STATE_ON} only after the power state ON is fully committed.
+     */
+    public int committedState;
+
+    /**
      * The UID of the application that owns this display, or zero if it is owned by the system.
      * <p>
      * If the display is private, then only the owner can use it.
@@ -380,6 +386,7 @@
                 && appVsyncOffsetNanos == other.appVsyncOffsetNanos
                 && presentationDeadlineNanos == other.presentationDeadlineNanos
                 && state == other.state
+                && committedState == other.committedState
                 && ownerUid == other.ownerUid
                 && Objects.equals(ownerPackageName, other.ownerPackageName)
                 && removeMode == other.removeMode
@@ -431,6 +438,7 @@
         appVsyncOffsetNanos = other.appVsyncOffsetNanos;
         presentationDeadlineNanos = other.presentationDeadlineNanos;
         state = other.state;
+        committedState = other.committedState;
         ownerUid = other.ownerUid;
         ownerPackageName = other.ownerPackageName;
         removeMode = other.removeMode;
@@ -482,6 +490,7 @@
         appVsyncOffsetNanos = source.readLong();
         presentationDeadlineNanos = source.readLong();
         state = source.readInt();
+        committedState = source.readInt();
         ownerUid = source.readInt();
         ownerPackageName = source.readString8();
         uniqueId = source.readString8();
@@ -538,6 +547,7 @@
         dest.writeLong(appVsyncOffsetNanos);
         dest.writeLong(presentationDeadlineNanos);
         dest.writeInt(state);
+        dest.writeInt(committedState);
         dest.writeInt(ownerUid);
         dest.writeString8(ownerPackageName);
         dest.writeString8(uniqueId);
@@ -761,6 +771,8 @@
         sb.append(rotation);
         sb.append(", state ");
         sb.append(Display.stateToString(state));
+        sb.append(", committedState ");
+        sb.append(Display.stateToString(committedState));
 
         if (Process.myUid() != Process.SYSTEM_UID) {
             sb.append("}");
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index d7480e5..543a22b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -8774,7 +8774,8 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public void getBoundsOnScreen(Rect outRect, boolean clipToParent) {
+    @TestApi
+    public void getBoundsOnScreen(@NonNull Rect outRect, boolean clipToParent) {
         if (mAttachInfo == null) {
             return;
         }
@@ -8782,6 +8783,9 @@
         getBoundsToScreenInternal(position, clipToParent);
         outRect.set(Math.round(position.left), Math.round(position.top),
                 Math.round(position.right), Math.round(position.bottom));
+        // If "Sandboxing View Bounds APIs" override is enabled, applyViewBoundsSandboxingIfNeeded
+        // will sandbox outRect within window bounds.
+        mAttachInfo.mViewRootImpl.applyViewBoundsSandboxingIfNeeded(outRect);
     }
 
     /**
@@ -15586,7 +15590,8 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public void getWindowDisplayFrame(Rect outRect) {
+    @TestApi
+    public void getWindowDisplayFrame(@NonNull Rect outRect) {
         if (mAttachInfo != null) {
             mAttachInfo.mViewRootImpl.getDisplayFrame(outRect);
             return;
@@ -25786,6 +25791,9 @@
         if (info != null) {
             outLocation[0] += info.mWindowLeft;
             outLocation[1] += info.mWindowTop;
+            // If OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS override is enabled,
+            // applyViewLocationSandboxingIfNeeded sandboxes outLocation within window bounds.
+            info.mViewRootImpl.applyViewLocationSandboxingIfNeeded(outLocation);
         }
     }
 
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index f9e8411..f6211fd 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import static android.content.pm.ActivityInfo.OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS;
 import static android.graphics.HardwareRenderer.SYNC_CONTEXT_IS_STOPPED;
 import static android.graphics.HardwareRenderer.SYNC_LOST_SURFACE_REWARD_IF_FOUND;
 import static android.os.IInputConstants.INVALID_INPUT_EVENT_ID;
@@ -82,6 +83,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
 import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
+import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS;
 import static android.view.WindowManagerGlobal.RELAYOUT_RES_CANCEL_AND_REDRAW;
 import static android.view.WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS;
 import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
@@ -94,12 +96,14 @@
 import android.annotation.AnyThread;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.Size;
 import android.annotation.UiContext;
 import android.app.ActivityManager;
 import android.app.ActivityThread;
 import android.app.ICompatCameraControlCallback;
 import android.app.ResourcesManager;
 import android.app.WindowConfiguration;
+import android.app.compat.CompatChanges;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ClipData;
 import android.content.ClipDescription;
@@ -871,6 +875,15 @@
 
     private boolean mRelayoutRequested;
 
+    /**
+     * Whether sandboxing of {@link android.view.View#getBoundsOnScreen},
+     * {@link android.view.View#getLocationOnScreen(int[])},
+     * {@link android.view.View#getWindowDisplayFrame} and
+     * {@link android.view.View#getWindowVisibleDisplayFrame}
+     * within Activity bounds is enabled for the current application.
+     */
+    private final boolean mViewBoundsSandboxingEnabled;
+
     private int mLastTransformHint = Integer.MIN_VALUE;
 
     /**
@@ -958,6 +971,8 @@
         mHandwritingInitiator = new HandwritingInitiator(mViewConfiguration,
                 mContext.getSystemService(InputMethodManager.class));
 
+        mViewBoundsSandboxingEnabled = getViewBoundsSandboxingEnabled();
+
         String processorOverrideName = context.getResources().getString(
                                     R.string.config_inputEventCompatProcessorOverrideClassName);
         if (processorOverrideName.isEmpty()) {
@@ -8426,6 +8441,9 @@
      */
     void getDisplayFrame(Rect outFrame) {
         outFrame.set(mTmpFrames.displayFrame);
+        // Apply sandboxing here (in getter) due to possible layout updates on the client after
+        // mTmpFrames.displayFrame is received from the server.
+        applyViewBoundsSandboxingIfNeeded(outFrame);
     }
 
     /**
@@ -8442,6 +8460,69 @@
         outFrame.top += insets.top;
         outFrame.right -= insets.right;
         outFrame.bottom -= insets.bottom;
+        // Apply sandboxing here (in getter) due to possible layout updates on the client after
+        // mTmpFrames.displayFrame is received from the server.
+        applyViewBoundsSandboxingIfNeeded(outFrame);
+    }
+
+    /**
+     * Offset outRect to make it sandboxed within Window's bounds.
+     *
+     * <p>This is used by {@link android.view.View#getBoundsOnScreen},
+     * {@link android.view.ViewRootImpl#getDisplayFrame} and
+     * {@link android.view.ViewRootImpl#getWindowVisibleDisplayFrame}, which are invoked by
+     * {@link android.view.View#getWindowDisplayFrame} and
+     * {@link android.view.View#getWindowVisibleDisplayFrame}, as well as
+     * {@link android.view.ViewDebug#captureLayers} for debugging.
+     */
+    void applyViewBoundsSandboxingIfNeeded(final Rect inOutRect) {
+        if (mViewBoundsSandboxingEnabled) {
+            final Rect bounds = getConfiguration().windowConfiguration.getBounds();
+            inOutRect.offset(-bounds.left, -bounds.top);
+        }
+    }
+
+    /**
+     * Offset outLocation to make it sandboxed within Window's bounds.
+     *
+     * <p>This is used by {@link android.view.View#getLocationOnScreen(int[])}
+     */
+    public void applyViewLocationSandboxingIfNeeded(@Size(2) int[] outLocation) {
+        if (mViewBoundsSandboxingEnabled) {
+            final Rect bounds = getConfiguration().windowConfiguration.getBounds();
+            outLocation[0] -= bounds.left;
+            outLocation[1] -= bounds.top;
+        }
+    }
+
+    private boolean getViewBoundsSandboxingEnabled() {
+        // System dialogs (e.g. ANR) can be created within System process, so handleBindApplication
+        // may be never called. This results into all app compat changes being enabled
+        // (see b/268007823) because AppCompatCallbacks.install() is never called with non-empty
+        // array.
+        // With ActivityThread.isSystem we verify that it is not the system process,
+        // then this CompatChange can take effect.
+        if (ActivityThread.isSystem()
+                || !CompatChanges.isChangeEnabled(OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS)) {
+            // It is a system process or OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS change-id is disabled.
+            return false;
+        }
+
+        // OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS is enabled by the device manufacturer.
+        try {
+            final List<PackageManager.Property> properties = mContext.getPackageManager()
+                    .queryApplicationProperty(PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS);
+
+            final boolean isOptedOut = !properties.isEmpty() && !properties.get(0).getBoolean();
+            if (isOptedOut) {
+                // PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS is disabled by the app devs.
+                return false;
+            }
+        } catch (RuntimeException e) {
+            // remote exception.
+        }
+
+        return true;
     }
 
     /**
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 02027e4..293f9082 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -823,6 +823,11 @@
     /** @hide */
     public final void destroy() {
         mDestroyed = true;
+        onDestroy();
+    }
+
+    /** @hide */
+    protected void onDestroy() {
     }
 
     /** @hide */
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 17df585..a01c832 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -854,6 +854,42 @@
 
     /**
      * Application level {@link android.content.pm.PackageManager.Property PackageManager
+     * .Property} for an app to inform the system that it needs to be opted-out from the
+     * compatibility treatment that sandboxes {@link android.view.View} API.
+     *
+     * <p>The treatment can be enabled by device manufacturers for applications which misuse
+     * {@link android.view.View} APIs by expecting that
+     * {@link android.view.View#getLocationOnScreen},
+     * {@link android.view.View#getBoundsOnScreen},
+     * {@link android.view.View#getWindowVisibleDisplayFrame},
+     * {@link android.view.View#getWindowDisplayFrame}
+     * return coordinates as if an activity is positioned in the top-left corner of the screen, with
+     * left coordinate equal to 0. This may not be the case for applications in multi-window and in
+     * letterbox modes.
+     *
+     * <p>Setting this property to {@code false} informs the system that the application must be
+     * opted-out from the "Sandbox {@link android.view.View} API to Activity bounds" treatment even
+     * if the device manufacturer has opted the app into the treatment.
+     *
+     * <p>Not setting this property at all, or setting this property to {@code true} has no effect.
+     *
+     * <p><b>Syntax:</b>
+     * <pre>
+     * &lt;application&gt;
+     *   &lt;property
+     *     android:name="android.window.PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS"
+     *     android:value="false"/&gt;
+     * &lt;/application&gt;
+     * </pre>
+     *
+     * @hide
+     */
+    // TODO(b/263984287): Make this public API.
+    String PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS =
+            "android.window.PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS";
+
+    /**
+     * Application level {@link android.content.pm.PackageManager.Property PackageManager
      * .Property} for an app to inform the system that the application can be opted-in or opted-out
      * from the compatibility treatment that enables sending a fake focus event for unfocused
      * resumed split screen activities. This is needed because some game engines wait to get
diff --git a/core/java/android/view/contentcapture/ContentCaptureContext.java b/core/java/android/view/contentcapture/ContentCaptureContext.java
index 59b5286..34c7b8b 100644
--- a/core/java/android/view/contentcapture/ContentCaptureContext.java
+++ b/core/java/android/view/contentcapture/ContentCaptureContext.java
@@ -82,11 +82,19 @@
     @SystemApi
     public static final int FLAG_RECONNECTED = 0x4;
 
+    /**
+     * Flag used to disable flush when receiving a VIEW_TREE_APPEARING event.
+     *
+     * @hide
+     */
+    public static final int FLAG_DISABLED_FLUSH_FOR_VIEW_TREE_APPEARING = 1 << 3;
+
     /** @hide */
     @IntDef(flag = true, prefix = { "FLAG_" }, value = {
             FLAG_DISABLED_BY_APP,
             FLAG_DISABLED_BY_FLAG_SECURE,
-            FLAG_RECONNECTED
+            FLAG_RECONNECTED,
+            FLAG_DISABLED_FLUSH_FOR_VIEW_TREE_APPEARING
     })
     @Retention(RetentionPolicy.SOURCE)
     @interface ContextCreationFlags{}
@@ -252,7 +260,8 @@
      * Gets the flags associated with this context.
      *
      * @return any combination of {@link #FLAG_DISABLED_BY_FLAG_SECURE},
-     * {@link #FLAG_DISABLED_BY_APP} and {@link #FLAG_RECONNECTED}.
+     * {@link #FLAG_DISABLED_BY_APP}, {@link #FLAG_RECONNECTED} and {@link
+     * #FLAG_DISABLED_FLUSH_FOR_VIEW_TREE_APPEARING}.
      *
      * @hide
      */
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 497f066..668351b 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -51,6 +51,7 @@
 import android.view.contentcapture.ContentCaptureSession.FlushReason;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.SyncResultReceiver;
 
 import java.io.PrintWriter;
@@ -343,6 +344,14 @@
      */
     public static final String DEVICE_CONFIG_PROPERTY_IDLE_UNBIND_TIMEOUT = "idle_unbind_timeout";
 
+    /**
+     * Sets to disable flush when receiving a VIEW_TREE_APPEARING event.
+     *
+     * @hide
+     */
+    public static final String DEVICE_CONFIG_PROPERTY_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING =
+            "disable_flush_for_view_tree_appearing";
+
     /** @hide */
     @TestApi
     public static final int LOGGING_LEVEL_OFF = 0;
@@ -373,6 +382,8 @@
     public static final int DEFAULT_TEXT_CHANGE_FLUSHING_FREQUENCY_MS = 1_000;
     /** @hide */
     public static final int DEFAULT_LOG_HISTORY_SIZE = 10;
+    /** @hide */
+    public static final boolean DEFAULT_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING = false;
 
     private final Object mLock = new Object();
 
@@ -448,6 +459,7 @@
         mOptions = Objects.requireNonNull(options, "options cannot be null");
 
         ContentCaptureHelper.setLoggingLevel(mOptions.loggingLevel);
+        setFlushViewTreeAppearingEventDisabled(mOptions.disableFlushForViewTreeAppearing);
 
         if (sVerbose) Log.v(TAG, "Constructor for " + context.getPackageName());
 
@@ -687,6 +699,38 @@
     }
 
     /**
+     * Explicitly sets enable or disable flush for view tree appearing event.
+     *
+     * @hide
+     */
+    @VisibleForTesting
+    public void setFlushViewTreeAppearingEventDisabled(boolean disabled) {
+        if (sDebug) {
+            Log.d(TAG, "setFlushViewTreeAppearingEventDisabled(): setting to " + disabled);
+        }
+
+        synchronized (mLock) {
+            if (disabled) {
+                mFlags |= ContentCaptureContext.FLAG_DISABLED_FLUSH_FOR_VIEW_TREE_APPEARING;
+            } else {
+                mFlags &= ~ContentCaptureContext.FLAG_DISABLED_FLUSH_FOR_VIEW_TREE_APPEARING;
+            }
+        }
+    }
+
+    /**
+     * Gets whether content capture is needed to flush for view tree appearing event.
+     *
+     * @hide
+     */
+    public boolean getFlushViewTreeAppearingEventDisabled() {
+        synchronized (mLock) {
+            return (mFlags & ContentCaptureContext.FLAG_DISABLED_FLUSH_FOR_VIEW_TREE_APPEARING)
+                    != 0;
+        }
+    }
+
+    /**
      * Gets whether content capture is enabled for the given user.
      *
      * <p>This method is typically used by the content capture service settings page, so it can
diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java
index 2134d81..bdec197 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -170,6 +170,12 @@
     public static final int FLUSH_REASON_TEXT_CHANGE_TIMEOUT = 6;
     /** @hide */
     public static final int FLUSH_REASON_SESSION_CONNECTED = 7;
+    /** @hide */
+    public static final int FLUSH_REASON_FORCE_FLUSH = 8;
+    /** @hide */
+    public static final int FLUSH_REASON_VIEW_TREE_APPEARING = 9;
+    /** @hide */
+    public static final int FLUSH_REASON_VIEW_TREE_APPEARED = 10;
 
     /** @hide */
     @IntDef(prefix = { "FLUSH_REASON_" }, value = {
@@ -179,7 +185,10 @@
             FLUSH_REASON_SESSION_FINISHED,
             FLUSH_REASON_IDLE_TIMEOUT,
             FLUSH_REASON_TEXT_CHANGE_TIMEOUT,
-            FLUSH_REASON_SESSION_CONNECTED
+            FLUSH_REASON_SESSION_CONNECTED,
+            FLUSH_REASON_FORCE_FLUSH,
+            FLUSH_REASON_VIEW_TREE_APPEARING,
+            FLUSH_REASON_VIEW_TREE_APPEARED
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface FlushReason{}
@@ -614,6 +623,12 @@
                 return "TEXT_CHANGE";
             case FLUSH_REASON_SESSION_CONNECTED:
                 return "CONNECTED";
+            case FLUSH_REASON_FORCE_FLUSH:
+                return "FORCE_FLUSH";
+            case FLUSH_REASON_VIEW_TREE_APPEARING:
+                return "VIEW_TREE_APPEARING";
+            case FLUSH_REASON_VIEW_TREE_APPEARED:
+                return "VIEW_TREE_APPEARED";
             default:
                 return "UNKOWN-" + reason;
         }
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index 1f5e462..9848acd 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -458,6 +458,12 @@
             case ContentCaptureEvent.TYPE_SESSION_FINISHED:
                 flushReason = FLUSH_REASON_SESSION_FINISHED;
                 break;
+            case ContentCaptureEvent.TYPE_VIEW_TREE_APPEARING:
+                flushReason = FLUSH_REASON_VIEW_TREE_APPEARING;
+                break;
+            case ContentCaptureEvent.TYPE_VIEW_TREE_APPEARED:
+                flushReason = FLUSH_REASON_VIEW_TREE_APPEARED;
+                break;
             default:
                 flushReason = FLUSH_REASON_FULL;
         }
@@ -764,7 +770,11 @@
     /** Public because is also used by ViewRootImpl */
     public void notifyViewTreeEvent(int sessionId, boolean started) {
         final int type = started ? TYPE_VIEW_TREE_APPEARING : TYPE_VIEW_TREE_APPEARED;
-        mHandler.post(() -> sendEvent(new ContentCaptureEvent(sessionId, type), FORCE_FLUSH));
+        final boolean disableFlush = mManager.getFlushViewTreeAppearingEventDisabled();
+
+        mHandler.post(() -> sendEvent(
+                new ContentCaptureEvent(sessionId, type),
+                disableFlush ? !started : FORCE_FLUSH));
     }
 
     void notifySessionResumed(int sessionId) {
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index ca57c84..fceee4e 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -189,6 +189,9 @@
 
     /**
      * Show the view for the specified duration.
+     *
+     * <p>Note that toasts being sent from the background are rate limited, so avoid sending such
+     * toasts in quick succession.
      */
     public void show() {
         if (Compatibility.isChangeEnabled(CHANGE_TEXT_TOASTS_IN_THE_SYSTEM)) {
diff --git a/core/java/android/window/ITaskOrganizerController.aidl b/core/java/android/window/ITaskOrganizerController.aidl
index 0032b9c..e10f7c8 100644
--- a/core/java/android/window/ITaskOrganizerController.aidl
+++ b/core/java/android/window/ITaskOrganizerController.aidl
@@ -73,11 +73,17 @@
 
     /**
      * Controls whether ignore orientation request logic in {@link
-     * com.android.server.wm.DisplayArea} is disabled at runtime.
+     * com.android.server.wm.DisplayArea} is disabled at runtime and how to optionally map some
+     * requested orientations to others.
      *
      * @param isDisabled when {@code true}, the system always ignores the value of {@link
      *                   com.android.server.wm.DisplayArea#getIgnoreOrientationRequest} and app
      *                   requested orientation is respected.
+     * @param fromOrientations The orientations we want to map to the correspondent orientations
+     *                        in toOrientation.
+     * @param toOrientations The orientations we map to the ones in fromOrientations at the same
+     *                       index
      */
-     void setIsIgnoreOrientationRequestDisabled(boolean isDisabled);
+     void setOrientationRequestPolicy(boolean isIgnoreOrientationRequestDisabled,
+            in int[] fromOrientations, in int[] toOrientations);
 }
diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java
index 02878f8..3aa9941 100644
--- a/core/java/android/window/TaskOrganizer.java
+++ b/core/java/android/window/TaskOrganizer.java
@@ -270,17 +270,24 @@
 
     /**
      * Controls whether ignore orientation request logic in {@link
-     * com.android.server.wm.DisplayArea} is disabled at runtime.
+     * com.android.server.wm.DisplayArea} is disabled at runtime and how to optionally map some
+     * requested orientation to others.
      *
-     * @param isDisabled when {@code true}, the system always ignores the value of {@link
-     *                   com.android.server.wm.DisplayArea#getIgnoreOrientationRequest} and app
-     *                   requested orientation is respected.
+     * @param isIgnoreOrientationRequestDisabled when {@code true}, the system always ignores the
+     *           value of  {@link com.android.server.wm.DisplayArea#getIgnoreOrientationRequest}
+     *           and app requested orientation is respected.
+     * @param fromOrientations The orientations we want to map to the correspondent orientations
+     *                        in toOrientation.
+     * @param toOrientations The orientations we map to the ones in fromOrientations at the same
+     *                       index
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
-    public void setIsIgnoreOrientationRequestDisabled(boolean isDisabled) {
+    public void setOrientationRequestPolicy(boolean isIgnoreOrientationRequestDisabled,
+            @Nullable int[] fromOrientations, @Nullable int[] toOrientations) {
         try {
-            mTaskOrganizerController.setIsIgnoreOrientationRequestDisabled(isDisabled);
+            mTaskOrganizerController.setOrientationRequestPolicy(isIgnoreOrientationRequestDisabled,
+                    fromOrientations, toOrientations);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index d7b4929..0a600ea 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -122,6 +122,19 @@
     }
 
     /**
+     * Sets the densityDpi value in the configuration for the given container.
+     * @hide
+     */
+    @NonNull
+    public WindowContainerTransaction setDensityDpi(@NonNull WindowContainerToken container,
+            int densityDpi) {
+        Change chg = getOrCreateChange(container.asBinder());
+        chg.mConfiguration.densityDpi = densityDpi;
+        chg.mConfigSetMask |= ActivityInfo.CONFIG_DENSITY;
+        return this;
+    }
+
+    /**
      * Notify {@link com.android.server.wm.PinnedTaskController} that the picture-in-picture task
      * has finished the enter animation with the given bounds.
      */
diff --git a/core/java/com/android/internal/app/procstats/DumpUtils.java b/core/java/com/android/internal/app/procstats/DumpUtils.java
index bce0d60..f6bcc46 100644
--- a/core/java/com/android/internal/app/procstats/DumpUtils.java
+++ b/core/java/com/android/internal/app/procstats/DumpUtils.java
@@ -27,12 +27,12 @@
 import static com.android.internal.app.procstats.ProcessStats.ADJ_SCREEN_OFF;
 import static com.android.internal.app.procstats.ProcessStats.ADJ_SCREEN_ON;
 import static com.android.internal.app.procstats.ProcessStats.STATE_BACKUP;
-import static com.android.internal.app.procstats.ProcessStats.STATE_BOUND_TOP_OR_FGS;
-import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_ACTIVITY;
-import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_ACTIVITY_CLIENT;
-import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_EMPTY;
+import static com.android.internal.app.procstats.ProcessStats.STATE_BOUND_FGS;
+import static com.android.internal.app.procstats.ProcessStats.STATE_BOUND_TOP;
+import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED;
 import static com.android.internal.app.procstats.ProcessStats.STATE_COUNT;
 import static com.android.internal.app.procstats.ProcessStats.STATE_FGS;
+import static com.android.internal.app.procstats.ProcessStats.STATE_FROZEN;
 import static com.android.internal.app.procstats.ProcessStats.STATE_HEAVY_WEIGHT;
 import static com.android.internal.app.procstats.ProcessStats.STATE_HOME;
 import static com.android.internal.app.procstats.ProcessStats.STATE_IMPORTANT_BACKGROUND;
@@ -72,7 +72,8 @@
         STATE_NAMES = new String[STATE_COUNT];
         STATE_NAMES[STATE_PERSISTENT]               = "Persist";
         STATE_NAMES[STATE_TOP]                      = "Top";
-        STATE_NAMES[STATE_BOUND_TOP_OR_FGS]         = "BTopFgs";
+        STATE_NAMES[STATE_BOUND_FGS]                = "BFgs";
+        STATE_NAMES[STATE_BOUND_TOP]                = "BTop";
         STATE_NAMES[STATE_FGS]                      = "Fgs";
         STATE_NAMES[STATE_IMPORTANT_FOREGROUND]     = "ImpFg";
         STATE_NAMES[STATE_IMPORTANT_BACKGROUND]     = "ImpBg";
@@ -83,14 +84,14 @@
         STATE_NAMES[STATE_HEAVY_WEIGHT]             = "HeavyWt";
         STATE_NAMES[STATE_HOME]                     = "Home";
         STATE_NAMES[STATE_LAST_ACTIVITY]            = "LastAct";
-        STATE_NAMES[STATE_CACHED_ACTIVITY]          = "CchAct";
-        STATE_NAMES[STATE_CACHED_ACTIVITY_CLIENT]   = "CchCAct";
-        STATE_NAMES[STATE_CACHED_EMPTY]             = "CchEmty";
+        STATE_NAMES[STATE_CACHED]                   = "Cached";
+        STATE_NAMES[STATE_FROZEN]                   = "Frozen";
 
         STATE_LABELS = new String[STATE_COUNT];
         STATE_LABELS[STATE_PERSISTENT]              = "Persistent";
         STATE_LABELS[STATE_TOP]                     = "       Top";
-        STATE_LABELS[STATE_BOUND_TOP_OR_FGS]        = "Bnd TopFgs";
+        STATE_LABELS[STATE_BOUND_FGS]               = "   Bnd Fgs";
+        STATE_LABELS[STATE_BOUND_TOP]               = "   Bnd Top";
         STATE_LABELS[STATE_FGS]                     = "       Fgs";
         STATE_LABELS[STATE_IMPORTANT_FOREGROUND]    = "    Imp Fg";
         STATE_LABELS[STATE_IMPORTANT_BACKGROUND]    = "    Imp Bg";
@@ -101,16 +102,16 @@
         STATE_LABELS[STATE_HEAVY_WEIGHT]            = " Heavy Wgt";
         STATE_LABELS[STATE_HOME]                    = "    (Home)";
         STATE_LABELS[STATE_LAST_ACTIVITY]           = "(Last Act)";
-        STATE_LABELS[STATE_CACHED_ACTIVITY]         = " (Cch Act)";
-        STATE_LABELS[STATE_CACHED_ACTIVITY_CLIENT]  = "(Cch CAct)";
-        STATE_LABELS[STATE_CACHED_EMPTY]            = "(Cch Emty)";
+        STATE_LABELS[STATE_CACHED]                  = "  (Cached)";
+        STATE_LABELS[STATE_FROZEN]                  = "    Frozen";
         STATE_LABEL_CACHED                          = "  (Cached)";
         STATE_LABEL_TOTAL                           = "     TOTAL";
 
         STATE_NAMES_CSV = new String[STATE_COUNT];
         STATE_NAMES_CSV[STATE_PERSISTENT]               = "pers";
         STATE_NAMES_CSV[STATE_TOP]                      = "top";
-        STATE_NAMES_CSV[STATE_BOUND_TOP_OR_FGS]         = "btopfgs";
+        STATE_NAMES_CSV[STATE_BOUND_FGS]                = "bfgs";
+        STATE_NAMES_CSV[STATE_BOUND_TOP]                = "btop";
         STATE_NAMES_CSV[STATE_FGS]                      = "fgs";
         STATE_NAMES_CSV[STATE_IMPORTANT_FOREGROUND]     = "impfg";
         STATE_NAMES_CSV[STATE_IMPORTANT_BACKGROUND]     = "impbg";
@@ -121,14 +122,14 @@
         STATE_NAMES_CSV[STATE_HEAVY_WEIGHT]             = "heavy";
         STATE_NAMES_CSV[STATE_HOME]                     = "home";
         STATE_NAMES_CSV[STATE_LAST_ACTIVITY]            = "lastact";
-        STATE_NAMES_CSV[STATE_CACHED_ACTIVITY]          = "cch-activity";
-        STATE_NAMES_CSV[STATE_CACHED_ACTIVITY_CLIENT]   = "cch-aclient";
-        STATE_NAMES_CSV[STATE_CACHED_EMPTY]             = "cch-empty";
+        STATE_NAMES_CSV[STATE_CACHED]                   = "cached";
+        STATE_NAMES_CSV[STATE_FROZEN]                   = "frzn";
 
         STATE_TAGS = new String[STATE_COUNT];
         STATE_TAGS[STATE_PERSISTENT]                = "p";
         STATE_TAGS[STATE_TOP]                       = "t";
-        STATE_TAGS[STATE_BOUND_TOP_OR_FGS]          = "d";
+        STATE_TAGS[STATE_BOUND_FGS]                 = "y";
+        STATE_TAGS[STATE_BOUND_TOP]                 = "z";
         STATE_TAGS[STATE_FGS]                       = "g";
         STATE_TAGS[STATE_IMPORTANT_FOREGROUND]      = "f";
         STATE_TAGS[STATE_IMPORTANT_BACKGROUND]      = "b";
@@ -139,15 +140,14 @@
         STATE_TAGS[STATE_HEAVY_WEIGHT]              = "w";
         STATE_TAGS[STATE_HOME]                      = "h";
         STATE_TAGS[STATE_LAST_ACTIVITY]             = "l";
-        STATE_TAGS[STATE_CACHED_ACTIVITY]           = "a";
-        STATE_TAGS[STATE_CACHED_ACTIVITY_CLIENT]    = "c";
-        STATE_TAGS[STATE_CACHED_EMPTY]              = "e";
+        STATE_TAGS[STATE_CACHED]                    = "a";
+        STATE_TAGS[STATE_FROZEN]                    = "e";
 
         STATE_PROTO_ENUMS = new int[STATE_COUNT];
         STATE_PROTO_ENUMS[STATE_PERSISTENT] = ProcessStatsEnums.PROCESS_STATE_PERSISTENT;
         STATE_PROTO_ENUMS[STATE_TOP] = ProcessStatsEnums.PROCESS_STATE_TOP;
-        STATE_PROTO_ENUMS[STATE_BOUND_TOP_OR_FGS] =
-                ProcessStatsEnums.PROCESS_STATE_BOUND_TOP_OR_FGS;
+        STATE_PROTO_ENUMS[STATE_BOUND_FGS] = ProcessStatsEnums.PROCESS_STATE_BOUND_FGS;
+        STATE_PROTO_ENUMS[STATE_BOUND_TOP] = ProcessStatsEnums.PROCESS_STATE_BOUND_TOP;
         STATE_PROTO_ENUMS[STATE_FGS] = ProcessStatsEnums.PROCESS_STATE_FGS;
         STATE_PROTO_ENUMS[STATE_IMPORTANT_FOREGROUND] =
                 ProcessStatsEnums.PROCESS_STATE_IMPORTANT_FOREGROUND;
@@ -161,10 +161,8 @@
         STATE_PROTO_ENUMS[STATE_HEAVY_WEIGHT] = ProcessStatsEnums.PROCESS_STATE_HEAVY_WEIGHT;
         STATE_PROTO_ENUMS[STATE_HOME] = ProcessStatsEnums.PROCESS_STATE_HOME;
         STATE_PROTO_ENUMS[STATE_LAST_ACTIVITY] = ProcessStatsEnums.PROCESS_STATE_LAST_ACTIVITY;
-        STATE_PROTO_ENUMS[STATE_CACHED_ACTIVITY] = ProcessStatsEnums.PROCESS_STATE_CACHED_ACTIVITY;
-        STATE_PROTO_ENUMS[STATE_CACHED_ACTIVITY_CLIENT] =
-                ProcessStatsEnums.PROCESS_STATE_CACHED_ACTIVITY_CLIENT;
-        STATE_PROTO_ENUMS[STATE_CACHED_EMPTY] = ProcessStatsEnums.PROCESS_STATE_CACHED_EMPTY;
+        STATE_PROTO_ENUMS[STATE_CACHED] = ProcessStatsEnums.PROCESS_STATE_CACHED_ACTIVITY;
+        STATE_PROTO_ENUMS[STATE_FROZEN] = ProcessStatsEnums.PROCESS_STATE_FROZEN;
 
         // Remap states, as defined by ProcessStats.java, to a reduced subset of states for data
         // aggregation / size reduction purposes.
@@ -173,7 +171,9 @@
                 ProcessStatsEnums.AGGREGATED_PROCESS_STATE_PERSISTENT;
         PROCESS_STATS_STATE_TO_AGGREGATED_STATE[STATE_TOP] =
                 ProcessStatsEnums.AGGREGATED_PROCESS_STATE_TOP;
-        PROCESS_STATS_STATE_TO_AGGREGATED_STATE[STATE_BOUND_TOP_OR_FGS] =
+        PROCESS_STATS_STATE_TO_AGGREGATED_STATE[STATE_BOUND_FGS] =
+                ProcessStatsEnums.AGGREGATED_PROCESS_STATE_BOUND_TOP_OR_FGS;
+        PROCESS_STATS_STATE_TO_AGGREGATED_STATE[STATE_BOUND_TOP] =
                 ProcessStatsEnums.AGGREGATED_PROCESS_STATE_BOUND_TOP_OR_FGS;
         PROCESS_STATS_STATE_TO_AGGREGATED_STATE[STATE_FGS] =
                 ProcessStatsEnums.AGGREGATED_PROCESS_STATE_FGS;
@@ -196,11 +196,9 @@
                 ProcessStatsEnums.AGGREGATED_PROCESS_STATE_CACHED;
         PROCESS_STATS_STATE_TO_AGGREGATED_STATE[STATE_LAST_ACTIVITY] =
                 ProcessStatsEnums.AGGREGATED_PROCESS_STATE_CACHED;
-        PROCESS_STATS_STATE_TO_AGGREGATED_STATE[STATE_CACHED_ACTIVITY] =
+        PROCESS_STATS_STATE_TO_AGGREGATED_STATE[STATE_CACHED] =
                 ProcessStatsEnums.AGGREGATED_PROCESS_STATE_CACHED;
-        PROCESS_STATS_STATE_TO_AGGREGATED_STATE[STATE_CACHED_ACTIVITY_CLIENT] =
-                ProcessStatsEnums.AGGREGATED_PROCESS_STATE_CACHED;
-        PROCESS_STATS_STATE_TO_AGGREGATED_STATE[STATE_CACHED_EMPTY] =
+        PROCESS_STATS_STATE_TO_AGGREGATED_STATE[STATE_FROZEN] =
                 ProcessStatsEnums.AGGREGATED_PROCESS_STATE_CACHED;
     }
 
diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java
index 72b9cd2..fff778c 100644
--- a/core/java/com/android/internal/app/procstats/ProcessState.java
+++ b/core/java/com/android/internal/app/procstats/ProcessState.java
@@ -28,10 +28,9 @@
 import static com.android.internal.app.procstats.ProcessStats.PSS_USS_MAXIMUM;
 import static com.android.internal.app.procstats.ProcessStats.PSS_USS_MINIMUM;
 import static com.android.internal.app.procstats.ProcessStats.STATE_BACKUP;
-import static com.android.internal.app.procstats.ProcessStats.STATE_BOUND_TOP_OR_FGS;
-import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_ACTIVITY;
-import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_ACTIVITY_CLIENT;
-import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_EMPTY;
+import static com.android.internal.app.procstats.ProcessStats.STATE_BOUND_FGS;
+import static com.android.internal.app.procstats.ProcessStats.STATE_BOUND_TOP;
+import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED;
 import static com.android.internal.app.procstats.ProcessStats.STATE_COUNT;
 import static com.android.internal.app.procstats.ProcessStats.STATE_FGS;
 import static com.android.internal.app.procstats.ProcessStats.STATE_HEAVY_WEIGHT;
@@ -73,6 +72,7 @@
 
 import java.io.PrintWriter;
 import java.util.Comparator;
+import java.util.concurrent.TimeUnit;
 
 public final class ProcessState {
     private static final String TAG = "ProcessStats";
@@ -84,9 +84,9 @@
         STATE_PERSISTENT,               // ActivityManager.PROCESS_STATE_PERSISTENT
         STATE_PERSISTENT,               // ActivityManager.PROCESS_STATE_PERSISTENT_UI
         STATE_TOP,                      // ActivityManager.PROCESS_STATE_TOP
-        STATE_BOUND_TOP_OR_FGS,         // ActivityManager.PROCESS_STATE_BOUND_TOP
+        STATE_BOUND_TOP,                // ActivityManager.PROCESS_STATE_BOUND_TOP
         STATE_FGS,                      // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
-        STATE_BOUND_TOP_OR_FGS,         // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
+        STATE_BOUND_FGS,                // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
         STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
         STATE_IMPORTANT_BACKGROUND,     // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
         STATE_IMPORTANT_BACKGROUND,     // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
@@ -97,10 +97,10 @@
         STATE_HEAVY_WEIGHT,             // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
         STATE_HOME,                     // ActivityManager.PROCESS_STATE_HOME
         STATE_LAST_ACTIVITY,            // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
-        STATE_CACHED_ACTIVITY,          // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
-        STATE_CACHED_ACTIVITY_CLIENT,   // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
-        STATE_CACHED_ACTIVITY,          // ActivityManager.PROCESS_STATE_CACHED_RECENT
-        STATE_CACHED_EMPTY,             // ActivityManager.PROCESS_STATE_CACHED_EMPTY
+        STATE_CACHED,                   // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
+        STATE_CACHED,                   // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
+        STATE_CACHED,                   // ActivityManager.PROCESS_STATE_CACHED_RECENT
+        STATE_CACHED,                   // ActivityManager.PROCESS_STATE_CACHED_EMPTY
     };
 
     public static final Comparator<ProcessState> COMPARATOR = new Comparator<ProcessState>() {
@@ -925,8 +925,11 @@
                 screenStates, memStates, new int[] { STATE_PERSISTENT }, now, totalTime, true);
         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_TOP],
                 screenStates, memStates, new int[] {STATE_TOP}, now, totalTime, true);
-        dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_BOUND_TOP_OR_FGS],
-                screenStates, memStates, new int[] { STATE_BOUND_TOP_OR_FGS}, now, totalTime,
+        dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_BOUND_TOP],
+                screenStates, memStates, new int[] { STATE_BOUND_TOP }, now, totalTime,
+                true);
+        dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_BOUND_FGS],
+                screenStates, memStates, new int[] { STATE_BOUND_FGS }, now, totalTime,
                 true);
         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_FGS],
                 screenStates, memStates, new int[] { STATE_FGS}, now, totalTime,
@@ -952,9 +955,6 @@
                 screenStates, memStates, new int[] {STATE_HOME}, now, totalTime, true);
         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_LAST_ACTIVITY],
                 screenStates, memStates, new int[] {STATE_LAST_ACTIVITY}, now, totalTime, true);
-        dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABEL_CACHED,
-                screenStates, memStates, new int[] {STATE_CACHED_ACTIVITY,
-                        STATE_CACHED_ACTIVITY_CLIENT, STATE_CACHED_EMPTY}, now, totalTime, true);
     }
 
     public void dumpProcessState(PrintWriter pw, String prefix,
@@ -1542,6 +1542,75 @@
         proto.write(fieldId, procName);
     }
 
+    /** Dumps the duration of each state to statsEventOutput. */
+    public void dumpStateDurationToStatsd(
+            int atomTag, ProcessStats processStats, StatsEventOutput statsEventOutput) {
+        long topMs = 0;
+        long fgsMs = 0;
+        long boundTopMs = 0;
+        long boundFgsMs = 0;
+        long importantForegroundMs = 0;
+        long cachedMs = 0;
+        long frozenMs = 0;
+        long otherMs = 0;
+        for (int i = 0, size = mDurations.getKeyCount(); i < size; i++) {
+            final int key = mDurations.getKeyAt(i);
+            final int type = SparseMappingTable.getIdFromKey(key);
+            int procStateIndex = type % STATE_COUNT;
+            long duration = mDurations.getValue(key);
+            switch (procStateIndex) {
+                case STATE_TOP:
+                    topMs += duration;
+                    break;
+                case STATE_BOUND_FGS:
+                    boundFgsMs += duration;
+                    break;
+                case STATE_BOUND_TOP:
+                    boundTopMs += duration;
+                    break;
+                case STATE_FGS:
+                    fgsMs += duration;
+                    break;
+                case STATE_IMPORTANT_FOREGROUND:
+                case STATE_IMPORTANT_BACKGROUND:
+                    importantForegroundMs += duration;
+                    break;
+                case STATE_BACKUP:
+                case STATE_SERVICE:
+                case STATE_SERVICE_RESTARTING:
+                case STATE_RECEIVER:
+                case STATE_HEAVY_WEIGHT:
+                case STATE_HOME:
+                case STATE_LAST_ACTIVITY:
+                case STATE_PERSISTENT:
+                    otherMs += duration;
+                    break;
+                case STATE_CACHED:
+                    cachedMs += duration;
+                    break;
+                    // TODO (b/261910877) Add support for tracking frozenMs.
+            }
+        }
+        statsEventOutput.write(
+                atomTag,
+                getUid(),
+                getName(),
+                (int) TimeUnit.MILLISECONDS.toSeconds(processStats.mTimePeriodStartUptime),
+                (int) TimeUnit.MILLISECONDS.toSeconds(processStats.mTimePeriodEndUptime),
+                (int)
+                        TimeUnit.MILLISECONDS.toSeconds(
+                                processStats.mTimePeriodEndUptime
+                                        - processStats.mTimePeriodStartUptime),
+                (int) TimeUnit.MILLISECONDS.toSeconds(topMs),
+                (int) TimeUnit.MILLISECONDS.toSeconds(fgsMs),
+                (int) TimeUnit.MILLISECONDS.toSeconds(boundTopMs),
+                (int) TimeUnit.MILLISECONDS.toSeconds(boundFgsMs),
+                (int) TimeUnit.MILLISECONDS.toSeconds(importantForegroundMs),
+                (int) TimeUnit.MILLISECONDS.toSeconds(cachedMs),
+                (int) TimeUnit.MILLISECONDS.toSeconds(frozenMs),
+                (int) TimeUnit.MILLISECONDS.toSeconds(otherMs));
+    }
+
     /** Similar to {@code #dumpDebug}, but with a reduced/aggregated subset of states. */
     public void dumpAggregatedProtoForStatsd(ProtoOutputStream proto, long fieldId,
             String procName, int uid, long now,
diff --git a/core/java/com/android/internal/app/procstats/ProcessStats.java b/core/java/com/android/internal/app/procstats/ProcessStats.java
index d2b2f0a..3ce234b 100644
--- a/core/java/com/android/internal/app/procstats/ProcessStats.java
+++ b/core/java/com/android/internal/app/procstats/ProcessStats.java
@@ -43,6 +43,7 @@
 import com.android.internal.app.ProcessMap;
 import com.android.internal.app.procstats.AssociationState.SourceKey;
 import com.android.internal.app.procstats.AssociationState.SourceState;
+import com.android.internal.util.function.QuintConsumer;
 
 import dalvik.system.VMRuntime;
 
@@ -56,6 +57,8 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -78,21 +81,21 @@
     public static final int STATE_NOTHING = -1;
     public static final int STATE_PERSISTENT = 0;
     public static final int STATE_TOP = 1;
-    public static final int STATE_BOUND_TOP_OR_FGS = 2;
+    public static final int STATE_BOUND_TOP = 2;
     public static final int STATE_FGS = 3;
-    public static final int STATE_IMPORTANT_FOREGROUND = 4;
-    public static final int STATE_IMPORTANT_BACKGROUND = 5;
-    public static final int STATE_BACKUP = 6;
-    public static final int STATE_SERVICE = 7;
-    public static final int STATE_SERVICE_RESTARTING = 8;
-    public static final int STATE_RECEIVER = 9;
-    public static final int STATE_HEAVY_WEIGHT = 10;
-    public static final int STATE_HOME = 11;
-    public static final int STATE_LAST_ACTIVITY = 12;
-    public static final int STATE_CACHED_ACTIVITY = 13;
-    public static final int STATE_CACHED_ACTIVITY_CLIENT = 14;
-    public static final int STATE_CACHED_EMPTY = 15;
-    public static final int STATE_COUNT = STATE_CACHED_EMPTY+1;
+    public static final int STATE_BOUND_FGS = 4;
+    public static final int STATE_IMPORTANT_FOREGROUND = 5;
+    public static final int STATE_IMPORTANT_BACKGROUND = 6;
+    public static final int STATE_BACKUP = 7;
+    public static final int STATE_SERVICE = 8;
+    public static final int STATE_SERVICE_RESTARTING = 9;
+    public static final int STATE_RECEIVER = 10;
+    public static final int STATE_HEAVY_WEIGHT = 11;
+    public static final int STATE_HOME = 12;
+    public static final int STATE_LAST_ACTIVITY = 13;
+    public static final int STATE_CACHED = 14;
+    public static final int STATE_FROZEN = 15;
+    public static final int STATE_COUNT = STATE_FROZEN + 1;
 
     public static final int PSS_SAMPLE_COUNT = 0;
     public static final int PSS_MINIMUM = 1;
@@ -151,9 +154,10 @@
     public static final int[] ALL_SCREEN_ADJ = new int[] { ADJ_SCREEN_OFF, ADJ_SCREEN_ON };
 
     public static final int[] NON_CACHED_PROC_STATES = new int[] {
-            STATE_PERSISTENT, STATE_TOP, STATE_BOUND_TOP_OR_FGS, STATE_FGS,
+            STATE_PERSISTENT, STATE_TOP, STATE_FGS,
             STATE_IMPORTANT_FOREGROUND, STATE_IMPORTANT_BACKGROUND, STATE_BACKUP,
-            STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER, STATE_HEAVY_WEIGHT
+            STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER, STATE_HEAVY_WEIGHT,
+            STATE_BOUND_TOP, STATE_BOUND_FGS
     };
 
     public static final int[] BACKGROUND_PROC_STATES = new int[] {
@@ -162,11 +166,11 @@
     };
 
     public static final int[] ALL_PROC_STATES = new int[] { STATE_PERSISTENT,
-            STATE_TOP, STATE_BOUND_TOP_OR_FGS, STATE_FGS, STATE_IMPORTANT_FOREGROUND,
+            STATE_TOP, STATE_FGS, STATE_IMPORTANT_FOREGROUND,
             STATE_IMPORTANT_BACKGROUND, STATE_BACKUP,
             STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER,
-            STATE_HEAVY_WEIGHT, STATE_HOME, STATE_LAST_ACTIVITY, STATE_CACHED_ACTIVITY,
-            STATE_CACHED_ACTIVITY_CLIENT, STATE_CACHED_EMPTY
+            STATE_HEAVY_WEIGHT, STATE_HOME, STATE_LAST_ACTIVITY, STATE_CACHED,
+            STATE_BOUND_TOP, STATE_BOUND_FGS, STATE_FROZEN
     };
 
     // Should report process stats.
@@ -2389,6 +2393,79 @@
         }
     }
 
+    void forEachProcess(Consumer<ProcessState> consumer) {
+        final ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
+        for (int ip = 0, size = procMap.size(); ip < size; ip++) {
+            final SparseArray<ProcessState> uids = procMap.valueAt(ip);
+            for (int iu = 0, uidsSize = uids.size(); iu < uidsSize; iu++) {
+                final ProcessState processState = uids.valueAt(iu);
+                consumer.accept(processState);
+            }
+        }
+    }
+
+    void forEachAssociation(
+            QuintConsumer<AssociationState, Integer, String, SourceKey, SourceState> consumer) {
+        final ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap =
+                mPackages.getMap();
+        for (int ip = 0, size = pkgMap.size(); ip < size; ip++) {
+            final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip);
+            for (int iu = 0, uidsSize = uids.size(); iu < uidsSize; iu++) {
+                final int uid = uids.keyAt(iu);
+                final LongSparseArray<PackageState> versions = uids.valueAt(iu);
+                for (int iv = 0, versionsSize = versions.size(); iv < versionsSize; iv++) {
+                    final PackageState state = versions.valueAt(iv);
+                    for (int iasc = 0, ascSize = state.mAssociations.size();
+                            iasc < ascSize;
+                            iasc++) {
+                        final String serviceName = state.mAssociations.keyAt(iasc);
+                        final AssociationState asc = state.mAssociations.valueAt(iasc);
+                        for (int is = 0, sourcesSize = asc.mSources.size();
+                                is < sourcesSize;
+                                is++) {
+                            final SourceState src = asc.mSources.valueAt(is);
+                            final SourceKey key = asc.mSources.keyAt(is);
+                            consumer.accept(asc, uid, serviceName, key, src);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /** Dumps the stats of all processes to statsEventOutput. */
+    public void dumpProcessState(int atomTag, StatsEventOutput statsEventOutput) {
+        forEachProcess(
+                (processState) -> {
+                    if (processState.isMultiPackage()
+                            && processState.getCommonProcess() != processState) {
+                        return;
+                    }
+                    processState.dumpStateDurationToStatsd(atomTag, this, statsEventOutput);
+                });
+    }
+
+    /** Dumps all process association data to statsEventOutput. */
+    public void dumpProcessAssociation(int atomTag, StatsEventOutput statsEventOutput) {
+        forEachAssociation(
+                (asc, serviceUid, serviceName, key, src) -> {
+                    statsEventOutput.write(
+                            atomTag,
+                            key.mUid,
+                            key.mProcess,
+                            serviceUid,
+                            serviceName,
+                            (int) TimeUnit.MILLISECONDS.toSeconds(mTimePeriodStartUptime),
+                            (int) TimeUnit.MILLISECONDS.toSeconds(mTimePeriodEndUptime),
+                            (int)
+                                    TimeUnit.MILLISECONDS.toSeconds(
+                                            mTimePeriodEndUptime - mTimePeriodStartUptime),
+                            (int) TimeUnit.MILLISECONDS.toSeconds(src.mDuration),
+                            src.mActiveCount,
+                            asc.getProcessName());
+                });
+    }
+
     private void dumpProtoPreamble(ProtoOutputStream proto) {
         proto.write(ProcessStatsSectionProto.START_REALTIME_MS, mTimePeriodStartRealtime);
         proto.write(ProcessStatsSectionProto.END_REALTIME_MS,
diff --git a/core/java/com/android/internal/app/procstats/StatsEventOutput.java b/core/java/com/android/internal/app/procstats/StatsEventOutput.java
new file mode 100644
index 0000000..b2e4054
--- /dev/null
+++ b/core/java/com/android/internal/app/procstats/StatsEventOutput.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.app.procstats;
+
+import android.util.StatsEvent;
+
+import com.android.internal.util.FrameworkStatsLog;
+
+import java.util.List;
+
+/**
+ * A simple wrapper of FrameworkStatsLog.buildStatsEvent. This allows unit tests to mock out the
+ * dependency.
+ */
+public class StatsEventOutput {
+
+    List<StatsEvent> mOutput;
+
+    public StatsEventOutput(List<StatsEvent> output) {
+        mOutput = output;
+    }
+
+    /** Writes the data to the output. */
+    public void write(
+            int atomTag,
+            int uid,
+            String processName,
+            int measurementStartUptimeSecs,
+            int measurementEndUptimeSecs,
+            int measurementDurationUptimeSecs,
+            int topSeconds,
+            int fgsSeconds,
+            int boundTopSeconds,
+            int boundFgsSeconds,
+            int importantForegroundSeconds,
+            int cachedSeconds,
+            int frozenSeconds,
+            int otherSeconds) {
+        mOutput.add(
+                FrameworkStatsLog.buildStatsEvent(
+                        atomTag,
+                        uid,
+                        processName,
+                        measurementStartUptimeSecs,
+                        measurementEndUptimeSecs,
+                        measurementDurationUptimeSecs,
+                        topSeconds,
+                        fgsSeconds,
+                        boundTopSeconds,
+                        boundFgsSeconds,
+                        importantForegroundSeconds,
+                        cachedSeconds,
+                        frozenSeconds,
+                        otherSeconds));
+    }
+
+    /** Writes the data to the output. */
+    public void write(
+            int atomTag,
+            int clientUid,
+            String processName,
+            int serviceUid,
+            String serviceName,
+            int measurementStartUptimeSecs,
+            int measurementEndUptimeSecs,
+            int measurementDurationUptimeSecs,
+            int activeDurationUptimeSecs,
+            int activeCount,
+            String serviceProcessName) {
+        mOutput.add(
+                FrameworkStatsLog.buildStatsEvent(
+                        atomTag,
+                        clientUid,
+                        processName,
+                        serviceUid,
+                        serviceName,
+                        measurementStartUptimeSecs,
+                        measurementEndUptimeSecs,
+                        measurementDurationUptimeSecs,
+                        activeDurationUptimeSecs,
+                        activeCount,
+                        serviceProcessName));
+    }
+}
diff --git a/core/java/com/android/internal/app/procstats/UidState.java b/core/java/com/android/internal/app/procstats/UidState.java
index 8761b74..4911346 100644
--- a/core/java/com/android/internal/app/procstats/UidState.java
+++ b/core/java/com/android/internal/app/procstats/UidState.java
@@ -150,6 +150,7 @@
     public void resetSafely(long now) {
         mDurations.resetTable();
         mStartTime = now;
+        mProcesses.removeIf(p -> !p.isInUse());
     }
 
     /**
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index d8afe50..475f7fd 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -16,6 +16,10 @@
 
 package com.android.internal.jank;
 
+import static android.Manifest.permission.READ_DEVICE_CONFIG;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.provider.DeviceConfig.NAMESPACE_INTERACTION_JANK_MONITOR;
+
 import static com.android.internal.jank.FrameTracker.REASON_CANCEL_NORMAL;
 import static com.android.internal.jank.FrameTracker.REASON_CANCEL_TIMEOUT;
 import static com.android.internal.jank.FrameTracker.REASON_END_NORMAL;
@@ -33,6 +37,7 @@
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_OPEN_ALL_APPS;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_QUICK_SWITCH;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_UNLOCK_ENTRANCE_ANIMATION;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_CLOCK_MOVE_ANIMATION;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_LAUNCH_CAMERA;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_OCCLUSION;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_PASSWORD_APPEAR;
@@ -93,6 +98,7 @@
 import android.annotation.NonNull;
 import android.annotation.UiThread;
 import android.annotation.WorkerThread;
+import android.app.ActivityThread;
 import android.content.Context;
 import android.os.Build;
 import android.os.Handler;
@@ -231,6 +237,7 @@
     public static final int CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS = 66;
     public static final int CUJ_LAUNCHER_CLOSE_ALL_APPS_SWIPE = 67;
     public static final int CUJ_LAUNCHER_CLOSE_ALL_APPS_TO_HOME = 68;
+    public static final int CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION = 70;
 
     private static final int NO_STATSD_LOGGING = -1;
 
@@ -308,6 +315,8 @@
             UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_SWIPE_TO_RECENTS,
             UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_CLOSE_ALL_APPS_SWIPE,
             UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_CLOSE_ALL_APPS_TO_HOME,
+            NO_STATSD_LOGGING,
+            UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_CLOCK_MOVE_ANIMATION,
     };
 
     private static volatile InteractionJankMonitor sInstance;
@@ -396,7 +405,8 @@
             CUJ_RECENTS_SCROLLING,
             CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS,
             CUJ_LAUNCHER_CLOSE_ALL_APPS_SWIPE,
-            CUJ_LAUNCHER_CLOSE_ALL_APPS_TO_HOME
+            CUJ_LAUNCHER_CLOSE_ALL_APPS_TO_HOME,
+            CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface CujType {
@@ -431,18 +441,37 @@
         mWorker = worker;
         mWorker.start();
         mSamplingInterval = DEFAULT_SAMPLING_INTERVAL;
-
-        // Post initialization to the background in case we're running on the main
-        // thread.
-        mWorker.getThreadHandler().post(
-                () -> mPropertiesChangedListener.onPropertiesChanged(
-                        DeviceConfig.getProperties(
-                                DeviceConfig.NAMESPACE_INTERACTION_JANK_MONITOR)));
-        DeviceConfig.addOnPropertiesChangedListener(
-                DeviceConfig.NAMESPACE_INTERACTION_JANK_MONITOR,
-                new HandlerExecutor(mWorker.getThreadHandler()),
-                mPropertiesChangedListener);
         mEnabled = DEFAULT_ENABLED;
+
+        final Context context = ActivityThread.currentApplication();
+        if (context.checkCallingOrSelfPermission(READ_DEVICE_CONFIG) != PERMISSION_GRANTED) {
+            if (DEBUG) {
+                Log.d(TAG, "Initialized the InteractionJankMonitor."
+                        + " (No READ_DEVICE_CONFIG permission to change configs)"
+                        + " enabled=" + mEnabled + ", interval=" + mSamplingInterval
+                        + ", missedFrameThreshold=" + mTraceThresholdMissedFrames
+                        + ", frameTimeThreshold=" + mTraceThresholdFrameTimeMillis
+                        + ", package=" + context.getPackageName());
+            }
+            return;
+        }
+
+        // Post initialization to the background in case we're running on the main thread.
+        mWorker.getThreadHandler().post(
+                () -> {
+                    try {
+                        mPropertiesChangedListener.onPropertiesChanged(
+                                DeviceConfig.getProperties(NAMESPACE_INTERACTION_JANK_MONITOR));
+                        DeviceConfig.addOnPropertiesChangedListener(
+                                NAMESPACE_INTERACTION_JANK_MONITOR,
+                                new HandlerExecutor(mWorker.getThreadHandler()),
+                                mPropertiesChangedListener);
+                    } catch (SecurityException ex) {
+                        Log.d(TAG, "Can't get properties: READ_DEVICE_CONFIG granted="
+                                + context.checkCallingOrSelfPermission(READ_DEVICE_CONFIG)
+                                + ", package=" + context.getPackageName());
+                    }
+                });
     }
 
     /**
@@ -917,6 +946,8 @@
                 return "LAUNCHER_CLOSE_ALL_APPS_SWIPE";
             case CUJ_LAUNCHER_CLOSE_ALL_APPS_TO_HOME:
                 return "LAUNCHER_CLOSE_ALL_APPS_TO_HOME";
+            case CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION:
+                return "LOCKSCREEN_CLOCK_MOVE_ANIMATION";
         }
         return "UNKNOWN";
     }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 6fed26c..e1e57de 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -166,8 +166,8 @@
     // In-memory Parcel magic number, used to detect attempts to unmarshall bad data
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
-    // Current on-disk Parcel version
-    static final int VERSION = 210;
+    // Current on-disk Parcel version. Must be updated when the format of the parcelable changes
+    public static final int VERSION = 211;
 
     // The maximum number of names wakelocks we will keep track of
     // per uid; once the limit is reached, we batch the remaining wakelocks
@@ -6491,6 +6491,9 @@
             addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
             mPhoneOn = true;
             mPhoneOnTimer.startRunningLocked(elapsedRealtimeMs);
+            if (mConstants.PHONE_ON_EXTERNAL_STATS_COLLECTION) {
+                scheduleSyncExternalStatsLocked("phone-on", ExternalStatsSync.UPDATE_RADIO);
+            }
         }
     }
 
@@ -6509,6 +6512,7 @@
             addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
             mPhoneOn = false;
             mPhoneOnTimer.stopRunningLocked(elapsedRealtimeMs);
+            scheduleSyncExternalStatsLocked("phone-off", ExternalStatsSync.UPDATE_RADIO);
         }
     }
 
@@ -8475,6 +8479,12 @@
 
     @GuardedBy("this")
     @Override
+    public long getPhoneEnergyConsumptionUC() {
+        return getPowerBucketConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_PHONE);
+    }
+
+    @GuardedBy("this")
+    @Override
     public long getScreenOnMeasuredBatteryConsumptionUC() {
         return getPowerBucketConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON);
     }
@@ -13717,18 +13727,36 @@
         }
 
         synchronized (this) {
+            final long totalRadioDurationMs =
+                    mMobileRadioActiveTimer.getTimeSinceMarkLocked(
+                            elapsedRealtimeMs * 1000) / 1000;
+            mMobileRadioActiveTimer.setMark(elapsedRealtimeMs);
+            final long phoneOnDurationMs = Math.min(totalRadioDurationMs,
+                    mPhoneOnTimer.getTimeSinceMarkLocked(elapsedRealtimeMs * 1000) / 1000);
+            mPhoneOnTimer.setMark(elapsedRealtimeMs);
+
             if (!mOnBatteryInternal || mIgnoreNextExternalStats) {
                 return;
             }
 
             final SparseDoubleArray uidEstimatedConsumptionMah;
+            final long dataConsumedChargeUC;
             if (consumedChargeUC > 0 && mMobileRadioPowerCalculator != null
                     && mGlobalMeasuredEnergyStats != null) {
+                // Crudely attribute power consumption. Added (totalRadioDurationMs / 2) to the
+                // numerator for long rounding.
+                final long phoneConsumedChargeUC =
+                        (consumedChargeUC * phoneOnDurationMs + totalRadioDurationMs / 2)
+                                / totalRadioDurationMs;
+                dataConsumedChargeUC = consumedChargeUC - phoneConsumedChargeUC;
                 mGlobalMeasuredEnergyStats.updateStandardBucket(
-                        MeasuredEnergyStats.POWER_BUCKET_MOBILE_RADIO, consumedChargeUC);
+                        MeasuredEnergyStats.POWER_BUCKET_PHONE, phoneConsumedChargeUC);
+                mGlobalMeasuredEnergyStats.updateStandardBucket(
+                        MeasuredEnergyStats.POWER_BUCKET_MOBILE_RADIO, dataConsumedChargeUC);
                 uidEstimatedConsumptionMah = new SparseDoubleArray();
             } else {
                 uidEstimatedConsumptionMah = null;
+                dataConsumedChargeUC = POWER_DATA_UNAVAILABLE;
             }
 
             if (deltaInfo != null) {
@@ -13888,14 +13916,9 @@
                 // Update the MeasuredEnergyStats information.
                 if (uidEstimatedConsumptionMah != null) {
                     double totalEstimatedConsumptionMah = 0.0;
-
-                    // Estimate total active radio power consumption since last mark.
-                    final long totalRadioTimeMs = mMobileRadioActiveTimer.getTimeSinceMarkLocked(
-                            elapsedRealtimeMs * 1000) / 1000;
-                    mMobileRadioActiveTimer.setMark(elapsedRealtimeMs);
                     totalEstimatedConsumptionMah +=
                             mMobileRadioPowerCalculator.calcPowerFromRadioActiveDurationMah(
-                                    totalRadioTimeMs);
+                                    totalRadioDurationMs);
 
                     // Estimate idle power consumption at each signal strength level
                     final int numSignalStrengthLevels = mPhoneSignalStrengthsTimer.length;
@@ -13919,7 +13942,7 @@
                             mMobileRadioPowerCalculator.calcScanTimePowerMah(scanTimeMs);
 
                     distributeEnergyToUidsLocked(MeasuredEnergyStats.POWER_BUCKET_MOBILE_RADIO,
-                            consumedChargeUC, uidEstimatedConsumptionMah,
+                            dataConsumedChargeUC, uidEstimatedConsumptionMah,
                             totalEstimatedConsumptionMah, elapsedRealtimeMs);
                 }
 
@@ -16651,6 +16674,8 @@
         public static final String KEY_MAX_HISTORY_BUFFER_KB = "max_history_buffer_kb";
         public static final String KEY_BATTERY_CHARGED_DELAY_MS =
                 "battery_charged_delay_ms";
+        public static final String KEY_PHONE_ON_EXTERNAL_STATS_COLLECTION =
+                "phone_on_external_stats_collection";
 
         private static final boolean DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME = true;
         private static final long DEFAULT_KERNEL_UID_READERS_THROTTLE_TIME = 1_000;
@@ -16663,6 +16688,7 @@
         private static final int DEFAULT_MAX_HISTORY_FILES_LOW_RAM_DEVICE = 64;
         private static final int DEFAULT_MAX_HISTORY_BUFFER_LOW_RAM_DEVICE_KB = 64; /*Kilo Bytes*/
         private static final int DEFAULT_BATTERY_CHARGED_DELAY_MS = 900000; /* 15 min */
+        private static final boolean DEFAULT_PHONE_ON_EXTERNAL_STATS_COLLECTION = true;
 
         public boolean TRACK_CPU_ACTIVE_CLUSTER_TIME = DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME;
         /* Do not set default value for KERNEL_UID_READERS_THROTTLE_TIME. Need to trigger an
@@ -16678,6 +16704,8 @@
         public int MAX_HISTORY_FILES;
         public int MAX_HISTORY_BUFFER; /*Bytes*/
         public int BATTERY_CHARGED_DELAY_MS = DEFAULT_BATTERY_CHARGED_DELAY_MS;
+        public boolean PHONE_ON_EXTERNAL_STATS_COLLECTION =
+                DEFAULT_PHONE_ON_EXTERNAL_STATS_COLLECTION;
 
         private ContentResolver mResolver;
         private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -16754,6 +16782,11 @@
                                 DEFAULT_MAX_HISTORY_BUFFER_LOW_RAM_DEVICE_KB
                                 : DEFAULT_MAX_HISTORY_BUFFER_KB)
                         * 1024;
+
+                PHONE_ON_EXTERNAL_STATS_COLLECTION = mParser.getBoolean(
+                        KEY_PHONE_ON_EXTERNAL_STATS_COLLECTION,
+                        DEFAULT_PHONE_ON_EXTERNAL_STATS_COLLECTION);
+
                 updateBatteryChargedDelayMsLocked();
             }
         }
@@ -16808,6 +16841,8 @@
             pw.println(MAX_HISTORY_BUFFER/1024);
             pw.print(KEY_BATTERY_CHARGED_DELAY_MS); pw.print("=");
             pw.println(BATTERY_CHARGED_DELAY_MS);
+            pw.print(KEY_PHONE_ON_EXTERNAL_STATS_COLLECTION); pw.print("=");
+            pw.println(PHONE_ON_EXTERNAL_STATS_COLLECTION);
         }
     }
 
diff --git a/core/java/com/android/internal/os/PhonePowerCalculator.java b/core/java/com/android/internal/os/PhonePowerCalculator.java
index cb893de..f1c4ffe 100644
--- a/core/java/com/android/internal/os/PhonePowerCalculator.java
+++ b/core/java/com/android/internal/os/PhonePowerCalculator.java
@@ -40,14 +40,27 @@
     @Override
     public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
             long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
+        final long energyConsumerUC = batteryStats.getPhoneEnergyConsumptionUC();
+        final int powerModel = getPowerModel(energyConsumerUC, query);
+
         final long phoneOnTimeMs = batteryStats.getPhoneOnTime(rawRealtimeUs,
                 BatteryStats.STATS_SINCE_CHARGED) / 1000;
-        final double phoneOnPower = mPowerEstimator.calculatePower(phoneOnTimeMs);
-        if (phoneOnPower != 0) {
-            builder.getAggregateBatteryConsumerBuilder(
-                    BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE)
-                    .setConsumedPower(BatteryConsumer.POWER_COMPONENT_PHONE, phoneOnPower)
-                    .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_PHONE, phoneOnTimeMs);
+        final double phoneOnPower;
+        switch (powerModel) {
+            case BatteryConsumer.POWER_MODEL_MEASURED_ENERGY:
+                phoneOnPower = uCtoMah(energyConsumerUC);
+                break;
+            case BatteryConsumer.POWER_MODEL_POWER_PROFILE:
+            default:
+                phoneOnPower = mPowerEstimator.calculatePower(phoneOnTimeMs);
         }
+
+        if (phoneOnPower == 0.0)  return;
+
+        builder.getAggregateBatteryConsumerBuilder(
+                        BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE)
+                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_PHONE, phoneOnPower, powerModel)
+                .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_PHONE, phoneOnTimeMs);
+
     }
 }
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index bb69192f..e603e2ed 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -295,6 +295,7 @@
     private boolean mClosingActionMenu;
 
     private int mVolumeControlStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE;
+    private int mAudioMode = AudioManager.MODE_NORMAL;
     private MediaController mMediaController;
 
     private AudioManager mAudioManager;
@@ -317,6 +318,8 @@
         }
     };
 
+    private AudioManager.OnModeChangedListener mOnModeChangedListener;
+
     private Transition mEnterTransition = null;
     private Transition mReturnTransition = USE_DEFAULT_TRANSITION;
     private Transition mExitTransition = null;
@@ -1950,9 +1953,9 @@
             case KeyEvent.KEYCODE_VOLUME_UP:
             case KeyEvent.KEYCODE_VOLUME_DOWN:
             case KeyEvent.KEYCODE_VOLUME_MUTE: {
-                // If we have a session send it the volume command, otherwise
-                // use the suggested stream.
-                if (mMediaController != null) {
+                // If we have a session and no active phone call send it the volume command,
+                // otherwise use the suggested stream.
+                if (mMediaController != null && !isActivePhoneCallOngoing()) {
                     getMediaSessionManager().dispatchVolumeKeyEventToSessionAsSystemService(event,
                             mMediaController.getSessionToken());
                 } else {
@@ -2003,6 +2006,11 @@
         return false;
     }
 
+    private boolean isActivePhoneCallOngoing() {
+        return mAudioMode == AudioManager.MODE_IN_CALL
+                || mAudioMode == AudioManager.MODE_IN_COMMUNICATION;
+    }
+
     private KeyguardManager getKeyguardManager() {
         if (mKeyguardManager == null) {
             mKeyguardManager = (KeyguardManager) getContext().getSystemService(
@@ -2326,6 +2334,14 @@
         }
     }
 
+    @Override
+    protected void onDestroy() {
+        if (mOnModeChangedListener != null) {
+            getAudioManager().removeOnModeChangedListener(mOnModeChangedListener);
+            mOnModeChangedListener = null;
+        }
+    }
+
     private class PanelMenuPresenterCallback implements MenuPresenter.Callback {
         @Override
         public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
@@ -3208,6 +3224,15 @@
     @Override
     public void setMediaController(MediaController controller) {
         mMediaController = controller;
+        if (controller != null && mOnModeChangedListener == null) {
+            mAudioMode = getAudioManager().getMode();
+            mOnModeChangedListener = mode -> mAudioMode = mode;
+            getAudioManager().addOnModeChangedListener(getContext().getMainExecutor(),
+                    mOnModeChangedListener);
+        } else if (mOnModeChangedListener != null) {
+            getAudioManager().removeOnModeChangedListener(mOnModeChangedListener);
+            mOnModeChangedListener = null;
+        }
     }
 
     @Override
diff --git a/core/java/com/android/internal/power/MeasuredEnergyStats.java b/core/java/com/android/internal/power/MeasuredEnergyStats.java
index 7fb8696..5bfdd62 100644
--- a/core/java/com/android/internal/power/MeasuredEnergyStats.java
+++ b/core/java/com/android/internal/power/MeasuredEnergyStats.java
@@ -59,7 +59,9 @@
     public static final int POWER_BUCKET_BLUETOOTH = 5;
     public static final int POWER_BUCKET_GNSS = 6;
     public static final int POWER_BUCKET_MOBILE_RADIO = 7;
-    public static final int NUMBER_STANDARD_POWER_BUCKETS = 8; // Buckets above this are custom.
+    public static final int POWER_BUCKET_CAMERA = 8;
+    public static final int POWER_BUCKET_PHONE = 9;
+    public static final int NUMBER_STANDARD_POWER_BUCKETS = 10;  // Buckets above this are custom.
 
     @IntDef(prefix = {"POWER_BUCKET_"}, value = {
             POWER_BUCKET_UNKNOWN,
diff --git a/core/java/com/android/internal/protolog/BaseProtoLogImpl.java b/core/java/com/android/internal/protolog/BaseProtoLogImpl.java
index 4d1234f..ac9188a 100644
--- a/core/java/com/android/internal/protolog/BaseProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/BaseProtoLogImpl.java
@@ -72,11 +72,13 @@
     private static final String TAG = "ProtoLog";
     private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
     static final String PROTOLOG_VERSION = "1.0.0";
+    private static final int DEFAULT_PER_CHUNK_SIZE = 0;
 
     private final File mLogFile;
     private final String mViewerConfigFilename;
     private final TraceBuffer mBuffer;
     protected final ProtoLogViewerConfigReader mViewerConfig;
+    private final int mPerChunkSize;
 
     private boolean mProtoLogEnabled;
     private boolean mProtoLogEnabledLockFree;
@@ -156,7 +158,7 @@
             return;
         }
         try {
-            ProtoOutputStream os = new ProtoOutputStream();
+            ProtoOutputStream os = new ProtoOutputStream(mPerChunkSize);
             long token = os.start(LOG);
             os.write(MESSAGE_HASH, messageHash);
             os.write(ELAPSED_REALTIME_NANOS, SystemClock.elapsedRealtimeNanos());
@@ -215,10 +217,16 @@
 
     public BaseProtoLogImpl(File file, String viewerConfigFilename, int bufferCapacity,
             ProtoLogViewerConfigReader viewerConfig) {
+        this(file, viewerConfigFilename, bufferCapacity, viewerConfig, DEFAULT_PER_CHUNK_SIZE);
+    }
+
+    public BaseProtoLogImpl(File file, String viewerConfigFilename, int bufferCapacity,
+            ProtoLogViewerConfigReader viewerConfig, int perChunkSize) {
         mLogFile = file;
         mBuffer = new TraceBuffer(bufferCapacity);
         mViewerConfigFilename = viewerConfigFilename;
         mViewerConfig = viewerConfig;
+        mPerChunkSize = perChunkSize;
     }
 
     /**
@@ -364,7 +372,7 @@
         try {
             long offset =
                     (System.currentTimeMillis() - (SystemClock.elapsedRealtimeNanos() / 1000000));
-            ProtoOutputStream proto = new ProtoOutputStream();
+            ProtoOutputStream proto = new ProtoOutputStream(mPerChunkSize);
             proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
             proto.write(VERSION, PROTOLOG_VERSION);
             proto.write(REAL_TIME_TO_ELAPSED_TIME_OFFSET_MILLIS, offset);
diff --git a/core/java/com/android/internal/protolog/ProtoLogImpl.java b/core/java/com/android/internal/protolog/ProtoLogImpl.java
index 353c6c0..527cfdd 100644
--- a/core/java/com/android/internal/protolog/ProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/ProtoLogImpl.java
@@ -30,6 +30,7 @@
     private static final int BUFFER_CAPACITY = 1024 * 1024;
     private static final String LOG_FILENAME = "/data/misc/wmtrace/wm_log.winscope";
     private static final String VIEWER_CONFIG_FILENAME = "/system/etc/protolog.conf.json.gz";
+    private static final int PER_CHUNK_SIZE = 1024;
 
     private static ProtoLogImpl sServiceInstance = null;
 
@@ -94,7 +95,10 @@
     public static synchronized ProtoLogImpl getSingleInstance() {
         if (sServiceInstance == null) {
             sServiceInstance = new ProtoLogImpl(
-                    new File(LOG_FILENAME), BUFFER_CAPACITY, new ProtoLogViewerConfigReader());
+                    new File(LOG_FILENAME)
+                    , BUFFER_CAPACITY
+                    , new ProtoLogViewerConfigReader()
+                    , PER_CHUNK_SIZE);
         }
         return sServiceInstance;
     }
@@ -105,8 +109,8 @@
     }
 
     public ProtoLogImpl(File logFile, int bufferCapacity,
-            ProtoLogViewerConfigReader viewConfigReader) {
-        super(logFile, VIEWER_CONFIG_FILENAME, bufferCapacity, viewConfigReader);
-    }
+            ProtoLogViewerConfigReader viewConfigReader, int perChunkSize) {
+        super(logFile, VIEWER_CONFIG_FILENAME, bufferCapacity, viewConfigReader, perChunkSize);
+  }
 }
 
diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java
index afb526a..c8a8b58 100644
--- a/core/java/com/android/internal/util/LatencyTracker.java
+++ b/core/java/com/android/internal/util/LatencyTracker.java
@@ -24,12 +24,15 @@
 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_FOLD_TO_AOD;
 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOAD_SHARE_SHEET;
 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOCKSCREEN_UNLOCK;
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_HIDDEN;
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_SHOWN;
 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN;
 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_CAMERA_CHECK;
 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_SENSOR;
 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_BACK_ARROW;
 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_SELECTION_TOOLBAR;
 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_VOICE_INTERACTION;
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SMARTSPACE_DOORBELL;
 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_START_RECENTS_ANIMATION;
 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SWITCH_DISPLAY_UNFOLD;
 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_TOGGLE_RECENTS;
@@ -187,6 +190,25 @@
      */
     public static final int ACTION_SHOW_VOICE_INTERACTION = 19;
 
+    /**
+     * Time it takes to request IME shown animation.
+     */
+    public static final int ACTION_REQUEST_IME_SHOWN = 20;
+
+    /**
+     * Time it takes to request IME hidden animation.
+     */
+    public static final int ACTION_REQUEST_IME_HIDDEN = 21;
+
+    /**
+     * Time it takes to load the animation frames in smart space doorbell card.
+     * It measures the duration from the images uris are passed into the view
+     * to all the frames are loaded.
+     * <p/>
+     * A long latency makes the doorbell animation looks janky until all the frames are loaded.
+     */
+    public static final int ACTION_SMARTSPACE_DOORBELL = 22;
+
     private static final int[] ACTIONS_ALL = {
         ACTION_EXPAND_PANEL,
         ACTION_TOGGLE_RECENTS,
@@ -208,6 +230,9 @@
         ACTION_SHOW_SELECTION_TOOLBAR,
         ACTION_FOLD_TO_AOD,
         ACTION_SHOW_VOICE_INTERACTION,
+        ACTION_REQUEST_IME_SHOWN,
+        ACTION_REQUEST_IME_HIDDEN,
+        ACTION_SMARTSPACE_DOORBELL,
     };
 
     /** @hide */
@@ -232,6 +257,9 @@
         ACTION_SHOW_SELECTION_TOOLBAR,
         ACTION_FOLD_TO_AOD,
         ACTION_SHOW_VOICE_INTERACTION,
+        ACTION_REQUEST_IME_SHOWN,
+        ACTION_REQUEST_IME_HIDDEN,
+        ACTION_SMARTSPACE_DOORBELL,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface Action {
@@ -259,6 +287,9 @@
             UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_SELECTION_TOOLBAR,
             UIACTION_LATENCY_REPORTED__ACTION__ACTION_FOLD_TO_AOD,
             UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_VOICE_INTERACTION,
+            UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_SHOWN,
+            UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_HIDDEN,
+            UIACTION_LATENCY_REPORTED__ACTION__ACTION_SMARTSPACE_DOORBELL,
     };
 
     private static LatencyTracker sLatencyTracker;
@@ -368,6 +399,12 @@
                 return "ACTION_FOLD_TO_AOD";
             case UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_VOICE_INTERACTION:
                 return "ACTION_SHOW_VOICE_INTERACTION";
+            case UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_SHOWN:
+                return "ACTION_REQUEST_IME_SHOWN";
+            case UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_HIDDEN:
+                return "ACTION_REQUEST_IME_HIDDEN";
+            case UIACTION_LATENCY_REPORTED__ACTION__ACTION_SMARTSPACE_DOORBELL:
+                return "ACTION_SMARTSPACE_DOORBELL";
             default:
                 throw new IllegalArgumentException("Invalid action");
         }
@@ -434,7 +471,7 @@
      */
     public void onActionStart(@Action int action, String tag) {
         synchronized (mLock) {
-            if (!isEnabled()) {
+            if (!isEnabled(action)) {
                 return;
             }
             // skip if the action is already instrumenting.
@@ -458,7 +495,7 @@
      */
     public void onActionEnd(@Action int action) {
         synchronized (mLock) {
-            if (!isEnabled()) {
+            if (!isEnabled(action)) {
                 return;
             }
             Session session = mSessions.get(action);
@@ -568,23 +605,27 @@
 
         void begin(@NonNull Runnable timeoutAction) {
             mStartRtc = SystemClock.elapsedRealtime();
-            Trace.asyncTraceBegin(TRACE_TAG_APP, traceName(), 0);
+            Trace.asyncTraceForTrackBegin(TRACE_TAG_APP, traceName(), traceName(), 0);
 
             // start counting timeout.
-            mTimeoutRunnable = timeoutAction;
+            mTimeoutRunnable = () -> {
+                Trace.instantForTrack(TRACE_TAG_APP, traceName(), "timeout");
+                timeoutAction.run();
+            };
             BackgroundThread.getHandler()
                     .postDelayed(mTimeoutRunnable, TimeUnit.SECONDS.toMillis(15));
         }
 
         void end() {
             mEndRtc = SystemClock.elapsedRealtime();
-            Trace.asyncTraceEnd(TRACE_TAG_APP, traceName(), 0);
+            Trace.asyncTraceForTrackEnd(TRACE_TAG_APP, traceName(), "end", 0);
             BackgroundThread.getHandler().removeCallbacks(mTimeoutRunnable);
             mTimeoutRunnable = null;
         }
 
         void cancel() {
-            Trace.asyncTraceEnd(TRACE_TAG_APP, traceName(), 0);
+            Trace.instantForTrack(TRACE_TAG_APP, traceName(), "cancel");
+            Trace.asyncTraceForTrackEnd(TRACE_TAG_APP, traceName(), "cancel", 0);
             BackgroundThread.getHandler().removeCallbacks(mTimeoutRunnable);
             mTimeoutRunnable = null;
         }
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 2dfe893..5b2c441 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -170,6 +170,8 @@
     private static final String LOCK_SCREEN_OWNER_INFO_ENABLED =
             Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
 
+    private static final String LOCK_PIN_ENHANCED_PRIVACY = "pin_enhanced_privacy";
+
     private static final String LOCK_SCREEN_DEVICE_OWNER_INFO = "lockscreen.device_owner_info";
 
     private static final String ENABLED_TRUST_AGENTS = "lockscreen.enabledtrustagents";
@@ -999,6 +1001,27 @@
     }
 
     /**
+     * @return Whether enhanced pin privacy is enabled.
+     */
+    public boolean isPinEnhancedPrivacyEnabled(int userId) {
+        return getBoolean(LOCK_PIN_ENHANCED_PRIVACY, false, userId);
+    }
+
+    /**
+     * Set whether enhanced pin privacy is enabled.
+     */
+    public void setPinEnhancedPrivacyEnabled(boolean enabled, int userId) {
+        setBoolean(LOCK_PIN_ENHANCED_PRIVACY, enabled, userId);
+    }
+
+    /**
+     * @return Whether enhanced pin privacy was ever chosen.
+     */
+    public boolean isPinEnhancedPrivacyEverChosen(int userId) {
+        return getString(LOCK_PIN_ENHANCED_PRIVACY, userId) != null;
+    }
+
+    /**
      * Set whether the visible password is enabled for cryptkeeper screen.
      */
     public void setVisiblePasswordEnabled(boolean enabled, int userId) {
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index a8abe50..2a670e8 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -556,7 +556,8 @@
 // connect to camera service
 static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
                                                  jint cameraId, jstring clientPackageName,
-                                                 jboolean overrideToPortrait) {
+                                                 jboolean overrideToPortrait,
+                                                 jboolean forceSlowJpegMode) {
     // Convert jstring to String16
     const char16_t *rawClientName = reinterpret_cast<const char16_t*>(
         env->GetStringChars(clientPackageName, NULL));
@@ -568,7 +569,7 @@
     int targetSdkVersion = android_get_application_target_sdk_version();
     sp<Camera> camera =
             Camera::connect(cameraId, clientName, Camera::USE_CALLING_UID, Camera::USE_CALLING_PID,
-                            targetSdkVersion, overrideToPortrait);
+                            targetSdkVersion, overrideToPortrait, forceSlowJpegMode);
     if (camera == NULL) {
         return -EACCES;
     }
@@ -1054,7 +1055,7 @@
         {"getNumberOfCameras", "()I", (void *)android_hardware_Camera_getNumberOfCameras},
         {"_getCameraInfo", "(IZLandroid/hardware/Camera$CameraInfo;)V",
          (void *)android_hardware_Camera_getCameraInfo},
-        {"native_setup", "(Ljava/lang/Object;ILjava/lang/String;Z)I",
+        {"native_setup", "(Ljava/lang/Object;ILjava/lang/String;ZZ)I",
          (void *)android_hardware_Camera_native_setup},
         {"native_release", "()V", (void *)android_hardware_Camera_release},
         {"setPreviewSurface", "(Landroid/view/Surface;)V",
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 556636dd..d443270 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -89,6 +89,8 @@
         // Setting for accessibility magnification for following typing.
         optional SettingProto accessibility_magnification_follow_typing_enabled = 43 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto contrast_level = 44 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        // Settings for font scaling
+        optional SettingProto accessibility_font_scaling_has_been_changed = 51 [ (android.privacy).dest = DEST_AUTOMATIC ];
     }
     optional Accessibility accessibility = 2;
 
diff --git a/core/res/res/layout/miniresolver.xml b/core/res/res/layout/miniresolver.xml
index 38a71f0..bb0f704 100644
--- a/core/res/res/layout/miniresolver.xml
+++ b/core/res/res/layout/miniresolver.xml
@@ -50,6 +50,7 @@
             android:paddingTop="16dp"
             android:layout_below="@id/icon"
             android:layout_centerHorizontal="true"
+            android:fontFamily="@string/config_headlineFontFamily"
             android:textSize="24sp"
             android:lineHeight="32sp"
             android:gravity="center"
diff --git a/core/res/res/layout/transient_notification.xml b/core/res/res/layout/transient_notification.xml
index 3259201..8bedb89 100644
--- a/core/res/res/layout/transient_notification.xml
+++ b/core/res/res/layout/transient_notification.xml
@@ -25,7 +25,7 @@
     android:orientation="horizontal"
     android:gravity="center_vertical"
     android:maxWidth="@dimen/toast_width"
-    android:background="?android:attr/toastFrameBackground"
+    android:background="?android:attr/colorBackground"
     android:elevation="@dimen/toast_elevation"
     android:layout_marginEnd="16dp"
     android:layout_marginStart="16dp"
diff --git a/core/res/res/layout/transient_notification_with_icon.xml b/core/res/res/layout/transient_notification_with_icon.xml
index e9b17df..0dfb3ad 100644
--- a/core/res/res/layout/transient_notification_with_icon.xml
+++ b/core/res/res/layout/transient_notification_with_icon.xml
@@ -22,7 +22,7 @@
     android:orientation="horizontal"
     android:gravity="center_vertical"
     android:maxWidth="@dimen/toast_width"
-    android:background="?android:attr/toastFrameBackground"
+    android:background="?android:attr/colorBackground"
     android:elevation="@dimen/toast_elevation"
     android:layout_marginEnd="16dp"
     android:layout_marginStart="16dp"
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 7a9fcb3..05e777e 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -577,7 +577,7 @@
     <string name="permdesc_mediaLocation" msgid="597912899423578138">"Permet que l\'aplicació llegeixi les ubicacions de les teves col·leccions multimèdia."</string>
     <string name="biometric_app_setting_name" msgid="3339209978734534457">"Utilitza la biometria"</string>
     <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Fes servir la biometria o el bloqueig de pantalla"</string>
-    <string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifica que ets tu"</string>
+    <string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifica la teva identitat"</string>
     <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Utilitza la teva biometria per continuar"</string>
     <string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Utilitza la biometria o el bloqueig de pantalla per continuar"</string>
     <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Maquinari biomètric no disponible"</string>
@@ -1232,7 +1232,7 @@
     <string name="screen_compat_mode_scale" msgid="8627359598437527726">"Escala"</string>
     <string name="screen_compat_mode_show" msgid="5080361367584709857">"Mostra sempre"</string>
     <string name="screen_compat_mode_hint" msgid="4032272159093750908">"Torna a activar-ho a Configuració del sistema &gt; Aplicacions &gt; Baixades."</string>
-    <string name="unsupported_display_size_message" msgid="7265211375269394699">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admet la mida de pantalla actual i és possible que funcioni de manera inesperada."</string>
+    <string name="unsupported_display_size_message" msgid="7265211375269394699">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admet la mida de visualització actual i és possible que funcioni de manera inesperada."</string>
     <string name="unsupported_display_size_show" msgid="980129850974919375">"Mostra sempre"</string>
     <string name="unsupported_compile_sdk_message" msgid="7326293500707890537">"<xliff:g id="APP_NAME">%1$s</xliff:g> es va crear per a una versió incompatible del sistema operatiu Android i pot funcionar de manera inesperada. És possible que hi hagi disponible una versió actualitzada de l\'aplicació."</string>
     <string name="unsupported_compile_sdk_show" msgid="1601210057960312248">"Mostra sempre"</string>
@@ -1326,8 +1326,8 @@
     <string name="sms_control_yes" msgid="4858845109269524622">"Permet"</string>
     <string name="sms_control_no" msgid="4845717880040355570">"Denega"</string>
     <string name="sms_short_code_confirm_message" msgid="1385416688897538724">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; vol enviar un missatge a &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt;."</string>
-    <string name="sms_short_code_details" msgid="2723725738333388351">"Aquesta acció "<b>"pot produir càrrecs"</b>" al teu compte per a mòbils."</string>
-    <string name="sms_premium_short_code_details" msgid="1400296309866638111"><b>"Aquesta acció produirà càrrecs al teu compte per a mòbils."</b></string>
+    <string name="sms_short_code_details" msgid="2723725738333388351">"Aquesta acció "<b>"pot produir càrrecs"</b>" al teu compte mòbil."</string>
+    <string name="sms_premium_short_code_details" msgid="1400296309866638111"><b>"Aquesta acció produirà càrrecs al teu compte mòbil."</b></string>
     <string name="sms_short_code_confirm_allow" msgid="920477594325526691">"Envia"</string>
     <string name="sms_short_code_confirm_deny" msgid="1356917469323768230">"Cancel·la"</string>
     <string name="sms_short_code_remember_choice" msgid="1374526438647744862">"Recorda la meva selecció"</string>
@@ -1366,7 +1366,7 @@
     <string name="usb_power_notification_message" msgid="7284765627437897702">"S\'està carregant el dispositiu connectat. Toca per veure més opcions."</string>
     <string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"S\'ha detectat un accessori d\'àudio analògic"</string>
     <string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"El dispositiu connectat no és compatible amb aquest telèfon. Toca per obtenir més informació."</string>
-    <string name="adb_active_notification_title" msgid="408390247354560331">"Depuració per USB activada"</string>
+    <string name="adb_active_notification_title" msgid="408390247354560331">"Depuració per USB connectada"</string>
     <string name="adb_active_notification_message" msgid="5617264033476778211">"Toca per desactivar la depuració per USB"</string>
     <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Selecciona per desactivar la depuració per USB"</string>
     <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"S\'ha connectat la depuració sense fil"</string>
@@ -1511,7 +1511,7 @@
     <string name="next_button_label" msgid="6040209156399907780">"Següent"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Omet"</string>
     <string name="no_matches" msgid="6472699895759164599">"No s\'ha trobat cap coincidència"</string>
-    <string name="find_on_page" msgid="5400537367077438198">"Troba-ho a la pàgina"</string>
+    <string name="find_on_page" msgid="5400537367077438198">"Cerca a la pàgina"</string>
     <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# coincidència}many{# de {total}}other{# de {total}}}"</string>
     <string name="action_mode_done" msgid="2536182504764803222">"Fet"</string>
     <string name="progress_erasing" msgid="6891435992721028004">"S\'està esborrant l\'emmagatzematge compartit…"</string>
@@ -1910,7 +1910,7 @@
     <string name="usb_midi_peripheral_manufacturer_name" msgid="7557148557088787741">"Android"</string>
     <string name="usb_midi_peripheral_product_name" msgid="2836276258480904434">"Port perifèric USB"</string>
     <string name="floating_toolbar_open_overflow_description" msgid="2260297653578167367">"Més opcions"</string>
-    <string name="floating_toolbar_close_overflow_description" msgid="3949818077708138098">"Tanca el menú addicional"</string>
+    <string name="floating_toolbar_close_overflow_description" msgid="3949818077708138098">"Tanca el menú de desbordament"</string>
     <string name="maximize_button_text" msgid="4258922519914732645">"Maximitza"</string>
     <string name="close_button_text" msgid="10603510034455258">"Tanca"</string>
     <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index fd169f5..02bee7e 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1148,7 +1148,7 @@
     <string name="selectTextMode" msgid="3225108910999318778">"Markér tekst"</string>
     <string name="undo" msgid="3175318090002654673">"Fortryd"</string>
     <string name="redo" msgid="7231448494008532233">"Annuller fortryd"</string>
-    <string name="autofill" msgid="511224882647795296">"AutoFyld"</string>
+    <string name="autofill" msgid="511224882647795296">"Autofyld"</string>
     <string name="textSelectionCABTitle" msgid="5151441579532476940">"Tekstmarkering"</string>
     <string name="addToDictionary" msgid="8041821113480950096">"Føj til ordbog"</string>
     <string name="deleteText" msgid="4200807474529938112">"Slet"</string>
@@ -1255,7 +1255,7 @@
     <string name="fp_power_button_enrollment_message" msgid="5648173517663246140">"Du har trykket på afbryderknappen, hvilket som regel slukker skærmen.\n\nPrøv at trykke let på knappen, mens du konfigurerer dit fingeraftryk."</string>
     <string name="fp_power_button_enrollment_title" msgid="6976841690455338563">"Sluk skærmen for at afslutte konfigurationen"</string>
     <string name="fp_power_button_enrollment_button_text" msgid="3199783266386029200">"Deaktiver"</string>
-    <string name="fp_power_button_bp_title" msgid="5585506104526820067">"Vil du bekræfte dit fingeraftryk?"</string>
+    <string name="fp_power_button_bp_title" msgid="5585506104526820067">"Vil du verificere dit fingeraftryk?"</string>
     <string name="fp_power_button_bp_message" msgid="2983163038168903393">"Du har trykket på afbryderknappen, hvilket som regel slukker skærmen.\n\nPrøv at trykke let på knappen for at bekræfte dit fingeraftryk."</string>
     <string name="fp_power_button_bp_positive_button" msgid="728945472408552251">"Sluk skærm"</string>
     <string name="fp_power_button_bp_negative_button" msgid="3971364246496775178">"Fortsæt"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 42fb58f..e889fa0 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1253,7 +1253,7 @@
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Apps werden gestartet..."</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"Start wird abgeschlossen..."</string>
     <string name="fp_power_button_enrollment_message" msgid="5648173517663246140">"Du hast die Ein-/Aus-Taste gedrückt — damit wird der Bildschirm ausgeschaltet.\n\nTippe die Taste leicht an, um deinen Fingerabdruck einzurichten."</string>
-    <string name="fp_power_button_enrollment_title" msgid="6976841690455338563">"Zum Beenden der Einrichtung Bildschirm deaktivieren"</string>
+    <string name="fp_power_button_enrollment_title" msgid="6976841690455338563">"Zum Beenden Bildschirm deaktivieren"</string>
     <string name="fp_power_button_enrollment_button_text" msgid="3199783266386029200">"Deaktivieren"</string>
     <string name="fp_power_button_bp_title" msgid="5585506104526820067">"Mit der Fingerabdruckprüfung fortfahren?"</string>
     <string name="fp_power_button_bp_message" msgid="2983163038168903393">"Du hast die Ein-/Aus-Taste gedrückt — damit wird der Bildschirm ausgeschaltet.\n\nTippe die Taste leicht an, um mit deinem Fingerabdruck deine Identität zu bestätigen."</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 8c6285c..2227f6e 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -1693,7 +1693,7 @@
     <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"View and control screen"</string>
     <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"It can read all content on the screen and display content over other apps."</string>
     <string name="accessibility_service_action_perform_title" msgid="779670378951658160">"View and perform actions"</string>
-    <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"It can track your interactions with an app or a hardware sensor, and interact with apps on your behalf."</string>
+    <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"It can track your interactions with an app or a hardware sensor and interact with apps on your behalf."</string>
     <string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"Allow"</string>
     <string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"Deny"</string>
     <string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Tap a feature to start using it:"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 03534d0..95ef903 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1366,7 +1366,7 @@
     <string name="usb_power_notification_message" msgid="7284765627437897702">"Cargando el dispositivo conectado. Presiona para ver más opciones."</string>
     <string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Se detectó un accesorio de audio analógico"</string>
     <string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"El dispositivo adjunto no es compatible con este teléfono. Presiona para obtener más información."</string>
-    <string name="adb_active_notification_title" msgid="408390247354560331">"Depuración por USB conectada"</string>
+    <string name="adb_active_notification_title" msgid="408390247354560331">"Depuración por USB activada"</string>
     <string name="adb_active_notification_message" msgid="5617264033476778211">"Presiona para desactivar"</string>
     <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Seleccionar para desactivar la depuración por USB"</string>
     <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Se conectó la depuración inalámbrica"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 1361870..4f36d21 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1366,9 +1366,9 @@
     <string name="usb_power_notification_message" msgid="7284765627437897702">"Cargando el dispositivo conectado. Toca para ver más opciones."</string>
     <string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Se ha detectado un accesorio de audio analógico"</string>
     <string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"El dispositivo adjunto no es compatible con este teléfono. Toca para obtener más información."</string>
-    <string name="adb_active_notification_title" msgid="408390247354560331">"Depuración USB habilitada"</string>
-    <string name="adb_active_notification_message" msgid="5617264033476778211">"Toca para desactivar la depuración USB"</string>
-    <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Seleccionar para inhabilitar la depuración USB"</string>
+    <string name="adb_active_notification_title" msgid="408390247354560331">"Depuración por USB activa"</string>
+    <string name="adb_active_notification_message" msgid="5617264033476778211">"Toca para desactivar la depuración por USB"</string>
+    <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Seleccionar para inhabilitar la depuración por USB"</string>
     <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Depuración inalámbrica conectada"</string>
     <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Toca para desactivar la depuración inalámbrica"</string>
     <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Toca para desactivar la depuración inalámbrica."</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 21ed746c..07950b5 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1861,8 +1861,8 @@
     <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-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="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Bateria-aurreztaileak gai iluna aktibatzen du, eta atzeko planoko jarduerak, zenbait efektu bisual, eta eginbide jakin eta sareko konexio batzuk mugatzen edo desaktibatzen ditu."</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 mugatzen 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>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 627911b..2997d45 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -595,7 +595,7 @@
     <string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"حرکت انگشت خیلی آهسته بود. لطفاً دوباره امتحان کنید."</string>
     <string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"اثر انگشت دیگری را امتحان کنید"</string>
     <string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"خیلی روشن است"</string>
-    <string name="fingerprint_acquired_power_press" msgid="3107864151278434961">"فشردن دکمه روشن/ خاموش شناسایی شد"</string>
+    <string name="fingerprint_acquired_power_press" msgid="3107864151278434961">"فشردن دکمه روشن/خاموش شناسایی شد"</string>
     <string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"اثر انگشت را تنظیم کنید"</string>
     <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"هربار موقعیت انگشتتان را کمی تغییر دهید"</string>
   <string-array name="fingerprint_acquired_vendor">
@@ -617,7 +617,7 @@
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"این دستگاه حسگر اثر انگشت ندارد."</string>
     <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"حسگر به‌طور موقت غیرفعال است."</string>
     <string name="fingerprint_error_bad_calibration" msgid="4385512597740168120">"امکان استفاده از حسگر اثر انگشت وجود ندارد. به ارائه‌دهنده خدمات تعمیر مراجعه کنید"</string>
-    <string name="fingerprint_error_power_pressed" msgid="5479524500542129414">"دکمه روشن/ خاموش فشار داده شد"</string>
+    <string name="fingerprint_error_power_pressed" msgid="5479524500542129414">"دکمه روشن/خاموش فشار داده شد"</string>
     <string name="fingerprint_name_template" msgid="8941662088160289778">"انگشت <xliff:g id="FINGERID">%d</xliff:g>"</string>
     <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"استفاده از اثر انگشت"</string>
     <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"استفاده از اثر انگشت یا قفل صفحه"</string>
@@ -1252,11 +1252,11 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"آماده‌سازی <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"درحال آغاز کردن برنامه‌ها."</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"درحال اتمام راه‌اندازی."</string>
-    <string name="fp_power_button_enrollment_message" msgid="5648173517663246140">"دکمه روشن/ خاموش را فشار دادید — این کار معمولاً صفحه‌نمایش را خاموش می‌کند.\n\nهنگام راه‌اندازی اثر انگشت، آرام ضربه بزنید."</string>
+    <string name="fp_power_button_enrollment_message" msgid="5648173517663246140">"دکمه روشن/خاموش را فشار دادید — این کار معمولاً صفحه‌نمایش را خاموش می‌کند.\n\nهنگام راه‌اندازی اثر انگشت، آرام ضربه بزنید."</string>
     <string name="fp_power_button_enrollment_title" msgid="6976841690455338563">"برای اتمام راه‌اندازی، صفحه را خاموش کنید"</string>
     <string name="fp_power_button_enrollment_button_text" msgid="3199783266386029200">"خاموش کردن"</string>
     <string name="fp_power_button_bp_title" msgid="5585506104526820067">"تأیید اثر انگشت را ادامه می‌دهید؟"</string>
-    <string name="fp_power_button_bp_message" msgid="2983163038168903393">"دکمه روشن/ خاموش را فشار دادید — این کار معمولاً صفحه‌نمایش را خاموش می‌کند.\n\nبرای تأیید اثر انگشتتان، آرام ضربه بزنید."</string>
+    <string name="fp_power_button_bp_message" msgid="2983163038168903393">"دکمه روشن/خاموش را فشار دادید — این کار معمولاً صفحه‌نمایش را خاموش می‌کند.\n\nبرای تأیید اثر انگشتتان، آرام ضربه بزنید."</string>
     <string name="fp_power_button_bp_positive_button" msgid="728945472408552251">"خاموش کردن صفحه"</string>
     <string name="fp_power_button_bp_negative_button" msgid="3971364246496775178">"ادامه"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g> در حال اجرا"</string>
@@ -2041,7 +2041,7 @@
     <string name="mmcc_imsi_unknown_in_hlr_msim_template" msgid="3688508325248599657">"سیم‌کارت <xliff:g id="SIMNUMBER">%d</xliff:g> مجوز لازم را ندارد"</string>
     <string name="mmcc_illegal_ms_msim_template" msgid="832644375774599327">"سیم‌کارت <xliff:g id="SIMNUMBER">%d</xliff:g> مجاز نیست"</string>
     <string name="mmcc_illegal_me_msim_template" msgid="4802735138861422802">"سیم‌کارت <xliff:g id="SIMNUMBER">%d</xliff:g> مجاز نیست"</string>
-    <string name="popup_window_default_title" msgid="6907717596694826919">"پنجره بازشو"</string>
+    <string name="popup_window_default_title" msgid="6907717596694826919">"پنجره بالاپر"</string>
     <string name="slice_more_content" msgid="3377367737876888459">"‎+ <xliff:g id="NUMBER">%1$d</xliff:g>‎"</string>
     <string name="shortcut_restored_on_lower_version" msgid="9206301954024286063">"نسخه برنامه تنزل داده شده است یا با این میان‌بر سازگار نیست"</string>
     <string name="shortcut_restore_not_supported" msgid="4763198938588468400">"نمی‌توان میان‌بر را بازیابی کرد زیرا برنامه از پشتیبان‌گیری و بازیابی پشتیبانی نمی‌کند"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 64e91ad..e464da3 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1325,8 +1325,8 @@
     <string name="sms_control_yes" msgid="4858845109269524622">"Permitir"</string>
     <string name="sms_control_no" msgid="4845717880040355570">"Rexeitar"</string>
     <string name="sms_short_code_confirm_message" msgid="1385416688897538724">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; quere enviar unha mensaxe a &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt;."</string>
-    <string name="sms_short_code_details" msgid="2723725738333388351">"Esta acción "<b>"pode supoñer custos"</b>" na túa conta de teléfono móbil."</string>
-    <string name="sms_premium_short_code_details" msgid="1400296309866638111"><b>"Esta acción suporá custos na túa conta de teléfono móbil."</b></string>
+    <string name="sms_short_code_details" msgid="2723725738333388351">"Esta acción "<b>"pode supoñer custos"</b>" na conta do teu operador móbil."</string>
+    <string name="sms_premium_short_code_details" msgid="1400296309866638111"><b>"Esta acción suporá custos na conta do teu operador móbil."</b></string>
     <string name="sms_short_code_confirm_allow" msgid="920477594325526691">"Enviar"</string>
     <string name="sms_short_code_confirm_deny" msgid="1356917469323768230">"Cancelar"</string>
     <string name="sms_short_code_remember_choice" msgid="1374526438647744862">"Lembrar a miña opción"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 3c960169..9793b0c 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1354,7 +1354,7 @@
     <string name="no_permissions" msgid="5729199278862516390">"કોઈ પરવાનગીઓ જરૂરી નથી"</string>
     <string name="perm_costs_money" msgid="749054595022779685">"આનાથી તમારા પૈસા ખર્ચ થઈ શકે છે"</string>
     <string name="dlg_ok" msgid="5103447663504839312">"ઓકે"</string>
-    <string name="usb_charging_notification_title" msgid="1674124518282666955">"આ ડિવાઇસને USB મારફતે ચાર્જ કરી રહ્યાં છીએ"</string>
+    <string name="usb_charging_notification_title" msgid="1674124518282666955">"આ ડિવાઇસને USB મારફતે ચાર્જ કરી રહ્યાં છીએ."</string>
     <string name="usb_supplying_notification_title" msgid="5378546632408101811">"કનેક્ટેડ ઉપકરણને USB મારફતે ચાર્જ કરી રહ્યાં છીએ"</string>
     <string name="usb_mtp_notification_title" msgid="1065989144124499810">"USB ફાઇલ ટ્રાન્સફર ચાલુ છે"</string>
     <string name="usb_ptp_notification_title" msgid="5043437571863443281">"USB મારફતે PTP ચાલુ કર્યું"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index a20714d..dff96b7 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1691,7 +1691,7 @@
     <string name="accessibility_enable_service_title" msgid="3931558336268541484">"<xliff:g id="SERVICE">%1$s</xliff:g> को अपना डिवाइस पूरी तरह कंट्रोल करने की मंज़ूरी दें?"</string>
     <string name="accessibility_service_warning_description" msgid="291674995220940133">"पूरी तरह कंट्रोल करने की अनुमति उन ऐप्लिकेशन के लिए ठीक है जो सुलभता से जुड़ी ज़रूरतों के लिए बने हैं, लेकिन ज़्यादातर ऐप्लिकेशन के लिए यह ठीक नहीं है."</string>
     <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"स्क्रीन को देखें और कंट्रोल करें"</string>
-    <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"यह स्क्रीन पर दिखने वाली हर तरह के कॉन्टेंट को पढ़ सकता है और उसे दूसरे ऐप्लिकेशन पर दिखा सकता है."</string>
+    <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"यह स्क्रीन पर दिखने वाले कॉन्टेंट को पढ़ सकता है और उसे दूसरे ऐप्लिकेशन के ऊपर दिखा सकता है."</string>
     <string name="accessibility_service_action_perform_title" msgid="779670378951658160">"देखें और कार्रवाई करें"</string>
     <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"यह आपके और किसी ऐप्लिकेशन या हार्डवेयर सेंसर के बीच होने वाले इंटरैक्शन को ट्रैक कर सकता है और आपकी तरफ़ से ऐप्लिकेशन के साथ इंटरैक्ट कर सकता है."</string>
     <string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"अनुमति दें"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 403afad..daad65f 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -298,7 +298,7 @@
     <string name="safeMode" msgid="8974401416068943888">"Modalità provvisoria"</string>
     <string name="android_system_label" msgid="5974767339591067210">"Sistema Android"</string>
     <string name="user_owner_label" msgid="8628726904184471211">"Passa al profilo personale"</string>
-    <string name="managed_profile_label" msgid="7316778766973512382">"Passa a profilo di lavoro"</string>
+    <string name="managed_profile_label" msgid="7316778766973512382">"Passa al profilo di lavoro"</string>
     <string name="permgrouplab_contacts" msgid="4254143639307316920">"Contatti"</string>
     <string name="permgroupdesc_contacts" msgid="9163927941244182567">"Possono accedere ai contatti"</string>
     <string name="permgrouplab_location" msgid="1858277002233964394">"Posizione"</string>
@@ -1692,7 +1692,7 @@
     <string name="accessibility_enable_service_title" msgid="3931558336268541484">"Vuoi consentire a <xliff:g id="SERVICE">%1$s</xliff:g> di avere il controllo totale del tuo dispositivo?"</string>
     <string name="accessibility_service_warning_description" msgid="291674995220940133">"Il controllo totale è appropriato per le app che rispondono alle tue esigenze di accessibilità, ma non per gran parte delle app."</string>
     <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"Visualizzare e controllare lo schermo"</string>
-    <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"Può leggere i contenuti presenti sullo schermo e mostrare i contenuti su altre app."</string>
+    <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"Può leggere tutti i contenuti presenti sullo schermo e mostrare i contenuti sopra altre app."</string>
     <string name="accessibility_service_action_perform_title" msgid="779670378951658160">"Visualizzare ed eseguire azioni"</string>
     <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"Può tenere traccia delle tue interazioni con un\'app o un sensore hardware e interagire con app per tuo conto."</string>
     <string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"Consenti"</string>
@@ -1979,7 +1979,7 @@
     <string name="app_info" msgid="6113278084877079851">"Informazioni app"</string>
     <string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="demo_starting_message" msgid="6577581216125805905">"Avvio della demo…"</string>
-    <string name="demo_restarting_message" msgid="1160053183701746766">"Ripristino del dispositivo…"</string>
+    <string name="demo_restarting_message" msgid="1160053183701746766">"Reset del dispositivo…"</string>
     <string name="suspended_widget_accessibility" msgid="6331451091851326101">"Widget <xliff:g id="LABEL">%1$s</xliff:g> disattivato"</string>
     <string name="conference_call" msgid="5731633152336490471">"Audioconferenza"</string>
     <string name="tooltip_popup_title" msgid="7863719020269945722">"Descrizione comando"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index bbfe134..3fd0fae 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1354,7 +1354,7 @@
     <string name="no_permissions" msgid="5729199278862516390">"권한 필요 없음"</string>
     <string name="perm_costs_money" msgid="749054595022779685">"비용이 부과될 수 있습니다."</string>
     <string name="dlg_ok" msgid="5103447663504839312">"확인"</string>
-    <string name="usb_charging_notification_title" msgid="1674124518282666955">"이 기기를 USB로 충전 중"</string>
+    <string name="usb_charging_notification_title" msgid="1674124518282666955">"이 기기를 USB로 충전 중."</string>
     <string name="usb_supplying_notification_title" msgid="5378546632408101811">"USB를 통해 연결된 기기 충전"</string>
     <string name="usb_mtp_notification_title" msgid="1065989144124499810">"USB 파일 전송 사용 설정됨"</string>
     <string name="usb_ptp_notification_title" msgid="5043437571863443281">"USB를 통해 PTP 사용 설정됨"</string>
@@ -1365,7 +1365,7 @@
     <string name="usb_power_notification_message" msgid="7284765627437897702">"연결된 기기를 충전합니다. 옵션을 더 보려면 탭하세요."</string>
     <string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"아날로그 오디오 액세서리가 감지됨"</string>
     <string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"연결된 기기가 이 휴대전화와 호환되지 않습니다. 자세히 알아보려면 탭하세요."</string>
-    <string name="adb_active_notification_title" msgid="408390247354560331">"USB 디버깅 연결됨"</string>
+    <string name="adb_active_notification_title" msgid="408390247354560331">"USB 디버깅 연결됨."</string>
     <string name="adb_active_notification_message" msgid="5617264033476778211">"USB 디버깅을 사용 중지하려면 탭하세요."</string>
     <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB 디버깅을 사용하지 않으려면 선택합니다."</string>
     <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"무선 디버깅 연결됨"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index fdf22a9..100a563 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1416,7 +1416,7 @@
     <string name="ext_media_unmountable_notification_message" product="automotive" msgid="2274596120715020680">"Түзмөктү форматташыңыз керек болушу мүмкүн. Чыгаруу үчүн таптап коюңуз."</string>
     <string name="ext_media_unsupported_notification_title" msgid="3487534182861251401">"<xliff:g id="NAME">%s</xliff:g> аныкталды"</string>
     <string name="ext_media_unsupported_notification_title" product="automotive" msgid="6004193172658722381">"<xliff:g id="NAME">%s</xliff:g> иштебей жатат"</string>
-    <string name="ext_media_unsupported_notification_message" msgid="8463636521459807981">"Тууралоо үчүн таптаңыз."</string>
+    <string name="ext_media_unsupported_notification_message" msgid="8463636521459807981">"Орнотуу үчүн басыңыз."</string>
     <string name="ext_media_unsupported_notification_message" product="tv" msgid="1595482802187036532">"Колдоого алынуучу форматта орнотуу үчүн <xliff:g id="NAME">%s</xliff:g> тандаңыз."</string>
     <string name="ext_media_unsupported_notification_message" product="automotive" msgid="3412494732736336330">"Түзмөктү форматташыңыз керек болушу мүмкүн"</string>
     <string name="ext_media_badremoval_notification_title" msgid="4114625551266196872">"<xliff:g id="NAME">%s</xliff:g> күтүүсүздөн өчүрүлдү"</string>
diff --git a/core/res/res/values-mcc334-mnc020-th/strings.xml b/core/res/res/values-mcc334-mnc020-th/strings.xml
index e4e62f0..dfd73ab 100644
--- a/core/res/res/values-mcc334-mnc020-th/strings.xml
+++ b/core/res/res/values-mcc334-mnc020-th/strings.xml
@@ -20,7 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string>
-    <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"การตรวจสอบสิทธิ์ล้มเหลว -29-"</string>
+    <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"การตรวจสอบสิทธิ์ไม่สำเร็จ -29-"</string>
     <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"ไม่ได้สมัครใช้บริการ -33-"</string>
     <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"ไม่อนุญาตการเชื่อมต่อ PDN หลายรายการสำหรับ APN ที่กำหนด -55-"</string>
 </resources>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 1e08228..513be11 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -587,11 +587,11 @@
     <string name="biometric_error_generic" msgid="6784371929985434439">"एरर ऑथेंटिकेट करत आहे"</string>
     <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"स्क्रीन लॉक वापरा"</string>
     <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"पुढे सुरू ठेवण्यासाठी तुमचे स्क्रीन लॉक एंटर करा"</string>
-    <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"सेन्सरवर जोरात दाबा"</string>
+    <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"सेन्सरवर जोरात प्रेस करा"</string>
     <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"फिंगरप्रिंट ओळखता आली नाही. पुन्हा प्रयत्न करा."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"फिंगरप्रिंट सेन्सर स्वच्छ करा आणि पुन्हा प्रयत्न करा"</string>
     <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"सेन्सर स्वच्छ करा आणि पुन्हा प्रयत्न करा"</string>
-    <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"सेन्सरवर जोरात दाबा"</string>
+    <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"सेन्सरवर जोरात प्रेस करा"</string>
     <string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"बोट खूप सावकाश हलविले. कृपया पुन्हा प्रयत्न करा."</string>
     <string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"दुसरी फिंगरप्रिंट वापरून पहा"</string>
     <string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"खूप प्रखर"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index dca9de6..ccf74a4 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -2014,7 +2014,7 @@
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Kemas kini <xliff:g id="TYPE_0">%1$s</xliff:g> dan <xliff:g id="TYPE_1">%2$s</xliff:g> dalam "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_3types" msgid="1312232153076212291">"Kemas kini item ini dalam "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> dan <xliff:g id="TYPE_2">%3$s</xliff:g> ?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Simpan"</string>
-    <string name="autofill_save_no" msgid="9212826374207023544">"Tidak, terima kasih"</string>
+    <string name="autofill_save_no" msgid="9212826374207023544">"Tidak perlu"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Bukan sekarang"</string>
     <string name="autofill_save_never" msgid="6821841919831402526">"Jangan"</string>
     <string name="autofill_update_yes" msgid="4608662968996874445">"Kemas kini"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index ba43d79..42afe18 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1691,9 +1691,9 @@
     <string name="accessibility_enable_service_title" msgid="3931558336268541484">"Toestaan dat <xliff:g id="SERVICE">%1$s</xliff:g> volledige controle over je apparaat heeft?"</string>
     <string name="accessibility_service_warning_description" msgid="291674995220940133">"Volledige controle is gepast voor apps die je helpen met toegankelijkheid, maar niet voor de meeste apps."</string>
     <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"Scherm bekijken en bedienen"</string>
-    <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"De functie kan alle content op het scherm lezen en content bovenop andere apps weergeven."</string>
+    <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"Deze functie kan alle content op het scherm lezen en content bovenop andere apps weergeven."</string>
     <string name="accessibility_service_action_perform_title" msgid="779670378951658160">"Acties bekijken en uitvoeren"</string>
-    <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"De functie kan je interacties met een app of een hardwaresensor bijhouden en namens jou met apps communiceren."</string>
+    <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"Deze functie kan je interacties met een app of een hardwaresensor bijhouden en namens jou met apps communiceren."</string>
     <string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"Toestaan"</string>
     <string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"Weigeren"</string>
     <string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Tik op een functie om deze te gebruiken:"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index b37d01c..0ac3a37 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -1861,7 +1861,7 @@
     <string name="package_updated_device_owner" msgid="7560272363805506941">"ଆପଣଙ୍କ ଆଡମିନ୍‌‌ ଅପଡେଟ୍‍ କରିଛନ୍ତି"</string>
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"ଆପଣଙ୍କ ଆଡମିନ୍‌‌ ଡିଲିଟ୍‍ କରିଛନ୍ତି"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ଠିକ୍ ଅଛି"</string>
-    <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"ବ୍ୟାଟେରୀ ସେଭର୍ ଗାଢ଼ା ଥିମକୁ ଚାଲୁ କରେ ଏବଂ ପୃଷ୍ଠପଟ କାର୍ଯ୍ୟକଳାପ, କିଛି ଭିଜୁଆଲ୍ ଇଫେକ୍ଟ, କିଛି ଫିଚର୍ ଏବଂ କିଛି ନେଟୱାର୍କ ସଂଯୋଗକୁ ସୀମିତ କିମ୍ବା ବନ୍ଦ କରେ।"</string>
+    <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"ବେଟେରୀ ସେଭର ଗାଢ଼ା ଥିମକୁ ଚାଲୁ କରେ ଏବଂ ପୃଷ୍ଠପଟ କାର୍ଯ୍ୟକଳାପ, କିଛି ଭିଜୁଆଲ ଇଫେକ୍ଟ, କିଛି ଫିଚର ଏବଂ କିଛି ନେଟୱାର୍କ ସଂଯୋଗକୁ ସୀମିତ କିମ୍ବା ବନ୍ଦ କରେ।"</string>
     <string name="battery_saver_description" msgid="8518809702138617167">"ବ୍ୟାଟେରୀ ସେଭର୍ ଗାଢ଼ା ଥିମକୁ ଚାଲୁ କରେ ଏବଂ ପୃଷ୍ଠପଟ କାର୍ଯ୍ୟକଳାପ, କିଛି ଭିଜୁଆଲ୍ ଇଫେକ୍ଟ, କିଛି ଫିଚର୍ ଏବଂ କିଛି ନେଟୱାର୍କ ସଂଯୋଗକୁ ସୀମିତ କିମ୍ବା ବନ୍ଦ କରେ।"</string>
     <string name="data_saver_description" msgid="4995164271550590517">"ଡାଟା ବ୍ୟବହାର କମ୍‍ କରିବାରେ ସାହାଯ୍ୟ କରିବାକୁ, ଡାଟା ସେଭର୍‍ ବ୍ୟାକ୍‌ଗ୍ରାଉଣ୍ଡରେ ଡାଟା ପଠାଇବା କିମ୍ବା ପ୍ରାପ୍ତ କରିବାକୁ କିଛି ଆପ୍‍କୁ ବାରଣ କରେ। ଆପଣ ବର୍ତ୍ତମାନ ବ୍ୟବହାର କରୁଥିବା ଆପ୍‍, ଡାଟା ଆକ୍ସେସ୍‍ କରିପାରେ, କିନ୍ତୁ ଏହା କମ୍‍ ଥର କରିପାରେ। ଏହାର ଅର୍ଥ ହୋଇପାରେ ଯେମିତି ଆପଣ ଇମେଜଗୁଡ଼ିକୁ ଟାପ୍‍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ସେଗୁଡ଼ିକ ଡିସପ୍ଲେ ହୁଏ ନାହିଁ।"</string>
     <string name="data_saver_enable_title" msgid="7080620065745260137">"ଡାଟା ସେଭର୍‌ ଚାଲୁ କରିବେ?"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index b6fbbea..8ddf065 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -561,7 +561,7 @@
     <string name="permdesc_requestPasswordComplexity" msgid="1130556896836258567">"Permite que a app aprenda o nível de complexidade do bloqueio de ecrã (elevado, médio, baixo ou nenhum), que indica o intervalo de comprimento e o tipo de bloqueio de ecrã possíveis. A app também pode sugerir aos utilizadores que atualizem o bloqueio de ecrã para um determinado nível, mas estes podem ignorar livremente a sugestão e continuar a navegação. Tenha em atenção que o bloqueio de ecrã não é armazenado em texto simples, pelo que a app desconhece a palavra-passe exata."</string>
     <string name="permlab_postNotification" msgid="4875401198597803658">"mostrar notificações"</string>
     <string name="permdesc_postNotification" msgid="5974977162462877075">"Permite à app mostrar notificações"</string>
-    <string name="permlab_useBiometric" msgid="6314741124749633786">"Utilizar hardware biométrico"</string>
+    <string name="permlab_useBiometric" msgid="6314741124749633786">"Usar hardware biométrico"</string>
     <string name="permdesc_useBiometric" msgid="7502858732677143410">"Permite que a app utilize hardware biométrico para autenticação."</string>
     <string name="permlab_manageFingerprint" msgid="7432667156322821178">"gerir o hardware de impressão digital"</string>
     <string name="permdesc_manageFingerprint" msgid="2025616816437339865">"Permite que a app invoque métodos para adicionar e eliminar modelos de impressão digital para utilização."</string>
@@ -575,8 +575,8 @@
     <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Permite que a app modifique a sua coleção de fotos."</string>
     <string name="permlab_mediaLocation" msgid="7368098373378598066">"ler as localizações a partir da sua coleção de multimédia"</string>
     <string name="permdesc_mediaLocation" msgid="597912899423578138">"Permite que a app leia as localizações a partir da sua coleção de multimédia."</string>
-    <string name="biometric_app_setting_name" msgid="3339209978734534457">"Utilizar a biometria"</string>
-    <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Utilizar a biometria ou o bloqueio de ecrã"</string>
+    <string name="biometric_app_setting_name" msgid="3339209978734534457">"Usar a biometria"</string>
+    <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Usar a biometria ou o bloqueio de ecrã"</string>
     <string name="biometric_dialog_default_title" msgid="55026799173208210">"Confirme a sua identidade"</string>
     <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Utilize a biometria para continuar."</string>
     <string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Utilize a biometria ou o bloqueio de ecrã para continuar"</string>
@@ -586,7 +586,7 @@
     <string name="biometric_error_canceled" msgid="8266582404844179778">"Autenticação cancelada"</string>
     <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nenhum PIN, padrão ou palavra-passe definidos."</string>
     <string name="biometric_error_generic" msgid="6784371929985434439">"Erro ao autenticar."</string>
-    <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Utilizar o bloqueio de ecrã"</string>
+    <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Usar o bloqueio de ecrã"</string>
     <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Introduza o bloqueio de ecrã para continuar"</string>
     <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Prima firmemente o sensor"</string>
     <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Não é possível reconhecer a impressão digital. Tente novamente."</string>
@@ -620,8 +620,8 @@
     <string name="fingerprint_error_bad_calibration" msgid="4385512597740168120">"Não é possível usar o sensor de impressões digitais. Visite um fornecedor de serviços de reparação"</string>
     <string name="fingerprint_error_power_pressed" msgid="5479524500542129414">"Botão ligar/desligar premido"</string>
     <string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string>
-    <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Utilizar a impressão digital"</string>
-    <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Utilizar o bloqueio de ecrã ou a impressão digital"</string>
+    <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Usar a impressão digital"</string>
+    <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Usar o bloqueio de ecrã ou a impressão digital"</string>
     <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Utilize a sua impressão digital para continuar."</string>
     <string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Utilize a impressão digital ou o bloqueio de ecrã para continuar"</string>
   <string-array name="fingerprint_error_vendor">
@@ -681,8 +681,8 @@
     <string name="face_error_hw_not_present" msgid="7940978724978763011">"O Desbloqueio facial não é suportado neste dispositivo"</string>
     <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor temporariamente desativado."</string>
     <string name="face_name_template" msgid="3877037340223318119">"Rosto <xliff:g id="FACEID">%d</xliff:g>"</string>
-    <string name="face_app_setting_name" msgid="5854024256907828015">"Utilizar o Desbloqueio facial"</string>
-    <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Utilizar o bloqueio através do rosto ou de ecrã"</string>
+    <string name="face_app_setting_name" msgid="5854024256907828015">"Usar o Desbloqueio facial"</string>
+    <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Usar o bloqueio através do rosto ou de ecrã"</string>
     <string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Utilize o rosto para continuar"</string>
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Utilize o rosto ou o bloqueio de ecrã para continuar"</string>
   <string-array name="face_error_vendor">
@@ -1196,13 +1196,13 @@
     <string name="whichSendToApplicationNamed" msgid="3385686512014670003">"Enviar com %1$s"</string>
     <string name="whichSendToApplicationLabel" msgid="3543240188816513303">"Enviar"</string>
     <string name="whichHomeApplication" msgid="8276350727038396616">"Selecione uma app Página inicial"</string>
-    <string name="whichHomeApplicationNamed" msgid="5855990024847433794">"Utilizar %1$s como Página inicial"</string>
+    <string name="whichHomeApplicationNamed" msgid="5855990024847433794">"Usar %1$s como Página inicial"</string>
     <string name="whichHomeApplicationLabel" msgid="8907334282202933959">"Capturar imagem"</string>
     <string name="whichImageCaptureApplication" msgid="2737413019463215284">"Capturar imagem com"</string>
     <string name="whichImageCaptureApplicationNamed" msgid="8820702441847612202">"Capturar imagem com o %1$s"</string>
     <string name="whichImageCaptureApplicationLabel" msgid="6505433734824988277">"Capturar imagem"</string>
-    <string name="alwaysUse" msgid="3153558199076112903">"Utilizar por predefinição para esta ação."</string>
-    <string name="use_a_different_app" msgid="4987790276170972776">"Utilizar outra app"</string>
+    <string name="alwaysUse" msgid="3153558199076112903">"Usar por predefinição para esta ação."</string>
+    <string name="use_a_different_app" msgid="4987790276170972776">"Usar outra app"</string>
     <string name="clearDefaultHintMsg" msgid="1325866337702524936">"Limpar a predefinição nas Definições do Sistema &gt; Apps &gt; Transferidas."</string>
     <string name="chooseActivity" msgid="8563390197659779956">"Escolha uma ação"</string>
     <string name="chooseUsbActivity" msgid="2096269989990986612">"Escolher uma app para o dispositivo USB"</string>
@@ -1704,7 +1704,7 @@
     <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Editar atalhos"</string>
     <string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Concluído"</string>
     <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Desativar atalho"</string>
-    <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Utilizar atalho"</string>
+    <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Usar atalho"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Inversão de cores"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Correção da cor"</string>
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modo para uma mão"</string>
@@ -2160,8 +2160,8 @@
     <string name="resolver_no_personal_apps_available" msgid="6284837227019594881">"Sem apps pessoais"</string>
     <string name="miniresolver_open_in_personal" msgid="3874522693661065566">"Abrir a app <xliff:g id="APP">%s</xliff:g> no seu perfil pessoal?"</string>
     <string name="miniresolver_open_in_work" msgid="4415223793669536559">"Abrir a app <xliff:g id="APP">%s</xliff:g> no seu perfil de trabalho?"</string>
-    <string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Utilizar navegador pessoal"</string>
-    <string name="miniresolver_use_work_browser" msgid="543575306251952994">"Utilizar navegador de trabalho"</string>
+    <string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Usar navegador pessoal"</string>
+    <string name="miniresolver_use_work_browser" msgid="543575306251952994">"Usar navegador de trabalho"</string>
     <string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"PIN para desbloqueio de rede do cartão SIM"</string>
     <string name="PERSOSUBSTATE_SIM_NETWORK_SUBSET_ENTRY" msgid="7164399703751688214">"PIN para desbloqueio do subconjunto da rede do cartão SIM"</string>
     <string name="PERSOSUBSTATE_SIM_CORPORATE_ENTRY" msgid="4447629474818217364">"PIN para desbloqueio empresarial do cartão SIM"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index a2df463..4fa6506 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1356,7 +1356,7 @@
     <string name="no_permissions" msgid="5729199278862516390">"Не требуется разрешений"</string>
     <string name="perm_costs_money" msgid="749054595022779685">"это может стоить вам денег!"</string>
     <string name="dlg_ok" msgid="5103447663504839312">"ОК"</string>
-    <string name="usb_charging_notification_title" msgid="1674124518282666955">"Зарядка устройства через USB…"</string>
+    <string name="usb_charging_notification_title" msgid="1674124518282666955">"Зарядка устройства через USB"</string>
     <string name="usb_supplying_notification_title" msgid="5378546632408101811">"Зарядка устройства через USB…"</string>
     <string name="usb_mtp_notification_title" msgid="1065989144124499810">"Передача файлов через USB включена"</string>
     <string name="usb_ptp_notification_title" msgid="5043437571863443281">"Режим PTP включен"</string>
@@ -1863,8 +1863,8 @@
     <string name="package_updated_device_owner" msgid="7560272363805506941">"Обновлено администратором"</string>
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Удалено администратором"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string>
-    <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"В режиме энергосбережения включается тёмная тема, ограничиваются или отключаются фоновые процессы, а также некоторые визуальные эффекты, функции и сетевые подключения."</string>
-    <string name="battery_saver_description" msgid="8518809702138617167">"В режиме энергосбережения включается тёмная тема, ограничиваются или отключаются фоновые процессы, а также некоторые визуальные эффекты, функции и сетевые подключения."</string>
+    <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"В режиме энергосбережения включается тёмная тема, ограничиваются или отключаются фоновые процессы, а также некоторые визуальные эффекты, часть функций и сетевых подключений."</string>
+    <string name="battery_saver_description" msgid="8518809702138617167">"В режиме энергосбережения включается тёмная тема, ограничиваются или отключаются фоновые процессы, а также некоторые визуальные эффекты, часть функций и сетевых подключений."</string>
     <string name="data_saver_description" msgid="4995164271550590517">"В режиме экономии трафика фоновая передача данных для некоторых приложений отключена. Приложение, которым вы пользуетесь, может получать и отправлять данные, но реже, чем обычно. Например, изображения могут не загружаться, пока вы не нажмете на них."</string>
     <string name="data_saver_enable_title" msgid="7080620065745260137">"Включить экономию трафика?"</string>
     <string name="data_saver_enable_button" msgid="4399405762586419726">"Включить"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index d84a751..c1fe87f 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1367,7 +1367,7 @@
     <string name="usb_power_notification_message" msgid="7284765627437897702">"Pripojené zariadenie sa nabíja. Ďalšie možností získate klepnutím."</string>
     <string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Bolo zistené analógové zvukové príslušenstvo"</string>
     <string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"Pripojené zariadenie nie je kompatibilné s týmto telefónom. Ďalšie informácie zobrazíte klepnutím."</string>
-    <string name="adb_active_notification_title" msgid="408390247354560331">"Ladenie cez USB pripojené"</string>
+    <string name="adb_active_notification_title" msgid="408390247354560331">"Ladenie cez USB je pripojené"</string>
     <string name="adb_active_notification_message" msgid="5617264033476778211">"Klepnutím vypnite ladenie cez USB"</string>
     <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Vyberte, ak chcete zakázať ladenie cez USB."</string>
     <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Bezdrôtové ladenie je pripojené"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index c822b5c..de202421 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -300,7 +300,7 @@
     <string name="managed_profile_label" msgid="7316778766973512382">"Byt till jobbprofilen"</string>
     <string name="permgrouplab_contacts" msgid="4254143639307316920">"Kontakter"</string>
     <string name="permgroupdesc_contacts" msgid="9163927941244182567">"få tillgång till dina kontakter"</string>
-    <string name="permgrouplab_location" msgid="1858277002233964394">"Plats"</string>
+    <string name="permgrouplab_location" msgid="1858277002233964394">"plats"</string>
     <string name="permgroupdesc_location" msgid="1995955142118450685">"komma åt enhetens platsuppgifter"</string>
     <string name="permgrouplab_calendar" msgid="6426860926123033230">"Kalender"</string>
     <string name="permgroupdesc_calendar" msgid="6762751063361489379">"få tillgång till din kalender"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 8eddb31..0b29b9d 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -227,9 +227,9 @@
     <string name="reboot_to_update_title" msgid="2125818841916373708">"Оновлення системи Android"</string>
     <string name="reboot_to_update_prepare" msgid="6978842143587422365">"Підготовка до оновлення…"</string>
     <string name="reboot_to_update_package" msgid="4644104795527534811">"Обробка пакета оновлення…"</string>
-    <string name="reboot_to_update_reboot" msgid="4474726009984452312">"Перезавантаження…"</string>
+    <string name="reboot_to_update_reboot" msgid="4474726009984452312">"Перезапуск…"</string>
     <string name="reboot_to_reset_title" msgid="2226229680017882787">"Скидання налаштувань"</string>
-    <string name="reboot_to_reset_message" msgid="3347690497972074356">"Перезавантаження…"</string>
+    <string name="reboot_to_reset_message" msgid="3347690497972074356">"Перезапуск…"</string>
     <string name="shutdown_progress" msgid="5017145516412657345">"Вимкнення..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="2872769463279602432">"Ваш пристрій буде вимкнено."</string>
     <string name="shutdown_confirm" product="tv" msgid="7975942887313518330">"Пристрій Android TV буде вимкнено."</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index dafa0ad..46aaa1f 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -727,20 +727,22 @@
          mode. -->
     <integer name="config_unfoldTransitionHalfFoldedTimeout">1000</integer>
 
+    <!-- Timeout for receiving the keyguard drawn event from System UI.  -->
+    <integer name="config_keyguardDrawnTimeout">1000</integer>
+
     <!-- Indicates that the device supports having more than one internal display on at the same
          time. Only applicable to devices with more than one internal display. If this option is
          set to false, DisplayManager will make additional effort to ensure no more than 1 internal
          display is powered on at the same time. -->
     <bool name="config_supportsConcurrentInternalDisplays">true</bool>
 
-    <!-- Map of DeviceState to rotation lock setting. Each entry must be in the format
-         "key:value", for example: "0:1".
-          The keys are device states, and the values are one of
-          Settings.Secure.DeviceStateRotationLockSetting.
-          Any device state that doesn't have a default set here will be treated as
-          DEVICE_STATE_ROTATION_LOCK_IGNORED meaning it will not have its own rotation lock setting.
-          If this map is missing, the feature is disabled and only one global rotation lock setting
-           will apply, regardless of device state. -->
+    <!-- Map of device posture to rotation lock setting. Each entry must be in the format
+         "key:value", or "key:value:fallback_key" for example: "0:1" or "2:0:1". The keys are one of
+         Settings.Secure.DeviceStateRotationLockKey, and the values are one of
+         Settings.Secure.DeviceStateRotationLockSetting.
+         The fallback is a key to a device posture that can be specified when the value is
+         Settings.Secure.DEVICE_STATE_ROTATION_LOCK_IGNORED.
+     -->
     <string-array name="config_perDeviceStateRotationLockDefaults" />
 
     <!-- Dock behavior -->
@@ -769,6 +771,11 @@
          we rely on gravity to determine the effective orientation. -->
     <bool name="config_deskDockEnablesAccelerometer">true</bool>
 
+    <!-- Control whether nosensor and locked orientation requests are respected from the app when
+         config_deskDockEnablesAccelerometer is set to false.
+         TODO(b/274763533): Consider making true by default and removing this. -->
+    <bool name="config_deskRespectsNoSensorAndLockedWithoutAccelerometer">false</bool>
+
     <!-- Car dock behavior -->
 
     <!-- The number of degrees to rotate the display when the device is in a car dock.
@@ -5043,6 +5050,11 @@
          of known compatibility issues. -->
     <string-array name="config_highRefreshRateBlacklist"></string-array>
 
+    <!-- The list of packages to force slowJpegMode for Apps using Camera API1 -->
+    <string-array name="config_forceSlowJpegModeList" translatable="false">
+        <!-- Add packages here -->
+    </string-array>
+
     <!-- Whether or not to hide the navigation bar when the soft keyboard is visible in order to
          create additional screen real estate outside beyond the keyboard. Note that the user needs
          to have a confirmed way to dismiss the keyboard when desired. -->
@@ -5331,6 +5343,10 @@
     <!-- Whether vertical reachability repositioning is allowed for letterboxed fullscreen apps. -->
     <bool name="config_letterboxIsVerticalReachabilityEnabled">false</bool>
 
+    <!-- Whether book mode automatic horizontal reachability positioning is allowed for letterboxed
+        fullscreen apps -->
+    <bool name="config_letterboxIsAutomaticReachabilityInBookModeEnabled">false</bool>
+
     <!-- Default horizontal position of the letterboxed app window when reachability is
         enabled and an app is fullscreen in landscape device orientation. When reachability is
         enabled, the position can change between left, center and right. This config defines the
@@ -6092,4 +6108,8 @@
 
     <!-- Whether to show weather on the lock screen by default. -->
     <bool name="config_lockscreenWeatherEnabledByDefault">false</bool>
+
+    <!-- Whether we should persist the brightness value in nits for the default display even if
+         the underlying display device changes. -->
+    <bool name="config_persistBrightnessNitsForDefaultDisplay">false</bool>
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 591ba5f..1a3feb8 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1739,6 +1739,7 @@
   <java-symbol type="bool" name="config_carDockEnablesAccelerometer" />
   <java-symbol type="bool" name="config_customUserSwitchUi" />
   <java-symbol type="bool" name="config_deskDockEnablesAccelerometer" />
+  <java-symbol type="bool" name="config_deskRespectsNoSensorAndLockedWithoutAccelerometer" />
   <java-symbol type="bool" name="config_disableMenuKeyInLockScreen" />
   <java-symbol type="bool" name="config_enableCarDockHomeLaunch" />
   <java-symbol type="bool" name="config_enableLockBeforeUnlockScreen" />
@@ -1987,6 +1988,7 @@
   <java-symbol type="bool" name="config_allowTheaterModeWakeFromDock" />
   <java-symbol type="bool" name="config_allowTheaterModeWakeFromWindowLayout" />
   <java-symbol type="bool" name="config_keepDreamingWhenUndocking" />
+  <java-symbol type="integer" name="config_keyguardDrawnTimeout" />
   <java-symbol type="bool" name="config_goToSleepOnButtonPressTheaterMode" />
   <java-symbol type="bool" name="config_supportLongPressPowerWhenNonInteractive" />
   <java-symbol type="bool" name="config_wimaxEnabled" />
@@ -2282,6 +2284,7 @@
   <java-symbol type="bool" name="config_preventImeStartupUnlessTextEditor" />
   <java-symbol type="array" name="config_nonPreemptibleInputMethods" />
   <java-symbol type="bool" name="config_enhancedConfirmationModeEnabled" />
+  <java-symbol type="bool" name="config_persistBrightnessNitsForDefaultDisplay" />
 
   <java-symbol type="layout" name="resolver_list" />
   <java-symbol type="id" name="resolver_list" />
@@ -4213,6 +4216,7 @@
 
   <java-symbol type="string" name="config_factoryResetPackage" />
   <java-symbol type="array" name="config_highRefreshRateBlacklist" />
+  <java-symbol type="array" name="config_forceSlowJpegModeList" />
 
   <java-symbol type="layout" name="chooser_dialog" />
   <java-symbol type="layout" name="chooser_dialog_item" />
@@ -4473,6 +4477,7 @@
   <java-symbol type="dimen" name="config_letterboxTabletopModePositionMultiplier" />
   <java-symbol type="bool" name="config_letterboxIsHorizontalReachabilityEnabled" />
   <java-symbol type="bool" name="config_letterboxIsVerticalReachabilityEnabled" />
+  <java-symbol type="bool" name="config_letterboxIsAutomaticReachabilityInBookModeEnabled" />
   <java-symbol type="integer" name="config_letterboxDefaultPositionForHorizontalReachability" />
   <java-symbol type="integer" name="config_letterboxDefaultPositionForVerticalReachability" />
   <java-symbol type="integer" name="config_letterboxDefaultPositionForBookModeReachability" />
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java
index eae1bbc..17ed4c4 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java
@@ -15,6 +15,8 @@
  */
 package android.view.contentcapture;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.Mockito.mock;
 import static org.testng.Assert.assertThrows;
 
@@ -54,4 +56,19 @@
 
         assertThrows(NullPointerException.class, () -> manager.removeData(null));
     }
+
+    @Test
+    @SuppressWarnings("GuardedBy")
+    public void testFlushViewTreeAppearingEventDisabled_setAndGet() {
+        final IContentCaptureManager mockService = mock(IContentCaptureManager.class);
+        final ContentCaptureOptions options = new ContentCaptureOptions(null);
+        final ContentCaptureManager manager =
+                new ContentCaptureManager(mMockContext, mockService, options);
+
+        assertThat(manager.getFlushViewTreeAppearingEventDisabled()).isFalse();
+        manager.setFlushViewTreeAppearingEventDisabled(true);
+        assertThat(manager.getFlushViewTreeAppearingEventDisabled()).isTrue();
+        manager.setFlushViewTreeAppearingEventDisabled(false);
+        assertThat(manager.getFlushViewTreeAppearingEventDisabled()).isFalse();
+    }
 }
diff --git a/core/tests/coretests/src/com/android/internal/app/procstats/ProcessStatsTest.java b/core/tests/coretests/src/com/android/internal/app/procstats/ProcessStatsTest.java
new file mode 100644
index 0000000..6189914
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/app/procstats/ProcessStatsTest.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.app.procstats;
+
+import static com.android.internal.app.procstats.ProcessStats.STATE_TOP;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import android.app.ActivityManager;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.util.FrameworkStatsLog;
+
+import junit.framework.TestCase;
+
+import org.junit.Before;
+import org.mockito.Mock;
+
+import java.util.concurrent.TimeUnit;
+
+/** Provides test cases for ProcessStats. */
+public class ProcessStatsTest extends TestCase {
+
+    private static final String APP_1_PACKAGE_NAME = "com.android.testapp";
+    private static final int APP_1_UID = 5001;
+    private static final long APP_1_VERSION = 10;
+    private static final String APP_1_PROCESS_NAME = "com.android.testapp.p";
+    private static final String APP_1_SERVICE_NAME = "com.android.testapp.service";
+
+    private static final String APP_2_PACKAGE_NAME = "com.android.testapp2";
+    private static final int APP_2_UID = 5002;
+    private static final long APP_2_VERSION = 30;
+    private static final String APP_2_PROCESS_NAME = "com.android.testapp2.p";
+
+    private static final long NOW_MS = 123000;
+    private static final int DURATION_SECS = 6;
+
+    @Mock StatsEventOutput mStatsEventOutput;
+
+    @Before
+    public void setUp() {
+        initMocks(this);
+    }
+
+    @SmallTest
+    public void testDumpProcessState() throws Exception {
+        ProcessStats processStats = new ProcessStats();
+        processStats.getProcessStateLocked(
+                APP_1_PACKAGE_NAME, APP_1_UID, APP_1_VERSION, APP_1_PROCESS_NAME);
+        processStats.getProcessStateLocked(
+                APP_2_PACKAGE_NAME, APP_2_UID, APP_2_VERSION, APP_2_PROCESS_NAME);
+        processStats.dumpProcessState(FrameworkStatsLog.PROCESS_STATE, mStatsEventOutput);
+        verify(mStatsEventOutput)
+                .write(
+                        eq(FrameworkStatsLog.PROCESS_STATE),
+                        eq(APP_1_UID),
+                        eq(APP_1_PROCESS_NAME),
+                        anyInt(),
+                        anyInt(),
+                        eq(0),
+                        eq(0),
+                        eq(0),
+                        eq(0),
+                        eq(0),
+                        eq(0),
+                        eq(0),
+                        eq(0),
+                        eq(0));
+        verify(mStatsEventOutput)
+                .write(
+                        eq(FrameworkStatsLog.PROCESS_STATE),
+                        eq(APP_2_UID),
+                        eq(APP_2_PROCESS_NAME),
+                        anyInt(),
+                        anyInt(),
+                        eq(0),
+                        eq(0),
+                        eq(0),
+                        eq(0),
+                        eq(0),
+                        eq(0),
+                        eq(0),
+                        eq(0),
+                        eq(0));
+    }
+
+    @SmallTest
+    public void testNonZeroProcessStateDuration() throws Exception {
+        ProcessStats processStats = new ProcessStats();
+        ProcessState processState =
+                processStats.getProcessStateLocked(
+                        APP_1_PACKAGE_NAME, APP_1_UID, APP_1_VERSION, APP_1_PROCESS_NAME);
+        processState.setCombinedState(STATE_TOP, NOW_MS);
+        processState.commitStateTime(NOW_MS + TimeUnit.SECONDS.toMillis(DURATION_SECS));
+        processStats.dumpProcessState(FrameworkStatsLog.PROCESS_STATE, mStatsEventOutput);
+        verify(mStatsEventOutput)
+                .write(
+                        eq(FrameworkStatsLog.PROCESS_STATE),
+                        eq(APP_1_UID),
+                        eq(APP_1_PROCESS_NAME),
+                        anyInt(),
+                        anyInt(),
+                        eq(0),
+                        eq(DURATION_SECS),
+                        eq(0),
+                        eq(0),
+                        eq(0),
+                        eq(0),
+                        eq(0),
+                        eq(0),
+                        eq(0));
+    }
+
+    @SmallTest
+    public void testDumpBoundFgsDuration() throws Exception {
+        ProcessStats processStats = new ProcessStats();
+        ProcessState processState =
+                processStats.getProcessStateLocked(
+                        APP_1_PACKAGE_NAME, APP_1_UID, APP_1_VERSION, APP_1_PROCESS_NAME);
+        processState.setState(ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE,
+                ProcessStats.ADJ_MEM_FACTOR_NORMAL, NOW_MS, /* pkgList */ null);
+        processState.commitStateTime(NOW_MS + TimeUnit.SECONDS.toMillis(DURATION_SECS));
+        processStats.dumpProcessState(FrameworkStatsLog.PROCESS_STATE, mStatsEventOutput);
+        verify(mStatsEventOutput)
+                .write(
+                        eq(FrameworkStatsLog.PROCESS_STATE),
+                        eq(APP_1_UID),
+                        eq(APP_1_PROCESS_NAME),
+                        anyInt(),
+                        anyInt(),
+                        eq(0),
+                        eq(0),
+                        eq(0),
+                        eq(0),
+                        eq(DURATION_SECS),
+                        eq(0),
+                        eq(0),
+                        eq(0),
+                        eq(0));
+    }
+
+    @SmallTest
+    public void testDumpProcessAssociation() throws Exception {
+        ProcessStats processStats = new ProcessStats();
+        AssociationState associationState =
+                processStats.getAssociationStateLocked(
+                        APP_1_PACKAGE_NAME,
+                        APP_1_UID,
+                        APP_1_VERSION,
+                        APP_1_PROCESS_NAME,
+                        APP_1_SERVICE_NAME);
+        AssociationState.SourceState sourceState =
+                associationState.startSource(APP_2_UID, APP_2_PROCESS_NAME, APP_2_PACKAGE_NAME);
+        sourceState.stop();
+        processStats.dumpProcessAssociation(
+                FrameworkStatsLog.PROCESS_ASSOCIATION, mStatsEventOutput);
+        verify(mStatsEventOutput)
+                .write(
+                        eq(FrameworkStatsLog.PROCESS_ASSOCIATION),
+                        eq(APP_2_UID),
+                        eq(APP_2_PROCESS_NAME),
+                        eq(APP_1_UID),
+                        eq(APP_1_SERVICE_NAME),
+                        anyInt(),
+                        anyInt(),
+                        eq(0),
+                        eq(0),
+                        eq(0),
+                        eq(APP_1_PROCESS_NAME));
+    }
+
+    @SmallTest
+    public void testSafelyResetClearsProcessInUidState() throws Exception {
+        ProcessStats processStats = new ProcessStats();
+        ProcessState processState =
+                processStats.getProcessStateLocked(
+                        APP_1_PACKAGE_NAME, APP_1_UID, APP_1_VERSION, APP_1_PROCESS_NAME);
+        processState.makeActive();
+        UidState uidState = processStats.mUidStates.get(APP_1_UID);
+        assertTrue(uidState.isInUse());
+        processState.makeInactive();
+        uidState.resetSafely(NOW_MS);
+        processState.makeActive();
+        assertFalse(uidState.isInUse());
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java
index 00ac198..0bdf491 100644
--- a/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java
@@ -245,6 +245,8 @@
         stats.noteNetworkInterfaceForTransports("cellular",
                 new int[]{NetworkCapabilities.TRANSPORT_CELLULAR});
 
+        stats.notePhoneOnLocked(9800, 9800);
+
         // Note application network activity
         NetworkStats networkStats = new NetworkStats(10000, 1)
                 .addEntry(new NetworkStats.Entry("cellular", APP_UID, 0, 0,
@@ -257,27 +259,33 @@
 
         mStatsRule.setTime(12_000, 12_000);
 
-        MobileRadioPowerCalculator calculator =
+        MobileRadioPowerCalculator mobileRadioPowerCalculator =
                 new MobileRadioPowerCalculator(mStatsRule.getPowerProfile());
-
-        mStatsRule.apply(calculator);
+        PhonePowerCalculator phonePowerCalculator =
+                new PhonePowerCalculator(mStatsRule.getPowerProfile());
+        mStatsRule.apply(mobileRadioPowerCalculator, phonePowerCalculator);
 
         UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
         assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
-                .isWithin(PRECISION).of(1.53934);
+                .isWithin(PRECISION).of(1.38541);
         assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
 
         BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer();
         // 10_000_000 micro-Coulomb * 1/1000 milli/micro * 1/3600 hour/second = 2.77778 mAh
         assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
-                .isWithin(PRECISION).of(2.77778);
+                .isWithin(PRECISION).of(2.5);
         assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
 
+        assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_PHONE))
+                .isWithin(PRECISION).of(0.27778);
+        assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_PHONE))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
+
         BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer();
         assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
-                .isWithin(PRECISION).of(1.53934);
+                .isWithin(PRECISION).of(1.38541);
         assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
     }
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index caa118a..e1c9b3c 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -517,6 +517,12 @@
         <permission name="android.permission.BIND_WALLPAPER"/>
     </privapp-permissions>
 
+    <privapp-permissions package="com.android.wallpaper">
+        <permission name="android.permission.SET_WALLPAPER_COMPONENT"/>
+        <permission name="android.permission.BIND_WALLPAPER"/>
+        <permission name="android.permission.CUSTOMIZE_SYSTEM_UI"/>
+    </privapp-permissions>
+
     <privapp-permissions package="com.android.dynsystem">
         <permission name="android.permission.REBOOT"/>
         <permission name="android.permission.MANAGE_DYNAMIC_SYSTEM"/>
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 1cf819a..3d7fb16b 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -1051,6 +1051,12 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/WindowContainer.java"
     },
+    "-1104347731": {
+      "message": "Setting requested orientation %s for %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "-1103716954": {
       "message": "Not removing %s due to exit animation",
       "level": "VERBOSE",
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java
index ff5f256..9118ee2 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java
@@ -187,6 +187,10 @@
 
     @GuardedBy("mLock")
     private int getCurrentStatus() {
+        if (mRearDisplayState == INVALID_DEVICE_STATE) {
+            return WindowAreaComponent.STATUS_UNSUPPORTED;
+        }
+
         if (mRearDisplaySessionStatus == WindowAreaComponent.SESSION_STATE_ACTIVE
                 || isRearDisplayActive()) {
             return WindowAreaComponent.STATUS_UNAVAILABLE;
diff --git a/libs/WindowManager/Shell/OWNERS b/libs/WindowManager/Shell/OWNERS
index 4b12590..852edef 100644
--- a/libs/WindowManager/Shell/OWNERS
+++ b/libs/WindowManager/Shell/OWNERS
@@ -1,4 +1,4 @@
 xutan@google.com
 
 # Give submodule owners in shell resource approval
-per-file res*/*/*.xml = hwwang@google.com, lbill@google.com, madym@google.com
+per-file res*/*/*.xml = hwwang@google.com, jorgegil@google.com, lbill@google.com, madym@google.com
diff --git a/libs/WindowManager/Shell/res/color/split_divider_background.xml b/libs/WindowManager/Shell/res/color-night/taskbar_background.xml
similarity index 81%
rename from libs/WindowManager/Shell/res/color/split_divider_background.xml
rename to libs/WindowManager/Shell/res/color-night/taskbar_background.xml
index 0499808..01df006 100644
--- a/libs/WindowManager/Shell/res/color/split_divider_background.xml
+++ b/libs/WindowManager/Shell/res/color-night/taskbar_background.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2021 The Android Open Source Project
+  ~ Copyright (C) 2023 The Android Open Source Project
   ~
   ~ Licensed under the Apache License, Version 2.0 (the "License");
   ~ you may not use this file except in compliance with the License.
@@ -14,6 +14,7 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
+<!-- Should be the same as in packages/apps/Launcher3/res/color-night-v31/taskbar_background.xml -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="@android:color/system_neutral1_500" android:lStar="15" />
+    <item android:color="@android:color/system_neutral1_500" android:lStar="20" />
 </selector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/color/taskbar_background.xml b/libs/WindowManager/Shell/res/color/taskbar_background.xml
index b3d26029..876ee02 100644
--- a/libs/WindowManager/Shell/res/color/taskbar_background.xml
+++ b/libs/WindowManager/Shell/res/color/taskbar_background.xml
@@ -16,5 +16,5 @@
   -->
 <!-- Should be the same as in packages/apps/Launcher3/res/color-v31/taskbar_background.xml -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="@android:color/system_neutral1_500" android:lStar="15" />
+    <item android:color="@android:color/system_neutral1_500" android:lStar="98" />
 </selector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/color/unfold_background.xml b/libs/WindowManager/Shell/res/color/unfold_background.xml
new file mode 100644
index 0000000..e33eb12
--- /dev/null
+++ b/libs/WindowManager/Shell/res/color/unfold_background.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_neutral1_500" android:lStar="5" />
+</selector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/reachability_education_ic_left_hand.xml b/libs/WindowManager/Shell/res/drawable/reachability_education_ic_left_hand.xml
new file mode 100644
index 0000000..c400dc6
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/reachability_education_ic_left_hand.xml
@@ -0,0 +1,699 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<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="30dp" android:width="30dp" android:viewportHeight="30"
+                android:viewportWidth="30">
+            <group android:name="_R_G" android:scaleX="-1" android:translateX="30">
+                <group android:name="_R_G_L_0_G" android:translateX="-135" android:translateY="-135"
+                       android:pivotX="150" android:pivotY="150" android:scaleX="0.1"
+                       android:scaleY="0.1">
+                    <group android:name="_R_G_L_0_G_L_1_G" android:translateX="134.624"
+                           android:translateY="87.514" android:pivotX="11.625" android:pivotY="6.39"
+                           android:scaleX="10" android:scaleY="10">
+                        <group android:name="_R_G_L_0_G_L_1_G_D_0_P_0_G_0_T_0"
+                               android:translateX="11.625" android:translateY="6.464"
+                               android:scaleX="1" android:scaleY="1">
+                            <path android:name="_R_G_L_0_G_L_1_G_D_0_P_0"
+                                  android:fillColor="@color/letterbox_reachability_education_item_color"
+                                  android:fillAlpha="1"
+                                  android:fillType="nonZero"
+                                  android:pathData=" M-1.54 5.39 C-3.87,4.71 -5.49,2.54 -5.49,0.11 C-5.49,-2.92 -3.03,-5.38 0,-5.38 C3.03,-5.38 5.49,-2.92 5.49,0.11 C5.49,2.11 4.41,3.95 2.66,4.92 C2.66,4.92 1.69,3.17 1.69,3.17 C2.8,2.55 3.49,1.38 3.49,0.11 C3.49,-1.82 1.93,-3.38 0,-3.38 C-1.93,-3.38 -3.49,-1.82 -3.49,0.11 C-3.49,1.65 -2.46,3.03 -0.98,3.47 C-0.98,3.47 -1.54,5.39 -1.54,5.39c "/>
+                        </group>
+                    </group>
+                    <group android:name="_R_G_L_0_G_L_0_G" android:translateX="138"
+                           android:translateY="138" android:pivotX="12" android:pivotY="12"
+                           android:scaleX="10" android:scaleY="10">
+                        <path android:name="_R_G_L_0_G_L_0_G_D_0_P_0"
+                              android:fillColor="@color/letterbox_reachability_education_item_color"
+                              android:fillAlpha="1" android:fillType="nonZero"
+                              android:pathData=" M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c "/>
+                    </group>
+                </group>
+            </group>
+            <group android:name="time_group"/>
+        </vector>
+    </aapt:attr>
+    <target android:name="_R_G_L_0_G_L_1_G_D_0_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator android:propertyName="fillAlpha" android:duration="500"
+                                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="fillAlpha" android:duration="250"
+                                android:startOffset="500" android:valueFrom="1"
+                                android:valueTo="0.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="fillAlpha" android:duration="83"
+                                android:startOffset="750" android:valueFrom="0.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="fillAlpha" android:duration="250"
+                                android:startOffset="833" android:valueFrom="1"
+                                android:valueTo="0.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="fillAlpha" android:duration="83"
+                                android:startOffset="1083" android:valueFrom="0.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="fillAlpha" android:duration="833"
+                                android:startOffset="1167" 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="fillAlpha" android:duration="250"
+                                android:startOffset="2000" android:valueFrom="1"
+                                android:valueTo="0.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="fillAlpha" android:duration="83"
+                                android:startOffset="2250" android:valueFrom="0.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="fillAlpha" android:duration="250"
+                                android:startOffset="2333" android:valueFrom="1"
+                                android:valueTo="0.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="fillAlpha" android:duration="83"
+                                android:startOffset="2583" android:valueFrom="0.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="fillAlpha" android:duration="833"
+                                android:startOffset="2667" 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="fillAlpha" android:duration="250"
+                                android:startOffset="3500" android:valueFrom="1"
+                                android:valueTo="0.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="fillAlpha" android:duration="83"
+                                android:startOffset="3750" android:valueFrom="0.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="fillAlpha" android:duration="250"
+                                android:startOffset="3833" android:valueFrom="1"
+                                android:valueTo="0.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="fillAlpha" android:duration="83"
+                                android:startOffset="4083" android:valueFrom="0.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="fillAlpha" android:duration="833"
+                                android:startOffset="4167" 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="fillAlpha" android:duration="250"
+                                android:startOffset="5000" android:valueFrom="1"
+                                android:valueTo="0.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="fillAlpha" android:duration="83"
+                                android:startOffset="5250" android:valueFrom="0.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="fillAlpha" android:duration="250"
+                                android:startOffset="5333" android:valueFrom="1"
+                                android:valueTo="0.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="fillAlpha" android:duration="83"
+                                android:startOffset="5583" android:valueFrom="0.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>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_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="500"
+                                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.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="500"
+                                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.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="250"
+                                android:startOffset="500" android:valueFrom="1"
+                                android:valueTo="1.4000000000000001" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="250"
+                                android:startOffset="500" android:valueFrom="1"
+                                android:valueTo="1.4000000000000001" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="83"
+                                android:startOffset="750" android:valueFrom="1.4000000000000001"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="83"
+                                android:startOffset="750" android:valueFrom="1.4000000000000001"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="250"
+                                android:startOffset="833" android:valueFrom="1"
+                                android:valueTo="1.4000000000000001" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="250"
+                                android:startOffset="833" android:valueFrom="1"
+                                android:valueTo="1.4000000000000001" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="83"
+                                android:startOffset="1083" android:valueFrom="1.4000000000000001"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="83"
+                                android:startOffset="1083" android:valueFrom="1.4000000000000001"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="833"
+                                android:startOffset="1167" 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 0.833,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="833"
+                                android:startOffset="1167" 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 0.833,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="250"
+                                android:startOffset="2000" android:valueFrom="1"
+                                android:valueTo="1.4000000000000001" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="250"
+                                android:startOffset="2000" android:valueFrom="1"
+                                android:valueTo="1.4000000000000001" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="83"
+                                android:startOffset="2250" android:valueFrom="1.4000000000000001"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="83"
+                                android:startOffset="2250" android:valueFrom="1.4000000000000001"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="250"
+                                android:startOffset="2333" android:valueFrom="1"
+                                android:valueTo="1.4000000000000001" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="250"
+                                android:startOffset="2333" android:valueFrom="1"
+                                android:valueTo="1.4000000000000001" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="83"
+                                android:startOffset="2583" android:valueFrom="1.4000000000000001"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="83"
+                                android:startOffset="2583" android:valueFrom="1.4000000000000001"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="833"
+                                android:startOffset="2667" 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 0.833,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="833"
+                                android:startOffset="2667" 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 0.833,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="250"
+                                android:startOffset="3500" android:valueFrom="1"
+                                android:valueTo="1.4000000000000001" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="250"
+                                android:startOffset="3500" android:valueFrom="1"
+                                android:valueTo="1.4000000000000001" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="83"
+                                android:startOffset="3750" android:valueFrom="1.4000000000000001"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="83"
+                                android:startOffset="3750" android:valueFrom="1.4000000000000001"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="250"
+                                android:startOffset="3833" android:valueFrom="1"
+                                android:valueTo="1.4000000000000001" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="250"
+                                android:startOffset="3833" android:valueFrom="1"
+                                android:valueTo="1.4000000000000001" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="83"
+                                android:startOffset="4083" android:valueFrom="1.4000000000000001"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="83"
+                                android:startOffset="4083" android:valueFrom="1.4000000000000001"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="833"
+                                android:startOffset="4167" 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 0.833,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="833"
+                                android:startOffset="4167" 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 0.833,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="250"
+                                android:startOffset="5000" android:valueFrom="1"
+                                android:valueTo="1.4000000000000001" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="250"
+                                android:startOffset="5000" android:valueFrom="1"
+                                android:valueTo="1.4000000000000001" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="83"
+                                android:startOffset="5250" android:valueFrom="1.4000000000000001"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="83"
+                                android:startOffset="5250" android:valueFrom="1.4000000000000001"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="250"
+                                android:startOffset="5333" android:valueFrom="1"
+                                android:valueTo="1.4000000000000001" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="250"
+                                android:startOffset="5333" android:valueFrom="1"
+                                android:valueTo="1.4000000000000001" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="83"
+                                android:startOffset="5583" android:valueFrom="1.4000000000000001"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="83"
+                                android:startOffset="5583" android:valueFrom="1.4000000000000001"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_L_0_G_D_0_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator android:propertyName="pathData" android:duration="500"
+                                android:startOffset="0"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                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="250"
+                                android:startOffset="500"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                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="83"
+                                android:startOffset="750"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="pathData" android:duration="250"
+                                android:startOffset="833"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                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="83"
+                                android:startOffset="1083"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="pathData" android:duration="833"
+                                android:startOffset="1167"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="pathData" android:duration="250"
+                                android:startOffset="2000"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                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="83"
+                                android:startOffset="2250"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="pathData" android:duration="250"
+                                android:startOffset="2333"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                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="83"
+                                android:startOffset="2583"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="pathData" android:duration="833"
+                                android:startOffset="2667"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="pathData" android:duration="250"
+                                android:startOffset="3500"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                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="83"
+                                android:startOffset="3750"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="pathData" android:duration="250"
+                                android:startOffset="3833"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                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="83"
+                                android:startOffset="4083"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="pathData" android:duration="833"
+                                android:startOffset="4167"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="pathData" android:duration="250"
+                                android:startOffset="5000"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                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="83"
+                                android:startOffset="5250"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="pathData" android:duration="250"
+                                android:startOffset="5333"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                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="83"
+                                android:startOffset="5583"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,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="6000"
+                                android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+                                android:valueType="floatType"/>
+            </set>
+        </aapt:attr>
+    </target>
+</animated-vector>
diff --git a/libs/WindowManager/Shell/res/drawable/reachability_education_ic_right_hand.xml b/libs/WindowManager/Shell/res/drawable/reachability_education_ic_right_hand.xml
new file mode 100644
index 0000000..a807a77
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/reachability_education_ic_right_hand.xml
@@ -0,0 +1,699 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<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="30dp" android:width="30dp" android:viewportHeight="30"
+                android:viewportWidth="30">
+            <group android:name="_R_G">
+                <group android:name="_R_G_L_0_G" android:translateX="-135" android:translateY="-135"
+                       android:pivotX="150" android:pivotY="150" android:scaleX="0.1"
+                       android:scaleY="0.1">
+                    <group android:name="_R_G_L_0_G_L_1_G" android:translateX="134.624"
+                           android:translateY="87.514" android:pivotX="11.625" android:pivotY="6.39"
+                           android:scaleX="10" android:scaleY="10">
+                        <group android:name="_R_G_L_0_G_L_1_G_D_0_P_0_G_0_T_0"
+                               android:translateX="11.625" android:translateY="6.464"
+                               android:scaleX="1" android:scaleY="1">
+                            <path android:name="_R_G_L_0_G_L_1_G_D_0_P_0"
+                                  android:fillColor="@color/letterbox_reachability_education_item_color"
+                                  android:fillAlpha="1"
+                                  android:fillType="nonZero"
+                                  android:pathData=" M-1.54 5.39 C-3.87,4.71 -5.49,2.54 -5.49,0.11 C-5.49,-2.92 -3.03,-5.38 0,-5.38 C3.03,-5.38 5.49,-2.92 5.49,0.11 C5.49,2.11 4.41,3.95 2.66,4.92 C2.66,4.92 1.69,3.17 1.69,3.17 C2.8,2.55 3.49,1.38 3.49,0.11 C3.49,-1.82 1.93,-3.38 0,-3.38 C-1.93,-3.38 -3.49,-1.82 -3.49,0.11 C-3.49,1.65 -2.46,3.03 -0.98,3.47 C-0.98,3.47 -1.54,5.39 -1.54,5.39c "/>
+                        </group>
+                    </group>
+                    <group android:name="_R_G_L_0_G_L_0_G" android:translateX="138"
+                           android:translateY="138" android:pivotX="12" android:pivotY="12"
+                           android:scaleX="10" android:scaleY="10">
+                        <path android:name="_R_G_L_0_G_L_0_G_D_0_P_0"
+                              android:fillColor="@color/letterbox_reachability_education_item_color"
+                              android:fillAlpha="1" android:fillType="nonZero"
+                              android:pathData=" M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c "/>
+                    </group>
+                </group>
+            </group>
+            <group android:name="time_group"/>
+        </vector>
+    </aapt:attr>
+    <target android:name="_R_G_L_0_G_L_1_G_D_0_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator android:propertyName="fillAlpha" android:duration="500"
+                                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="fillAlpha" android:duration="250"
+                                android:startOffset="500" android:valueFrom="1"
+                                android:valueTo="0.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="fillAlpha" android:duration="83"
+                                android:startOffset="750" android:valueFrom="0.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="fillAlpha" android:duration="250"
+                                android:startOffset="833" android:valueFrom="1"
+                                android:valueTo="0.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="fillAlpha" android:duration="83"
+                                android:startOffset="1083" android:valueFrom="0.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="fillAlpha" android:duration="833"
+                                android:startOffset="1167" 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="fillAlpha" android:duration="250"
+                                android:startOffset="2000" android:valueFrom="1"
+                                android:valueTo="0.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="fillAlpha" android:duration="83"
+                                android:startOffset="2250" android:valueFrom="0.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="fillAlpha" android:duration="250"
+                                android:startOffset="2333" android:valueFrom="1"
+                                android:valueTo="0.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="fillAlpha" android:duration="83"
+                                android:startOffset="2583" android:valueFrom="0.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="fillAlpha" android:duration="833"
+                                android:startOffset="2667" 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="fillAlpha" android:duration="250"
+                                android:startOffset="3500" android:valueFrom="1"
+                                android:valueTo="0.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="fillAlpha" android:duration="83"
+                                android:startOffset="3750" android:valueFrom="0.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="fillAlpha" android:duration="250"
+                                android:startOffset="3833" android:valueFrom="1"
+                                android:valueTo="0.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="fillAlpha" android:duration="83"
+                                android:startOffset="4083" android:valueFrom="0.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="fillAlpha" android:duration="833"
+                                android:startOffset="4167" 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="fillAlpha" android:duration="250"
+                                android:startOffset="5000" android:valueFrom="1"
+                                android:valueTo="0.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="fillAlpha" android:duration="83"
+                                android:startOffset="5250" android:valueFrom="0.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="fillAlpha" android:duration="250"
+                                android:startOffset="5333" android:valueFrom="1"
+                                android:valueTo="0.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="fillAlpha" android:duration="83"
+                                android:startOffset="5583" android:valueFrom="0.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>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_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="500"
+                                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.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="500"
+                                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.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="250"
+                                android:startOffset="500" android:valueFrom="1"
+                                android:valueTo="1.4000000000000001" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="250"
+                                android:startOffset="500" android:valueFrom="1"
+                                android:valueTo="1.4000000000000001" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="83"
+                                android:startOffset="750" android:valueFrom="1.4000000000000001"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="83"
+                                android:startOffset="750" android:valueFrom="1.4000000000000001"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="250"
+                                android:startOffset="833" android:valueFrom="1"
+                                android:valueTo="1.4000000000000001" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="250"
+                                android:startOffset="833" android:valueFrom="1"
+                                android:valueTo="1.4000000000000001" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="83"
+                                android:startOffset="1083" android:valueFrom="1.4000000000000001"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="83"
+                                android:startOffset="1083" android:valueFrom="1.4000000000000001"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="833"
+                                android:startOffset="1167" 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 0.833,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="833"
+                                android:startOffset="1167" 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 0.833,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="250"
+                                android:startOffset="2000" android:valueFrom="1"
+                                android:valueTo="1.4000000000000001" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="250"
+                                android:startOffset="2000" android:valueFrom="1"
+                                android:valueTo="1.4000000000000001" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="83"
+                                android:startOffset="2250" android:valueFrom="1.4000000000000001"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="83"
+                                android:startOffset="2250" android:valueFrom="1.4000000000000001"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="250"
+                                android:startOffset="2333" android:valueFrom="1"
+                                android:valueTo="1.4000000000000001" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="250"
+                                android:startOffset="2333" android:valueFrom="1"
+                                android:valueTo="1.4000000000000001" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="83"
+                                android:startOffset="2583" android:valueFrom="1.4000000000000001"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="83"
+                                android:startOffset="2583" android:valueFrom="1.4000000000000001"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="833"
+                                android:startOffset="2667" 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 0.833,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="833"
+                                android:startOffset="2667" 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 0.833,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="250"
+                                android:startOffset="3500" android:valueFrom="1"
+                                android:valueTo="1.4000000000000001" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="250"
+                                android:startOffset="3500" android:valueFrom="1"
+                                android:valueTo="1.4000000000000001" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="83"
+                                android:startOffset="3750" android:valueFrom="1.4000000000000001"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="83"
+                                android:startOffset="3750" android:valueFrom="1.4000000000000001"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="250"
+                                android:startOffset="3833" android:valueFrom="1"
+                                android:valueTo="1.4000000000000001" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="250"
+                                android:startOffset="3833" android:valueFrom="1"
+                                android:valueTo="1.4000000000000001" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="83"
+                                android:startOffset="4083" android:valueFrom="1.4000000000000001"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="83"
+                                android:startOffset="4083" android:valueFrom="1.4000000000000001"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="833"
+                                android:startOffset="4167" 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 0.833,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="833"
+                                android:startOffset="4167" 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 0.833,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="250"
+                                android:startOffset="5000" android:valueFrom="1"
+                                android:valueTo="1.4000000000000001" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="250"
+                                android:startOffset="5000" android:valueFrom="1"
+                                android:valueTo="1.4000000000000001" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="83"
+                                android:startOffset="5250" android:valueFrom="1.4000000000000001"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="83"
+                                android:startOffset="5250" android:valueFrom="1.4000000000000001"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="250"
+                                android:startOffset="5333" android:valueFrom="1"
+                                android:valueTo="1.4000000000000001" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="250"
+                                android:startOffset="5333" android:valueFrom="1"
+                                android:valueTo="1.4000000000000001" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleX" android:duration="83"
+                                android:startOffset="5583" android:valueFrom="1.4000000000000001"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="scaleY" android:duration="83"
+                                android:startOffset="5583" android:valueFrom="1.4000000000000001"
+                                android:valueTo="1" android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_L_0_G_D_0_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator android:propertyName="pathData" android:duration="500"
+                                android:startOffset="0"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                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="250"
+                                android:startOffset="500"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                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="83"
+                                android:startOffset="750"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="pathData" android:duration="250"
+                                android:startOffset="833"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                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="83"
+                                android:startOffset="1083"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="pathData" android:duration="833"
+                                android:startOffset="1167"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="pathData" android:duration="250"
+                                android:startOffset="2000"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                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="83"
+                                android:startOffset="2250"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="pathData" android:duration="250"
+                                android:startOffset="2333"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                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="83"
+                                android:startOffset="2583"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="pathData" android:duration="833"
+                                android:startOffset="2667"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="pathData" android:duration="250"
+                                android:startOffset="3500"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                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="83"
+                                android:startOffset="3750"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="pathData" android:duration="250"
+                                android:startOffset="3833"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                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="83"
+                                android:startOffset="4083"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="pathData" android:duration="833"
+                                android:startOffset="4167"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="pathData" android:duration="250"
+                                android:startOffset="5000"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                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="83"
+                                android:startOffset="5250"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/>
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator android:propertyName="pathData" android:duration="250"
+                                android:startOffset="5333"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                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="83"
+                                android:startOffset="5583"
+                                android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c "
+                                android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.001,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="6000"
+                                android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+                                android:valueType="floatType"/>
+            </set>
+        </aapt:attr>
+    </target>
+</animated-vector>
diff --git a/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml b/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml
index 413cfd7..a993469 100644
--- a/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml
+++ b/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml
@@ -1,5 +1,5 @@
 <!--
-  ~ Copyright (C) 2022 The Android Open Source Project
+  ~ Copyright (C) 2023 The Android Open Source Project
   ~
   ~ Licensed under the Apache License, Version 2.0 (the "License");
   ~ you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<com.android.wm.shell.compatui.letterboxedu.LetterboxEduDialogLayout
+<com.android.wm.shell.compatui.LetterboxEduDialogLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     style="@style/LetterboxDialog">
@@ -78,13 +78,13 @@
                     android:orientation="horizontal"
                     android:paddingTop="48dp">
 
-                    <com.android.wm.shell.compatui.letterboxedu.LetterboxEduDialogActionLayout
+                    <com.android.wm.shell.compatui.LetterboxEduDialogActionLayout
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
                         app:icon="@drawable/letterbox_education_ic_reposition"
                         app:text="@string/letterbox_education_reposition_text"/>
 
-                    <com.android.wm.shell.compatui.letterboxedu.LetterboxEduDialogActionLayout
+                    <com.android.wm.shell.compatui.LetterboxEduDialogActionLayout
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
                         android:layout_marginStart=
@@ -118,4 +118,4 @@
 
     </FrameLayout>
 
-</com.android.wm.shell.compatui.letterboxedu.LetterboxEduDialogLayout>
+</com.android.wm.shell.compatui.LetterboxEduDialogLayout>
diff --git a/libs/WindowManager/Shell/res/layout/reachability_ui_layout.xml b/libs/WindowManager/Shell/res/layout/reachability_ui_layout.xml
new file mode 100644
index 0000000..1e36fb6
--- /dev/null
+++ b/libs/WindowManager/Shell/res/layout/reachability_ui_layout.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<com.android.wm.shell.compatui.ReachabilityEduLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:focusable="false"
+    android:focusableInTouchMode="false"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <com.android.wm.shell.compatui.ReachabilityEduHandLayout
+        style="@style/ReachabilityEduHandLayout"
+        android:text="@string/letterbox_reachability_reposition_text"
+        app:drawableTopCompat="@drawable/reachability_education_ic_right_hand"
+        android:layout_gravity="center_horizontal|top"
+        android:layout_marginTop="@dimen/letterbox_reachability_education_dialog_margin"
+        android:id="@+id/reachability_move_up_button"
+        android:maxWidth="@dimen/letterbox_reachability_education_item_width"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"/>
+
+    <com.android.wm.shell.compatui.ReachabilityEduHandLayout
+        style="@style/ReachabilityEduHandLayout"
+        android:text="@string/letterbox_reachability_reposition_text"
+        app:drawableTopCompat="@drawable/reachability_education_ic_right_hand"
+        android:layout_gravity="center_vertical|right"
+        android:layout_marginTop="@dimen/letterbox_reachability_education_dialog_margin"
+        android:id="@+id/reachability_move_right_button"
+        android:maxWidth="@dimen/letterbox_reachability_education_item_width"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"/>
+
+
+    <com.android.wm.shell.compatui.ReachabilityEduHandLayout
+        style="@style/ReachabilityEduHandLayout"
+        android:text="@string/letterbox_reachability_reposition_text"
+        app:drawableTopCompat="@drawable/reachability_education_ic_left_hand"
+        android:layout_gravity="center_vertical|left"
+        android:layout_marginTop="@dimen/letterbox_reachability_education_dialog_margin"
+        android:id="@+id/reachability_move_left_button"
+        android:maxWidth="@dimen/letterbox_reachability_education_item_width"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"/>
+
+    <com.android.wm.shell.compatui.ReachabilityEduHandLayout
+        style="@style/ReachabilityEduHandLayout"
+        android:text="@string/letterbox_reachability_reposition_text"
+        app:drawableTopCompat="@drawable/reachability_education_ic_right_hand"
+        android:layout_gravity="center_horizontal|bottom"
+        android:layout_marginTop="@dimen/letterbox_reachability_education_dialog_margin"
+        android:id="@+id/reachability_move_down_button"
+        android:maxWidth="@dimen/letterbox_reachability_education_item_width"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"/>
+
+</com.android.wm.shell.compatui.ReachabilityEduLayout>
diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml
index a19706a..c8f9b99 100644
--- a/libs/WindowManager/Shell/res/values-ca/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ca/strings.xml
@@ -56,7 +56,7 @@
     <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Inicia el mode d\'una mà"</string>
     <string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"Surt del mode d\'una mà"</string>
     <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Configuració de les bombolles: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-    <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Menú addicional"</string>
+    <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Menú de desbordament"</string>
     <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Torna a afegir a la pila"</string>
     <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de: <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
     <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> (<xliff:g id="APP_NAME">%2$s</xliff:g>) i <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> més"</string>
diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml
index 1cc5faa..7bd39ba 100644
--- a/libs/WindowManager/Shell/res/values-fa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fa/strings.xml
@@ -56,7 +56,7 @@
     <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"آغاز «حالت یک‌دستی»"</string>
     <string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"خروج از «حالت یک‌دستی»"</string>
     <string name="bubbles_settings_button_description" msgid="1301286017420516912">"تنظیمات برای حبابک‌های <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-    <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"لبریزشده"</string>
+    <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"سرریز"</string>
     <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"افزودن برگشت به پشته"</string>
     <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> از <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
     <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> از <xliff:g id="APP_NAME">%2$s</xliff:g> و <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> مورد بیشتر"</string>
diff --git a/libs/WindowManager/Shell/res/values-mr/strings_tv.xml b/libs/WindowManager/Shell/res/values-mr/strings_tv.xml
index a9779b3..660212a 100644
--- a/libs/WindowManager/Shell/res/values-mr/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-mr/strings_tv.xml
@@ -24,7 +24,7 @@
     <string name="pip_move" msgid="158770205886688553">"हलवा"</string>
     <string name="pip_expand" msgid="1051966011679297308">"विस्तार करा"</string>
     <string name="pip_collapse" msgid="3903295106641385962">"कोलॅप्स करा"</string>
-    <string name="pip_edu_text" msgid="3672999496647508701">" नियंत्रणांसाठी "<annotation icon="home_icon">" होम "</annotation>" दोनदा दाबा"</string>
+    <string name="pip_edu_text" msgid="3672999496647508701">" नियंत्रणांसाठी "<annotation icon="home_icon">" होम "</annotation>" दोनदा प्रेस करा"</string>
     <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"चित्रात-चित्र मेनू."</string>
     <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"डावीकडे हलवा"</string>
     <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"उजवीकडे हलवा"</string>
diff --git a/libs/WindowManager/Shell/res/values-night/colors.xml b/libs/WindowManager/Shell/res/values-night/colors.xml
index 83c4d93..5c6bb57 100644
--- a/libs/WindowManager/Shell/res/values-night/colors.xml
+++ b/libs/WindowManager/Shell/res/values-night/colors.xml
@@ -15,6 +15,7 @@
   -->
 
 <resources>
+    <color name="docked_divider_handle">#ffffff</color>
     <!-- Bubbles -->
     <color name="bubbles_icon_tint">@color/GM2_grey_200</color>
     <!-- Splash screen-->
diff --git a/libs/WindowManager/Shell/res/values/attrs.xml b/libs/WindowManager/Shell/res/values/attrs.xml
index 2aad4c1..fbb5caa 100644
--- a/libs/WindowManager/Shell/res/values/attrs.xml
+++ b/libs/WindowManager/Shell/res/values/attrs.xml
@@ -1,5 +1,5 @@
 <!--
-  ~ Copyright (C) 2022 The Android Open Source Project
+  ~ Copyright (C) 2023 The Android Open Source Project
   ~
   ~ Licensed under the Apache License, Version 2.0 (the "License");
   ~ you may not use this file except in compliance with the License.
diff --git a/libs/WindowManager/Shell/res/values/colors.xml b/libs/WindowManager/Shell/res/values/colors.xml
index 965ab15..7d5760e 100644
--- a/libs/WindowManager/Shell/res/values/colors.xml
+++ b/libs/WindowManager/Shell/res/values/colors.xml
@@ -17,7 +17,8 @@
  */
 -->
 <resources>
-    <color name="docked_divider_handle">#ffffff</color>
+    <color name="docked_divider_handle">#000000</color>
+    <color name="split_divider_background">@color/taskbar_background</color>
     <drawable name="forced_resizable_background">#59000000</drawable>
     <color name="minimize_dock_shadow_start">#60000000</color>
     <color name="minimize_dock_shadow_end">#00000000</color>
@@ -44,6 +45,9 @@
     <!-- Letterbox Dialog -->
     <color name="letterbox_dialog_background">@android:color/system_neutral1_900</color>
 
+    <!-- Reachability Education color for hand icon and text-->
+    <color name="letterbox_reachability_education_item_color">#BFC8CC</color>
+
     <!-- GM2 colors -->
     <color name="GM2_grey_200">#E8EAED</color>
     <color name="GM2_grey_700">#5F6368</color>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 680ad51..04b53f2 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -327,6 +327,15 @@
     <!-- The vertical padding for the buttons in the letterbox restart dialog -->
     <dimen name="letterbox_restart_dialog_vertical_padding">8dp</dimen>
 
+    <!-- The margin between the reachability dialog container and its parent. -->
+    <dimen name="letterbox_reachability_education_dialog_margin">16dp</dimen>
+
+    <!-- The width of each item in the reachability education -->
+    <dimen name="letterbox_reachability_education_item_width">118dp</dimen>
+
+    <!-- The size of the icon in the item of reachability education -->
+    <dimen name="letterbox_reachability_education_item_image_size">24dp</dimen>
+
     <!-- The width of the brand image on staring surface. -->
     <dimen name="starting_surface_brand_image_width">200dp</dimen>
 
diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml
index 63992329..523657b 100644
--- a/libs/WindowManager/Shell/res/values/strings.xml
+++ b/libs/WindowManager/Shell/res/values/strings.xml
@@ -214,6 +214,17 @@
     <!-- Checkbox text for asking to not show the restart confirmation dialog again. [CHAR LIMIT=NONE] -->
     <string name="letterbox_restart_dialog_checkbox_title">Don\u2019t show again</string>
 
+    <!-- When an app is letterboxed, it is initially centered on the screen but the user can
+         double tap to move the app to a different position. With a double-tap on the right,
+         the app moves the right of the screen and with a double-tap on the left the app moves
+         on the left. The same happens if the app has space to be moved to the top or bottom of
+         the screen. This time the double-tap can happen on the top or bottom of the screen.
+         To teach the user about this feature, we display an education explaining how the double-tap
+         works and how the app can be moved on the screen.
+         This is the text we show to the user below an animated icon visualizing the double-tap
+         action. [CHAR LIMIT=NONE] -->
+    <string name="letterbox_reachability_reposition_text">Double-tap to move this app</string>
+
     <!-- Freeform window caption strings -->
     <!-- Accessibility text for the maximize window button [CHAR LIMIT=NONE] -->
     <string name="maximize_button_text">Maximize</string>
diff --git a/libs/WindowManager/Shell/res/values/styles.xml b/libs/WindowManager/Shell/res/values/styles.xml
index bc2e71d..d0782ad 100644
--- a/libs/WindowManager/Shell/res/values/styles.xml
+++ b/libs/WindowManager/Shell/res/values/styles.xml
@@ -144,4 +144,20 @@
             @*android:string/config_bodyFontFamily
         </item>
     </style>
+
+    <style name="ReachabilityEduHandLayout" parent="Theme.AppCompat">
+        <item name="android:focusable">false</item>
+        <item name="android:focusableInTouchMode">false</item>
+        <item name="android:background">@android:color/transparent</item>
+        <item name="android:contentDescription">@string/restart_button_description</item>
+        <item name="android:visibility">invisible</item>
+        <item name="android:lineSpacingExtra">-1sp</item>
+        <item name="android:textSize">12sp</item>
+        <item name="android:textAlignment">center</item>
+        <item name="android:textColor">@color/letterbox_reachability_education_item_color</item>
+        <item name="android:textAppearance">
+            @*android:style/TextAppearance.DeviceDefault.Body2
+        </item>
+    </style>
+
 </resources>
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 71e15c1..541c0f0 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
@@ -61,6 +61,7 @@
 import android.os.Handler;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.service.notification.NotificationListenerService;
@@ -125,6 +126,39 @@
     private static final String SYSTEM_DIALOG_REASON_KEY = "reason";
     private static final String SYSTEM_DIALOG_REASON_GESTURE_NAV = "gestureNav";
 
+    // TODO(b/256873975) Should use proper flag when available to shell/launcher
+    /**
+     * Whether bubbles are showing in the bubble bar from launcher. This is only available
+     * on large screens and {@link BubbleController#isShowingAsBubbleBar()} should be used
+     * to check all conditions that indicate if the bubble bar is in use.
+     */
+    private static final boolean BUBBLE_BAR_ENABLED =
+            SystemProperties.getBoolean("persist.wm.debug.bubble_bar", false);
+
+
+    /**
+     * Common interface to send updates to bubble views.
+     */
+    public interface BubbleViewCallback {
+        /** Called when the provided bubble should be removed. */
+        void removeBubble(Bubble removedBubble);
+        /** Called when the provided bubble should be added. */
+        void addBubble(Bubble addedBubble);
+        /** Called when the provided bubble should be updated. */
+        void updateBubble(Bubble updatedBubble);
+        /** Called when the provided bubble should be selected. */
+        void selectionChanged(BubbleViewProvider selectedBubble);
+        /** Called when the provided bubble's suppression state has changed. */
+        void suppressionChanged(Bubble bubble, boolean isSuppressed);
+        /** Called when the expansion state of bubbles has changed. */
+        void expansionChanged(boolean isExpanded);
+        /**
+         * Called when the order of the bubble list has changed. Depending on the expanded state
+         * the pointer might need to be updated.
+         */
+        void bubbleOrderChanged(List<Bubble> bubbleOrder, boolean updatePointer);
+    }
+
     private final Context mContext;
     private final BubblesImpl mImpl = new BubblesImpl();
     private Bubbles.BubbleExpandListener mExpandListener;
@@ -147,12 +181,8 @@
     // Used to post to main UI thread
     private final ShellExecutor mMainExecutor;
     private final Handler mMainHandler;
-
     private final ShellExecutor mBackgroundExecutor;
 
-    // Whether or not we should show bubbles pinned at the bottom of the screen.
-    private boolean mIsBubbleBarEnabled;
-
     private BubbleLogger mLogger;
     private BubbleData mBubbleData;
     @Nullable private BubbleStackView mStackView;
@@ -533,10 +563,10 @@
         mDataRepository.removeBubblesForUser(removedUserId, parentUserId);
     }
 
-    // TODO(b/256873975): Should pass this into the constructor once flags are available to shell.
-    /** Sets whether the bubble bar is enabled (i.e. bubbles pinned to bottom on large screens). */
-    public void setBubbleBarEnabled(boolean enabled) {
-        mIsBubbleBarEnabled = enabled;
+    /** Whether bubbles are showing in the bubble bar. */
+    public boolean isShowingAsBubbleBar() {
+        // TODO(b/269670598): should also check that we're in gesture nav
+        return BUBBLE_BAR_ENABLED && mBubblePositioner.isLargeScreen();
     }
 
     /** Whether this userId belongs to the current user. */
@@ -605,12 +635,6 @@
             mStackView.setUnbubbleConversationCallback(mSysuiProxy::onUnbubbleConversation);
         }
 
-        if (mIsBubbleBarEnabled && mBubblePositioner.isLargeScreen()) {
-            mBubblePositioner.setUsePinnedLocation(true);
-        } else {
-            mBubblePositioner.setUsePinnedLocation(false);
-        }
-
         addToWindowManagerMaybe();
     }
 
@@ -1284,6 +1308,58 @@
         });
     }
 
+    private final BubbleViewCallback mBubbleViewCallback = new BubbleViewCallback() {
+        @Override
+        public void removeBubble(Bubble removedBubble) {
+            if (mStackView != null) {
+                mStackView.removeBubble(removedBubble);
+            }
+        }
+
+        @Override
+        public void addBubble(Bubble addedBubble) {
+            if (mStackView != null) {
+                mStackView.addBubble(addedBubble);
+            }
+        }
+
+        @Override
+        public void updateBubble(Bubble updatedBubble) {
+            if (mStackView != null) {
+                mStackView.updateBubble(updatedBubble);
+            }
+        }
+
+        @Override
+        public void bubbleOrderChanged(List<Bubble> bubbleOrder, boolean updatePointer) {
+            if (mStackView != null) {
+                mStackView.updateBubbleOrder(bubbleOrder, updatePointer);
+            }
+        }
+
+        @Override
+        public void suppressionChanged(Bubble bubble, boolean isSuppressed) {
+            if (mStackView != null) {
+                mStackView.setBubbleSuppressed(bubble, isSuppressed);
+            }
+        }
+
+        @Override
+        public void expansionChanged(boolean isExpanded) {
+            if (mStackView != null) {
+                mStackView.setExpanded(isExpanded);
+            }
+        }
+
+        @Override
+        public void selectionChanged(BubbleViewProvider selectedBubble) {
+            if (mStackView != null) {
+                mStackView.setSelectedBubble(selectedBubble);
+            }
+
+        }
+    };
+
     @SuppressWarnings("FieldCanBeLocal")
     private final BubbleData.Listener mBubbleDataListener = new BubbleData.Listener() {
 
@@ -1306,7 +1382,8 @@
             // Lazy load overflow bubbles from disk
             loadOverflowBubblesFromDisk();
 
-            mStackView.updateOverflowButtonDot();
+            // If bubbles in the overflow have a dot, make sure the overflow shows a dot
+            updateOverflowButtonDot();
 
             // Update bubbles in overflow.
             if (mOverflowListener != null) {
@@ -1321,9 +1398,7 @@
                 final Bubble bubble = removed.first;
                 @Bubbles.DismissReason final int reason = removed.second;
 
-                if (mStackView != null) {
-                    mStackView.removeBubble(bubble);
-                }
+                mBubbleViewCallback.removeBubble(bubble);
 
                 // Leave the notification in place if we're dismissing due to user switching, or
                 // because DND is suppressing the bubble. In both of those cases, we need to be able
@@ -1353,49 +1428,47 @@
             }
             mDataRepository.removeBubbles(mCurrentUserId, bubblesToBeRemovedFromRepository);
 
-            if (update.addedBubble != null && mStackView != null) {
+            if (update.addedBubble != null) {
                 mDataRepository.addBubble(mCurrentUserId, update.addedBubble);
-                mStackView.addBubble(update.addedBubble);
+                mBubbleViewCallback.addBubble(update.addedBubble);
             }
 
-            if (update.updatedBubble != null && mStackView != null) {
-                mStackView.updateBubble(update.updatedBubble);
+            if (update.updatedBubble != null) {
+                mBubbleViewCallback.updateBubble(update.updatedBubble);
             }
 
-            if (update.suppressedBubble != null && mStackView != null) {
-                mStackView.setBubbleSuppressed(update.suppressedBubble, true);
+            if (update.suppressedBubble != null) {
+                mBubbleViewCallback.suppressionChanged(update.suppressedBubble, true);
             }
 
-            if (update.unsuppressedBubble != null && mStackView != null) {
-                mStackView.setBubbleSuppressed(update.unsuppressedBubble, false);
+            if (update.unsuppressedBubble != null) {
+                mBubbleViewCallback.suppressionChanged(update.unsuppressedBubble, false);
             }
 
             boolean collapseStack = update.expandedChanged && !update.expanded;
 
             // At this point, the correct bubbles are inflated in the stack.
             // Make sure the order in bubble data is reflected in bubble row.
-            if (update.orderChanged && mStackView != null) {
+            if (update.orderChanged) {
                 mDataRepository.addBubbles(mCurrentUserId, update.bubbles);
                 // if the stack is going to be collapsed, do not update pointer position
                 // after reordering
-                mStackView.updateBubbleOrder(update.bubbles, !collapseStack);
+                mBubbleViewCallback.bubbleOrderChanged(update.bubbles, !collapseStack);
             }
 
             if (collapseStack) {
-                mStackView.setExpanded(false);
+                mBubbleViewCallback.expansionChanged(/* expanded= */ false);
                 mSysuiProxy.requestNotificationShadeTopUi(false, TAG);
             }
 
-            if (update.selectionChanged && mStackView != null) {
-                mStackView.setSelectedBubble(update.selectedBubble);
+            if (update.selectionChanged) {
+                mBubbleViewCallback.selectionChanged(update.selectedBubble);
             }
 
             // Expanding? Apply this last.
             if (update.expandedChanged && update.expanded) {
-                if (mStackView != null) {
-                    mStackView.setExpanded(true);
-                    mSysuiProxy.requestNotificationShadeTopUi(true, TAG);
-                }
+                mBubbleViewCallback.expansionChanged(/* expanded= */ true);
+                mSysuiProxy.requestNotificationShadeTopUi(true, TAG);
             }
 
             mSysuiProxy.notifyInvalidateNotifications("BubbleData.Listener.applyUpdate");
@@ -1406,6 +1479,19 @@
         }
     };
 
+    private void updateOverflowButtonDot() {
+        BubbleOverflow overflow = mBubbleData.getOverflow();
+        if (overflow == null) return;
+
+        for (Bubble b : mBubbleData.getOverflowBubbles()) {
+            if (b.showDot()) {
+                overflow.setShowDot(true);
+                return;
+            }
+        }
+        overflow.setShowDot(false);
+    }
+
     private boolean handleDismissalInterception(BubbleEntry entry,
             @Nullable List<BubbleEntry> children, IntConsumer removeCallback) {
         if (isSummaryOfBubbles(entry)) {
@@ -1852,13 +1938,6 @@
         }
 
         @Override
-        public void setBubbleBarEnabled(boolean enabled) {
-            mMainExecutor.execute(() -> {
-                BubbleController.this.setBubbleBarEnabled(enabled);
-            });
-        }
-
-        @Override
         public void onNotificationPanelExpandedChanged(boolean expanded) {
             mMainExecutor.execute(
                     () -> BubbleController.this.onNotificationPanelExpandedChanged(expanded));
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
index 6230d22..3fd0967 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
@@ -283,7 +283,7 @@
     }
 
     boolean isShowingOverflow() {
-        return mShowingOverflow && (isExpanded() || mPositioner.showingInTaskbar());
+        return mShowingOverflow && isExpanded();
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index 07c5852..5ea2450 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -18,9 +18,6 @@
 
 import static android.view.View.LAYOUT_DIRECTION_RTL;
 
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
-import android.annotation.IntDef;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -39,8 +36,6 @@
 import com.android.launcher3.icons.IconNormalizer;
 import com.android.wm.shell.R;
 
-import java.lang.annotation.Retention;
-
 /**
  * Keeps track of display size, configuration, and specific bubble sizes. One place for all
  * placement and positioning calculations to refer to.
@@ -50,15 +45,6 @@
             ? "BubblePositioner"
             : BubbleDebugConfig.TAG_BUBBLES;
 
-    @Retention(SOURCE)
-    @IntDef({TASKBAR_POSITION_NONE, TASKBAR_POSITION_RIGHT, TASKBAR_POSITION_LEFT,
-            TASKBAR_POSITION_BOTTOM})
-    @interface TaskbarPosition {}
-    public static final int TASKBAR_POSITION_NONE = -1;
-    public static final int TASKBAR_POSITION_RIGHT = 0;
-    public static final int TASKBAR_POSITION_LEFT = 1;
-    public static final int TASKBAR_POSITION_BOTTOM = 2;
-
     /** When the bubbles are collapsed in a stack only some of them are shown, this is how many. **/
     public static final int NUM_VISIBLE_WHEN_RESTING = 2;
     /** Indicates a bubble's height should be the maximum available space. **/
@@ -108,15 +94,9 @@
     private int mOverflowHeight;
     private int mMinimumFlyoutWidthLargeScreen;
 
-    private PointF mPinLocation;
     private PointF mRestingStackPosition;
     private int[] mPaddings = new int[4];
 
-    private boolean mShowingInTaskbar;
-    private @TaskbarPosition int mTaskbarPosition = TASKBAR_POSITION_NONE;
-    private int mTaskbarIconSize;
-    private int mTaskbarSize;
-
     public BubblePositioner(Context context, WindowManager windowManager) {
         mContext = context;
         mWindowManager = windowManager;
@@ -153,27 +133,11 @@
                     + " insets: " + insets
                     + " isLargeScreen: " + mIsLargeScreen
                     + " isSmallTablet: " + mIsSmallTablet
-                    + " bounds: " + bounds
-                    + " showingInTaskbar: " + mShowingInTaskbar);
+                    + " bounds: " + bounds);
         }
         updateInternal(mRotation, insets, bounds);
     }
 
-    /**
-     * Updates position information to account for taskbar state.
-     *
-     * @param taskbarPosition which position the taskbar is displayed in.
-     * @param showingInTaskbar whether the taskbar is being shown.
-     */
-    public void updateForTaskbar(int iconSize,
-            @TaskbarPosition int taskbarPosition, boolean showingInTaskbar, int taskbarSize) {
-        mShowingInTaskbar = showingInTaskbar;
-        mTaskbarIconSize =  iconSize;
-        mTaskbarPosition = taskbarPosition;
-        mTaskbarSize = taskbarSize;
-        update();
-    }
-
     @VisibleForTesting
     public void updateInternal(int rotation, Insets insets, Rect bounds) {
         mRotation = rotation;
@@ -232,10 +196,6 @@
                 R.dimen.bubbles_flyout_min_width_large_screen);
 
         mMaxBubbles = calculateMaxBubbles();
-
-        if (mShowingInTaskbar) {
-            adjustForTaskbar();
-        }
     }
 
     /**
@@ -260,30 +220,6 @@
         return mDefaultMaxBubbles;
     }
 
-    /**
-     * Taskbar insets appear as navigationBar insets, however, unlike navigationBar this should
-     * not inset bubbles UI as bubbles floats above the taskbar. This adjust the available space
-     * and insets to account for the taskbar.
-     */
-    // TODO(b/171559950): When the insets are reported correctly we can remove this logic
-    private void adjustForTaskbar() {
-        // When bar is showing on edges... subtract that inset because we appear on top
-        if (mShowingInTaskbar && mTaskbarPosition != TASKBAR_POSITION_BOTTOM) {
-            WindowInsets metricInsets = mWindowManager.getCurrentWindowMetrics().getWindowInsets();
-            Insets navBarInsets = metricInsets.getInsetsIgnoringVisibility(
-                    WindowInsets.Type.navigationBars());
-            int newInsetLeft = mInsets.left;
-            int newInsetRight = mInsets.right;
-            if (mTaskbarPosition == TASKBAR_POSITION_LEFT) {
-                mPositionRect.left -= navBarInsets.left;
-                newInsetLeft -= navBarInsets.left;
-            } else if (mTaskbarPosition == TASKBAR_POSITION_RIGHT) {
-                mPositionRect.right += navBarInsets.right;
-                newInsetRight -= navBarInsets.right;
-            }
-            mInsets = Insets.of(newInsetLeft, mInsets.top, newInsetRight, mInsets.bottom);
-        }
-    }
 
     /**
      * @return a rect of available screen space accounting for orientation, system bars and cutouts.
@@ -327,14 +263,12 @@
      * to the left or right side.
      */
     public boolean showBubblesVertically() {
-        return isLandscape() || mShowingInTaskbar || mIsLargeScreen;
+        return isLandscape() || mIsLargeScreen;
     }
 
     /** Size of the bubble. */
     public int getBubbleSize() {
-        return (mShowingInTaskbar && mTaskbarIconSize > 0)
-                ? mTaskbarIconSize
-                : mBubbleSize;
+        return mBubbleSize;
     }
 
     /** The amount of padding at the top of the screen that the bubbles avoid when being placed. */
@@ -699,9 +633,6 @@
 
     /** The position the bubble stack should rest at when collapsed. */
     public PointF getRestingPosition() {
-        if (mPinLocation != null) {
-            return mPinLocation;
-        }
         if (mRestingStackPosition == null) {
             return getDefaultStartPosition();
         }
@@ -713,9 +644,6 @@
      * is being shown.
      */
     public PointF getDefaultStartPosition() {
-        if (mPinLocation != null) {
-            return mPinLocation;
-        }
         // Start on the left if we're in LTR, right otherwise.
         final boolean startOnLeft =
                 mContext.getResources().getConfiguration().getLayoutDirection()
@@ -730,7 +658,6 @@
                         1 /* default starts with 1 bubble */));
     }
 
-
     /**
      * Returns the region that the stack position must stay within. This goes slightly off the left
      * and right sides of the screen, below the status bar/cutout and above the navigation bar.
@@ -751,39 +678,6 @@
     }
 
     /**
-     * @return whether the bubble stack is pinned to the taskbar.
-     */
-    public boolean showingInTaskbar() {
-        return mShowingInTaskbar;
-    }
-
-    /**
-     * @return the taskbar position if set.
-     */
-    public int getTaskbarPosition() {
-        return mTaskbarPosition;
-    }
-
-    public int getTaskbarSize() {
-        return mTaskbarSize;
-    }
-
-    /**
-     * In some situations bubbles will be pinned to a specific onscreen location. This sets whether
-     * bubbles should be pinned or not.
-     */
-    public void setUsePinnedLocation(boolean usePinnedLocation) {
-        if (usePinnedLocation) {
-            mShowingInTaskbar = true;
-            mPinLocation = new PointF(mPositionRect.right - mBubbleSize,
-                    mPositionRect.bottom - mBubbleSize);
-        } else {
-            mPinLocation = null;
-            mShowingInTaskbar = false;
-        }
-    }
-
-    /**
      * Navigation bar has an area where system gestures can be started from.
      *
      * @return {@link Rect} for system navigation bar gesture zone
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index f2afefe..5ecbd6b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -680,8 +680,6 @@
 
                     // Re-show the expanded view if we hid it.
                     showExpandedViewIfNeeded();
-                } else if (mPositioner.showingInTaskbar()) {
-                    mStackAnimationController.snapStackBack();
                 } else {
                     // Fling the stack to the edge, and save whether or not it's going to end up on
                     // the left side of the screen.
@@ -1362,16 +1360,6 @@
         updateOverflowVisibility();
     }
 
-    void updateOverflowButtonDot() {
-        for (Bubble b : mBubbleData.getOverflowBubbles()) {
-            if (b.showDot()) {
-                mBubbleOverflow.setShowDot(true);
-                return;
-            }
-        }
-        mBubbleOverflow.setShowDot(false);
-    }
-
     /**
      * Handle theme changes.
      */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
index df43257..a5deac5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
@@ -257,11 +257,6 @@
      */
     void onUserRemoved(int removedUserId);
 
-    /**
-     * Sets whether bubble bar should be enabled or not.
-     */
-    void setBubbleBarEnabled(boolean enabled);
-
     /** Listener to find out about stack expansion / collapse events. */
     interface BubbleExpandListener {
         /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
index 0ee0ea6..5533842 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
@@ -417,23 +417,9 @@
     }
 
     /**
-     * Snaps the stack back to the previous resting position.
-     */
-    public void snapStackBack() {
-        if (mLayout == null) {
-            return;
-        }
-        PointF p = getStackPositionAlongNearestHorizontalEdge();
-        springStackAfterFling(p.x, p.y);
-    }
-
-    /**
      * Where the stack would be if it were snapped to the nearest horizontal edge (left or right).
      */
     public PointF getStackPositionAlongNearestHorizontalEdge() {
-        if (mPositioner.showingInTaskbar()) {
-            return mPositioner.getRestingPosition();
-        }
         final PointF stackPos = getStackPosition();
         final boolean onLeft = mLayout.isFirstChildXLeftOfCenter(stackPos.x);
         final RectF bounds = mPositioner.getAllowableStackPositionRegion(getBubbleCount());
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DevicePostureController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DevicePostureController.java
index 22587f4..8b4ac1a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DevicePostureController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DevicePostureController.java
@@ -39,6 +39,9 @@
  *
  * Note that most of the implementation here inherits from
  * {@link com.android.systemui.statusbar.policy.DevicePostureController}.
+ *
+ * Use the {@link TabletopModeController} if you are interested in tabletop mode change only,
+ * which is more common.
  */
 public class DevicePostureController {
     @IntDef(prefix = {"DEVICE_POSTURE_"}, value = {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TabletopModeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TabletopModeController.java
new file mode 100644
index 0000000..ac6e4c2
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TabletopModeController.java
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.common;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import static com.android.wm.shell.common.DevicePostureController.DEVICE_POSTURE_HALF_OPENED;
+import static com.android.wm.shell.common.DevicePostureController.DEVICE_POSTURE_UNKNOWN;
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_FOLDABLE;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.app.WindowConfiguration;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.os.SystemProperties;
+import android.util.ArraySet;
+import android.view.Surface;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.common.annotations.ShellMainThread;
+import com.android.wm.shell.sysui.ShellInit;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Wrapper class to track the tabletop (aka. flex) mode change on Fold-ables.
+ * See also <a
+ * href="https://developer.android.com/guide/topics/large-screens/learn-about-foldables
+ * #foldable_postures">Foldable states and postures</a> for reference.
+ *
+ * Use the {@link DevicePostureController} for more detailed posture changes.
+ */
+public class TabletopModeController implements
+        DevicePostureController.OnDevicePostureChangedListener,
+        DisplayController.OnDisplaysChangedListener {
+    /**
+     * When {@code true}, floating windows like PiP would auto move to the position
+     * specified by {@link #PREFER_TOP_HALF_IN_TABLETOP} when in tabletop mode.
+     */
+    private static final boolean ENABLE_MOVE_FLOATING_WINDOW_IN_TABLETOP =
+            SystemProperties.getBoolean(
+                    "persist.wm.debug.enable_move_floating_window_in_tabletop", true);
+
+    /**
+     * Prefer the {@link #PREFERRED_TABLETOP_HALF_TOP} if this flag is enabled,
+     * {@link #PREFERRED_TABLETOP_HALF_BOTTOM} otherwise.
+     * See also {@link #getPreferredHalfInTabletopMode()}.
+     */
+    private static final boolean PREFER_TOP_HALF_IN_TABLETOP =
+            SystemProperties.getBoolean("persist.wm.debug.prefer_top_half_in_tabletop", true);
+
+    private static final long TABLETOP_MODE_DELAY_MILLIS = 1_000;
+
+    @IntDef(prefix = {"PREFERRED_TABLETOP_HALF_"}, value = {
+            PREFERRED_TABLETOP_HALF_TOP,
+            PREFERRED_TABLETOP_HALF_BOTTOM
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PreferredTabletopHalf {}
+
+    public static final int PREFERRED_TABLETOP_HALF_TOP = 0;
+    public static final int PREFERRED_TABLETOP_HALF_BOTTOM = 1;
+
+    private final Context mContext;
+
+    private final DevicePostureController mDevicePostureController;
+
+    private final DisplayController mDisplayController;
+
+    private final ShellExecutor mMainExecutor;
+
+    private final Set<Integer> mTabletopModeRotations = new ArraySet<>();
+
+    private final List<OnTabletopModeChangedListener> mListeners = new ArrayList<>();
+
+    @VisibleForTesting
+    final Runnable mOnEnterTabletopModeCallback = () -> {
+        if (isInTabletopMode()) {
+            // We are still in tabletop mode, go ahead.
+            mayBroadcastOnTabletopModeChange(true /* isInTabletopMode */);
+        }
+    };
+
+    @DevicePostureController.DevicePostureInt
+    private int mDevicePosture = DEVICE_POSTURE_UNKNOWN;
+
+    @Surface.Rotation
+    private int mDisplayRotation = WindowConfiguration.ROTATION_UNDEFINED;
+
+    /**
+     * Track the last callback value for {@link OnTabletopModeChangedListener}.
+     * This is to avoid duplicated {@code false} callback to {@link #mListeners}.
+     */
+    private Boolean mLastIsInTabletopModeForCallback;
+
+    public TabletopModeController(Context context,
+            ShellInit shellInit,
+            DevicePostureController postureController,
+            DisplayController displayController,
+            @ShellMainThread ShellExecutor mainExecutor) {
+        mContext = context;
+        mDevicePostureController = postureController;
+        mDisplayController = displayController;
+        mMainExecutor = mainExecutor;
+        shellInit.addInitCallback(this::onInit, this);
+    }
+
+    @VisibleForTesting
+    void onInit() {
+        mDevicePostureController.registerOnDevicePostureChangedListener(this);
+        mDisplayController.addDisplayWindowListener(this);
+        // Aligns with what's in {@link com.android.server.wm.DisplayRotation}.
+        final int[] deviceTabletopRotations = mContext.getResources().getIntArray(
+                com.android.internal.R.array.config_deviceTabletopRotations);
+        if (deviceTabletopRotations == null || deviceTabletopRotations.length == 0) {
+            ProtoLog.e(WM_SHELL_FOLDABLE,
+                    "No valid config_deviceTabletopRotations, can not tell"
+                            + " tabletop mode in WMShell");
+            return;
+        }
+        for (int angle : deviceTabletopRotations) {
+            switch (angle) {
+                case 0:
+                    mTabletopModeRotations.add(Surface.ROTATION_0);
+                    break;
+                case 90:
+                    mTabletopModeRotations.add(Surface.ROTATION_90);
+                    break;
+                case 180:
+                    mTabletopModeRotations.add(Surface.ROTATION_180);
+                    break;
+                case 270:
+                    mTabletopModeRotations.add(Surface.ROTATION_270);
+                    break;
+                default:
+                    ProtoLog.e(WM_SHELL_FOLDABLE,
+                            "Invalid surface rotation angle in "
+                                    + "config_deviceTabletopRotations: %d",
+                            angle);
+                    break;
+            }
+        }
+    }
+
+    /**
+     * @return {@code true} if floating windows like PiP would auto move to the position
+     * specified by {@link #getPreferredHalfInTabletopMode()} when in tabletop mode.
+     */
+    public boolean enableMoveFloatingWindowInTabletop() {
+        return ENABLE_MOVE_FLOATING_WINDOW_IN_TABLETOP;
+    }
+
+    /** @return Preferred half for floating windows like PiP when in tabletop mode. */
+    @PreferredTabletopHalf
+    public int getPreferredHalfInTabletopMode() {
+        return PREFER_TOP_HALF_IN_TABLETOP
+                ? PREFERRED_TABLETOP_HALF_TOP
+                : PREFERRED_TABLETOP_HALF_BOTTOM;
+    }
+
+    /** Register {@link OnTabletopModeChangedListener} to listen for tabletop mode change. */
+    public void registerOnTabletopModeChangedListener(
+            @NonNull OnTabletopModeChangedListener listener) {
+        if (listener == null || mListeners.contains(listener)) return;
+        mListeners.add(listener);
+        listener.onTabletopModeChanged(isInTabletopMode());
+    }
+
+    /** Unregister {@link OnTabletopModeChangedListener} for tabletop mode change. */
+    public void unregisterOnTabletopModeChangedListener(
+            @NonNull OnTabletopModeChangedListener listener) {
+        mListeners.remove(listener);
+    }
+
+    @Override
+    public void onDevicePostureChanged(@DevicePostureController.DevicePostureInt int posture) {
+        if (mDevicePosture != posture) {
+            onDevicePostureOrDisplayRotationChanged(posture, mDisplayRotation);
+        }
+    }
+
+    @Override
+    public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
+        final int newDisplayRotation = newConfig.windowConfiguration.getDisplayRotation();
+        if (displayId == DEFAULT_DISPLAY && newDisplayRotation != mDisplayRotation) {
+            onDevicePostureOrDisplayRotationChanged(mDevicePosture, newDisplayRotation);
+        }
+    }
+
+    private void onDevicePostureOrDisplayRotationChanged(
+            @DevicePostureController.DevicePostureInt int newPosture,
+            @Surface.Rotation int newDisplayRotation) {
+        final boolean wasInTabletopMode = isInTabletopMode();
+        mDevicePosture = newPosture;
+        mDisplayRotation = newDisplayRotation;
+        final boolean couldBeInTabletopMode = isInTabletopMode();
+        mMainExecutor.removeCallbacks(mOnEnterTabletopModeCallback);
+        if (!wasInTabletopMode && couldBeInTabletopMode) {
+            // May enter tabletop mode, but we need to wait for additional time since this
+            // could be an intermediate state.
+            mMainExecutor.executeDelayed(mOnEnterTabletopModeCallback, TABLETOP_MODE_DELAY_MILLIS);
+        } else {
+            // Cancel entering tabletop mode if any condition's changed.
+            mayBroadcastOnTabletopModeChange(false /* isInTabletopMode */);
+        }
+    }
+
+    private boolean isHalfOpened(@DevicePostureController.DevicePostureInt int posture) {
+        return posture == DEVICE_POSTURE_HALF_OPENED;
+    }
+
+    private boolean isInTabletopMode() {
+        return isHalfOpened(mDevicePosture) && mTabletopModeRotations.contains(mDisplayRotation);
+    }
+
+    private void mayBroadcastOnTabletopModeChange(boolean isInTabletopMode) {
+        if (mLastIsInTabletopModeForCallback == null
+                || mLastIsInTabletopModeForCallback != isInTabletopMode) {
+            mListeners.forEach(l -> l.onTabletopModeChanged(isInTabletopMode));
+            mLastIsInTabletopModeForCallback = isInTabletopMode;
+        }
+    }
+
+    /**
+     * Listener interface for tabletop mode change.
+     */
+    public interface OnTabletopModeChangedListener {
+        /**
+         * Callback when tabletop mode changes. Expect duplicated callbacks with {@code false}.
+         * @param isInTabletopMode {@code true} if enters tabletop mode, {@code false} otherwise.
+         */
+        void onTabletopModeChanged(boolean isInTabletopMode);
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
index abb357c..bdf0ac2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
@@ -247,11 +247,11 @@
 
     /** Stops showing resizing hint. */
     public void onResized(SurfaceControl.Transaction t, Runnable animFinishedCallback) {
-        if (mScreenshot != null) {
-            if (mScreenshotAnimator != null && mScreenshotAnimator.isRunning()) {
-                mScreenshotAnimator.cancel();
-            }
+        if (mScreenshotAnimator != null && mScreenshotAnimator.isRunning()) {
+            mScreenshotAnimator.cancel();
+        }
 
+        if (mScreenshot != null) {
             t.setPosition(mScreenshot, mOffsetX, mOffsetY);
 
             final SurfaceControl.Transaction animT = new SurfaceControl.Transaction();
@@ -321,6 +321,10 @@
     /** Screenshot host leash and attach on it if meet some conditions */
     public void screenshotIfNeeded(SurfaceControl.Transaction t) {
         if (!mShown && mIsResizing && !mOldBounds.equals(mResizingBounds)) {
+            if (mScreenshotAnimator != null && mScreenshotAnimator.isRunning()) {
+                mScreenshotAnimator.cancel();
+            }
+
             mTempRect.set(mOldBounds);
             mTempRect.offsetTo(0, 0);
             mScreenshot = ScreenshotUtils.takeScreenshot(t, mHostLeash, mTempRect,
@@ -333,6 +337,10 @@
         if (screenshot == null || !screenshot.isValid()) return;
 
         if (!mShown && mIsResizing && !mOldBounds.equals(mResizingBounds)) {
+            if (mScreenshotAnimator != null && mScreenshotAnimator.isRunning()) {
+                mScreenshotAnimator.cancel();
+            }
+
             mScreenshot = screenshot;
             t.reparent(screenshot, mHostLeash);
             t.setLayer(screenshot, Integer.MAX_VALUE - 1);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index f616e6f..b4acd60 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -120,6 +120,7 @@
     private int mOrientation;
     private int mRotation;
     private int mDensity;
+    private int mUiMode;
 
     private final boolean mDimNonImeSide;
     private ValueAnimator mDividerFlingAnimator;
@@ -295,10 +296,12 @@
         final Rect rootBounds = configuration.windowConfiguration.getBounds();
         final int orientation = configuration.orientation;
         final int density = configuration.densityDpi;
+        final int uiMode = configuration.uiMode;
 
         if (mOrientation == orientation
                 && mRotation == rotation
                 && mDensity == density
+                && mUiMode == uiMode
                 && mRootBounds.equals(rootBounds)) {
             return false;
         }
@@ -310,6 +313,7 @@
         mRootBounds.set(rootBounds);
         mRotation = rotation;
         mDensity = density;
+        mUiMode = uiMode;
         mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds, null);
         updateDividerConfig(mContext);
         initDividerPosition(mTempRect);
@@ -723,6 +727,10 @@
         getRefBounds2(mTempRect);
         t.setPosition(leash2, mTempRect.left, mTempRect.top)
                 .setWindowCrop(leash2, mTempRect.width(), mTempRect.height());
+        // Make right or bottom side surface always higher than left or top side to avoid weird
+        // animation when dismiss split. e.g. App surface fling above on decor surface.
+        t.setLayer(leash1, 1);
+        t.setLayer(leash2, 2);
 
         if (mImePositionProcessor.adjustSurfaceLayoutForIme(
                 t, dividerLeash, leash1, leash2, dimLayer1, dimLayer2)) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIConfiguration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIConfiguration.java
index 06f0a70..902c41c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIConfiguration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIConfiguration.java
@@ -39,22 +39,41 @@
             "enable_letterbox_restart_confirmation_dialog";
 
     private static final String KEY_ENABLE_LETTERBOX_REACHABILITY_EDUCATION =
-            "enable_letterbox_reachability_education";
+            "enable_letterbox_education_for_reachability";
 
     private static final boolean DEFAULT_VALUE_ENABLE_LETTERBOX_RESTART_DIALOG = true;
 
-    private static final boolean DEFAULT_VALUE_ENABLE_LETTERBOX_REACHABILITY_EDUCATION = false;
+    private static final boolean DEFAULT_VALUE_ENABLE_LETTERBOX_REACHABILITY_EDUCATION = true;
 
     /**
-     * The name of the {@link SharedPreferences} that holds which user has seen the Restart
-     * confirmation dialog.
+     * The name of the {@link SharedPreferences} that holds information about compat ui.
      */
-    private static final String DONT_SHOW_RESTART_DIALOG_PREF_NAME = "dont_show_restart_dialog";
+    private static final String COMPAT_UI_SHARED_PREFERENCES = "dont_show_restart_dialog";
 
     /**
-     * The {@link SharedPreferences} instance for {@link #DONT_SHOW_RESTART_DIALOG_PREF_NAME}.
+     * The name of the {@link SharedPreferences} that holds which user has seen the Letterbox
+     * Education dialog.
      */
-    private final SharedPreferences mSharedPreferences;
+    private static final String HAS_SEEN_LETTERBOX_EDUCATION_SHARED_PREFERENCES =
+            "has_seen_letterbox_education";
+
+    /**
+     * Key prefix for the {@link SharedPreferences} entries related to the reachability
+     * education.
+     */
+    private static final String HAS_SEEN_REACHABILITY_EDUCATION_KEY_PREFIX =
+            "has_seen_reachability_education";
+
+    /**
+     * The {@link SharedPreferences} instance for the restart dialog and the reachability
+     * education.
+     */
+    private final SharedPreferences mCompatUISharedPreferences;
+
+    /**
+     * The {@link SharedPreferences} instance for the letterbox education dialog.
+     */
+    private final SharedPreferences mLetterboxEduSharedPreferences;
 
     // Whether the extended restart dialog is enabled
     private boolean mIsRestartDialogEnabled;
@@ -88,8 +107,10 @@
                 DEFAULT_VALUE_ENABLE_LETTERBOX_REACHABILITY_EDUCATION);
         DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_APP_COMPAT, mainExecutor,
                 this);
-        mSharedPreferences = context.getSharedPreferences(DONT_SHOW_RESTART_DIALOG_PREF_NAME,
+        mCompatUISharedPreferences = context.getSharedPreferences(getCompatUISharedPreferenceName(),
                 Context.MODE_PRIVATE);
+        mLetterboxEduSharedPreferences = context.getSharedPreferences(
+                getHasSeenLetterboxEducationSharedPreferencedName(), Context.MODE_PRIVATE);
     }
 
     /**
@@ -122,20 +143,53 @@
         mIsReachabilityEducationOverrideEnabled = enabled;
     }
 
-    boolean getDontShowRestartDialogAgain(TaskInfo taskInfo) {
-        final int userId = taskInfo.userId;
-        final String packageName = taskInfo.topActivity.getPackageName();
-        return mSharedPreferences.getBoolean(
-                getDontShowAgainRestartKey(userId, packageName), /* default= */ false);
-    }
-
     void setDontShowRestartDialogAgain(TaskInfo taskInfo) {
-        final int userId = taskInfo.userId;
-        final String packageName = taskInfo.topActivity.getPackageName();
-        mSharedPreferences.edit().putBoolean(getDontShowAgainRestartKey(userId, packageName),
+        mCompatUISharedPreferences.edit().putBoolean(
+                getDontShowAgainRestartKey(taskInfo.userId, taskInfo.topActivity.getPackageName()),
                 true).apply();
     }
 
+    boolean shouldShowRestartDialogAgain(TaskInfo taskInfo) {
+        return !mCompatUISharedPreferences.getBoolean(getDontShowAgainRestartKey(taskInfo.userId,
+                taskInfo.topActivity.getPackageName()), /* default= */ false);
+    }
+
+    void setDontShowReachabilityEducationAgain(TaskInfo taskInfo) {
+        mCompatUISharedPreferences.edit().putBoolean(
+                getDontShowAgainReachabilityEduKey(taskInfo.userId,
+                        taskInfo.topActivity.getPackageName()), true).apply();
+    }
+
+    boolean shouldShowReachabilityEducation(@NonNull TaskInfo taskInfo) {
+        return getHasSeenLetterboxEducation(taskInfo.userId)
+                && !mCompatUISharedPreferences.getBoolean(
+                getDontShowAgainReachabilityEduKey(taskInfo.userId,
+                        taskInfo.topActivity.getPackageName()), /* default= */false);
+    }
+
+    boolean getHasSeenLetterboxEducation(int userId) {
+        return mLetterboxEduSharedPreferences
+                .getBoolean(getDontShowLetterboxEduKey(userId), /* default= */ false);
+    }
+
+    void setSeenLetterboxEducation(int userId) {
+        mLetterboxEduSharedPreferences.edit().putBoolean(getDontShowLetterboxEduKey(userId),
+                true).apply();
+    }
+
+    protected String getCompatUISharedPreferenceName() {
+        return COMPAT_UI_SHARED_PREFERENCES;
+    }
+
+    protected String getHasSeenLetterboxEducationSharedPreferencedName() {
+        return HAS_SEEN_LETTERBOX_EDUCATION_SHARED_PREFERENCES;
+    }
+
+    /**
+     * Updates the {@link DeviceConfig} state for the CompatUI
+     * @param properties Contains the complete collection of properties which have changed for a
+     *                   single namespace. This includes only those which were added, updated,
+     */
     @Override
     public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) {
         if (properties.getKeyset().contains(KEY_ENABLE_LETTERBOX_RESTART_DIALOG)) {
@@ -152,6 +206,14 @@
         }
     }
 
+    private static String getDontShowAgainReachabilityEduKey(int userId, String packageName) {
+        return HAS_SEEN_REACHABILITY_EDUCATION_KEY_PREFIX + "_" + packageName + "@" + userId;
+    }
+
+    private static String getDontShowLetterboxEduKey(int userId) {
+        return String.valueOf(userId);
+    }
+
     private String getDontShowAgainRestartKey(int userId, String packageName) {
         return packageName + "@" + userId;
     }
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 76d9152..4d83247 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
@@ -42,7 +42,6 @@
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.compatui.CompatUIWindowManager.CompatUIHintsState;
-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;
@@ -113,6 +112,12 @@
     @Nullable
     private LetterboxEduWindowManager mActiveLetterboxEduLayout;
 
+    /**
+     * The active Reachability UI layout.
+     */
+    @Nullable
+    private ReachabilityEduWindowManager mActiveReachabilityEduLayout;
+
     /** Avoid creating display context frequently for non-default display. */
     private final SparseArray<WeakReference<Context>> mDisplayContextCache = new SparseArray<>(0);
 
@@ -196,6 +201,7 @@
         createOrUpdateCompatLayout(taskInfo, taskListener);
         createOrUpdateLetterboxEduLayout(taskInfo, taskListener);
         createOrUpdateRestartDialogLayout(taskInfo, taskListener);
+        createOrUpdateReachabilityEduLayout(taskInfo, taskListener, false);
     }
 
     @Override
@@ -309,7 +315,7 @@
     private void onRestartButtonClicked(
             Pair<TaskInfo, ShellTaskOrganizer.TaskListener> taskInfoState) {
         if (mCompatUIConfiguration.isRestartDialogEnabled()
-                && !mCompatUIConfiguration.getDontShowRestartDialogAgain(
+                && mCompatUIConfiguration.shouldShowRestartDialogAgain(
                 taskInfoState.first)) {
             // We need to show the dialog
             mSetOfTaskIdsShowingRestartDialog.add(taskInfoState.first.taskId);
@@ -356,13 +362,15 @@
             ShellTaskOrganizer.TaskListener taskListener) {
         return new LetterboxEduWindowManager(context, taskInfo,
                 mSyncQueue, taskListener, mDisplayController.getDisplayLayout(taskInfo.displayId),
-                mTransitionsLazy.get(),
-                this::onLetterboxEduDismissed,
-                mDockStateReader);
+                mTransitionsLazy.get(), this::onLetterboxEduDismissed, mDockStateReader,
+                mCompatUIConfiguration);
     }
 
-    private void onLetterboxEduDismissed() {
+    private void onLetterboxEduDismissed(
+            Pair<TaskInfo, ShellTaskOrganizer.TaskListener> stateInfo) {
         mActiveLetterboxEduLayout = null;
+        // We need to update the UI
+        createOrUpdateReachabilityEduLayout(stateInfo.first, stateInfo.second, true);
     }
 
     private void createOrUpdateRestartDialogLayout(TaskInfo taskInfo,
@@ -420,6 +428,47 @@
         onCompatInfoChanged(stateInfo.first, stateInfo.second);
     }
 
+    private void createOrUpdateReachabilityEduLayout(TaskInfo taskInfo,
+            ShellTaskOrganizer.TaskListener taskListener, boolean forceUpdate) {
+        if (mActiveReachabilityEduLayout != null) {
+            mActiveReachabilityEduLayout.forceUpdate(forceUpdate);
+            // UI already exists, update the UI layout.
+            if (!mActiveReachabilityEduLayout.updateCompatInfo(taskInfo, taskListener,
+                    showOnDisplay(mActiveReachabilityEduLayout.getDisplayId()))) {
+                // The layout is no longer eligible to be shown, remove from active layouts.
+                mActiveReachabilityEduLayout = null;
+            }
+            return;
+        }
+        // Create a new UI layout.
+        final Context context = getOrCreateDisplayContext(taskInfo.displayId);
+        if (context == null) {
+            return;
+        }
+        ReachabilityEduWindowManager newLayout = createReachabilityEduWindowManager(context,
+                taskInfo, taskListener);
+        if (newLayout.createLayout(showOnDisplay(taskInfo.displayId))) {
+            // The new layout is eligible to be shown, make it the active layout.
+            if (mActiveReachabilityEduLayout != null) {
+                // Release the previous layout since at most one can be active.
+                // Since letterbox reachability education is only shown once to the user,
+                // releasing the previous layout is only a precaution.
+                mActiveReachabilityEduLayout.release();
+            }
+            mActiveReachabilityEduLayout = newLayout;
+        }
+    }
+
+    @VisibleForTesting
+    ReachabilityEduWindowManager createReachabilityEduWindowManager(Context context,
+            TaskInfo taskInfo,
+            ShellTaskOrganizer.TaskListener taskListener) {
+        return new ReachabilityEduWindowManager(context, taskInfo, mSyncQueue, mCallback,
+                taskListener, mDisplayController.getDisplayLayout(taskInfo.displayId),
+                mCompatUIConfiguration, mMainExecutor);
+    }
+
+
     private void removeLayouts(int taskId) {
         final CompatUIWindowManager layout = mActiveCompatLayouts.get(taskId);
         if (layout != null) {
@@ -439,6 +488,11 @@
             mTaskIdToRestartDialogWindowManagerMap.remove(taskId);
             mSetOfTaskIdsShowingRestartDialog.remove(taskId);
         }
+        if (mActiveReachabilityEduLayout != null
+                && mActiveReachabilityEduLayout.getTaskId() == taskId) {
+            mActiveReachabilityEduLayout.release();
+            mActiveReachabilityEduLayout = null;
+        }
     }
 
     private Context getOrCreateDisplayContext(int displayId) {
@@ -491,6 +545,9 @@
                 callback.accept(layout);
             }
         }
+        if (mActiveReachabilityEduLayout != null && condition.test(mActiveReachabilityEduLayout)) {
+            callback.accept(mActiveReachabilityEduLayout);
+        }
     }
 
     /** An implementation of {@link OnInsetsChangedListener} for a given display id. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
index fe95d04..170c0ee 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
@@ -38,7 +38,6 @@
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.compatui.CompatUIController.CompatUICallback;
-import com.android.wm.shell.compatui.letterboxedu.LetterboxEduWindowManager;
 
 import java.util.function.Consumer;
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java
index cfb2acc..346cd94 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java
@@ -384,7 +384,7 @@
                 // Cannot be wrap_content as this determines the actual window size
                 width, height,
                 TYPE_APPLICATION_OVERLAY,
-                FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL,
+                getWindowManagerLayoutParamsFlags(),
                 PixelFormat.TRANSLUCENT);
         winParams.token = new Binder();
         winParams.setTitle(getClass().getSimpleName() + mTaskId);
@@ -392,6 +392,13 @@
         return winParams;
     }
 
+    /**
+     * @return Flags to use for the {@link WindowManager} layout
+     */
+    protected int getWindowManagerLayoutParamsFlags() {
+        return FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL;
+    }
+
     protected final String getTag() {
         return getClass().getSimpleName();
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogActionLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/LetterboxEduDialogActionLayout.java
similarity index 95%
rename from libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogActionLayout.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/compatui/LetterboxEduDialogActionLayout.java
index 02197f6..9974295 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogActionLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/LetterboxEduDialogActionLayout.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.wm.shell.compatui.letterboxedu;
+package com.android.wm.shell.compatui;
 
 import android.content.Context;
 import android.content.res.TypedArray;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/LetterboxEduDialogLayout.java
similarity index 94%
rename from libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/compatui/LetterboxEduDialogLayout.java
index 9232f36..df2f6ce 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/LetterboxEduDialogLayout.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.wm.shell.compatui.letterboxedu;
+package com.android.wm.shell.compatui;
 
 import android.annotation.Nullable;
 import android.content.Context;
@@ -26,7 +26,6 @@
 import androidx.constraintlayout.widget.ConstraintLayout;
 
 import com.android.wm.shell.R;
-import com.android.wm.shell.compatui.DialogContainerSupplier;
 
 /**
  * Container for Letterbox Education Dialog and background dim.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/LetterboxEduWindowManager.java
similarity index 82%
rename from libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/compatui/LetterboxEduWindowManager.java
index c14c009..0c21c8c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/LetterboxEduWindowManager.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,16 +14,17 @@
  * limitations under the License.
  */
 
-package com.android.wm.shell.compatui.letterboxedu;
+package com.android.wm.shell.compatui;
 
 import static android.provider.Settings.Secure.LAUNCHER_TASKBAR_EDUCATION_SHOWING;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.TaskInfo;
 import android.content.Context;
-import android.content.SharedPreferences;
 import android.graphics.Rect;
 import android.provider.Settings;
+import android.util.Pair;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup.MarginLayoutParams;
@@ -36,14 +37,14 @@
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.common.DockStateReader;
 import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.compatui.CompatUIWindowManagerAbstract;
-import com.android.wm.shell.compatui.DialogAnimationController;
 import com.android.wm.shell.transition.Transitions;
 
+import java.util.function.Consumer;
+
 /**
  * Window manager for the Letterbox Education.
  */
-public class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract {
+class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract {
 
     /**
      * The Letterbox Education should be the topmost child of the Task in case there can be more
@@ -51,19 +52,6 @@
      */
     public static final int Z_ORDER = Integer.MAX_VALUE;
 
-    /**
-     * The name of the {@link SharedPreferences} that holds which user has seen the Letterbox
-     * Education dialog.
-     */
-    @VisibleForTesting
-    static final String HAS_SEEN_LETTERBOX_EDUCATION_PREF_NAME =
-            "has_seen_letterbox_education";
-
-    /**
-     * The {@link SharedPreferences} instance for {@link #HAS_SEEN_LETTERBOX_EDUCATION_PREF_NAME}.
-     */
-    private final SharedPreferences mSharedPreferences;
-
     private final DialogAnimationController<LetterboxEduDialogLayout> mAnimationController;
 
     private final Transitions mTransitions;
@@ -75,6 +63,10 @@
      */
     private final int mUserId;
 
+    private final Consumer<Pair<TaskInfo, ShellTaskOrganizer.TaskListener>> mOnDismissCallback;
+
+    private final CompatUIConfiguration mCompatUIConfiguration;
+
     // Remember the last reported state in case visibility changes due to keyguard or IME updates.
     private boolean mEligibleForLetterboxEducation;
 
@@ -82,7 +74,8 @@
     @VisibleForTesting
     LetterboxEduDialogLayout mLayout;
 
-    private final Runnable mOnDismissCallback;
+    @NonNull
+    private TaskInfo mTaskInfo;
 
     /**
      * The vertical margin between the dialog container and the task stable bounds (excluding
@@ -92,33 +85,35 @@
 
     private final DockStateReader mDockStateReader;
 
-    public LetterboxEduWindowManager(Context context, TaskInfo taskInfo,
+    LetterboxEduWindowManager(Context context, TaskInfo taskInfo,
             SyncTransactionQueue syncQueue, ShellTaskOrganizer.TaskListener taskListener,
             DisplayLayout displayLayout, Transitions transitions,
-            Runnable onDismissCallback, DockStateReader dockStateReader) {
+            Consumer<Pair<TaskInfo, ShellTaskOrganizer.TaskListener>> onDismissCallback,
+            DockStateReader dockStateReader, CompatUIConfiguration compatUIConfiguration) {
         this(context, taskInfo, syncQueue, taskListener, displayLayout, transitions,
                 onDismissCallback,
                 new DialogAnimationController<>(context, /* tag */ "LetterboxEduWindowManager"),
-                dockStateReader);
+                dockStateReader, compatUIConfiguration);
     }
 
     @VisibleForTesting
     LetterboxEduWindowManager(Context context, TaskInfo taskInfo,
             SyncTransactionQueue syncQueue, ShellTaskOrganizer.TaskListener taskListener,
-            DisplayLayout displayLayout, Transitions transitions, Runnable onDismissCallback,
+            DisplayLayout displayLayout, Transitions transitions,
+            Consumer<Pair<TaskInfo, ShellTaskOrganizer.TaskListener>> onDismissCallback,
             DialogAnimationController<LetterboxEduDialogLayout> animationController,
-            DockStateReader dockStateReader) {
+            DockStateReader dockStateReader, CompatUIConfiguration compatUIConfiguration) {
         super(context, taskInfo, syncQueue, taskListener, displayLayout);
+        mTaskInfo = taskInfo;
         mTransitions = transitions;
         mOnDismissCallback = onDismissCallback;
         mAnimationController = animationController;
         mUserId = taskInfo.userId;
-        mEligibleForLetterboxEducation = taskInfo.topActivityEligibleForLetterboxEducation;
-        mSharedPreferences = mContext.getSharedPreferences(HAS_SEEN_LETTERBOX_EDUCATION_PREF_NAME,
-                Context.MODE_PRIVATE);
         mDialogVerticalMargin = (int) mContext.getResources().getDimension(
                 R.dimen.letterbox_education_dialog_margin);
         mDockStateReader = dockStateReader;
+        mCompatUIConfiguration = compatUIConfiguration;
+        mEligibleForLetterboxEducation = taskInfo.topActivityEligibleForLetterboxEducation;
     }
 
     @Override
@@ -144,8 +139,8 @@
         //   the controller will create a new instance of this class since this one isn't eligible).
         // - If the layout isn't null then it was previously showing, and we shouldn't check if the
         //   user has seen the letterbox education before.
-        return mEligibleForLetterboxEducation && !isTaskbarEduShowing()
-                && (mLayout != null || !getHasSeenLetterboxEducation())
+        return mEligibleForLetterboxEducation && !isTaskbarEduShowing() && (mLayout != null
+                || !mCompatUIConfiguration.getHasSeenLetterboxEducation(mUserId))
                 && !mDockStateReader.isDocked();
     }
 
@@ -194,7 +189,6 @@
             // Dialog has already been released.
             return;
         }
-        setSeenLetterboxEducation();
         mLayout.setDismissOnClickListener(this::onDismiss);
         // Focus on the dialog title for accessibility.
         mLayout.getDialogTitle().sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
@@ -204,10 +198,11 @@
         if (mLayout == null) {
             return;
         }
+        mCompatUIConfiguration.setSeenLetterboxEducation(mUserId);
         mLayout.setDismissOnClickListener(null);
         mAnimationController.startExitAnimation(mLayout, () -> {
             release();
-            mOnDismissCallback.run();
+            mOnDismissCallback.accept(Pair.create(mTaskInfo, getTaskListener()));
         });
     }
 
@@ -220,6 +215,7 @@
     @Override
     public boolean updateCompatInfo(TaskInfo taskInfo, ShellTaskOrganizer.TaskListener taskListener,
             boolean canShow) {
+        mTaskInfo = taskInfo;
         mEligibleForLetterboxEducation = taskInfo.topActivityEligibleForLetterboxEducation;
 
         return super.updateCompatInfo(taskInfo, taskListener, canShow);
@@ -250,18 +246,6 @@
                 taskBounds.height());
     }
 
-    private boolean getHasSeenLetterboxEducation() {
-        return mSharedPreferences.getBoolean(getPrefKey(), /* default= */ false);
-    }
-
-    private void setSeenLetterboxEducation() {
-        mSharedPreferences.edit().putBoolean(getPrefKey(), true).apply();
-    }
-
-    private String getPrefKey() {
-        return String.valueOf(mUserId);
-    }
-
     @VisibleForTesting
     boolean isTaskbarEduShowing() {
         return Settings.Secure.getInt(mContext.getContentResolver(),
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/ReachabilityEduHandLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/ReachabilityEduHandLayout.java
new file mode 100644
index 0000000..6081ef1
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/ReachabilityEduHandLayout.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.compatui;
+
+import android.content.Context;
+import android.graphics.drawable.Animatable;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.View;
+
+import androidx.appcompat.widget.AppCompatTextView;
+
+/**
+ * Custom layout for Reachability Education hand.
+ */
+public class ReachabilityEduHandLayout extends AppCompatTextView {
+
+    private Drawable mHandDrawable;
+
+    public ReachabilityEduHandLayout(Context context) {
+        this(context, null);
+    }
+
+    public ReachabilityEduHandLayout(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public ReachabilityEduHandLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        mHandDrawable = getCompoundDrawables()[/* top */ 1];
+    }
+
+    void hide() {
+        stopAnimation();
+        setAlpha(0);
+        setVisibility(View.INVISIBLE);
+    }
+
+    void startAnimation() {
+        if (mHandDrawable instanceof Animatable) {
+            final Animatable animatedBg = (Animatable) mHandDrawable;
+            animatedBg.start();
+        }
+    }
+
+    void stopAnimation() {
+        if (mHandDrawable instanceof Animatable) {
+            final Animatable animatedBg = (Animatable) mHandDrawable;
+            animatedBg.stop();
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/ReachabilityEduLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/ReachabilityEduLayout.java
new file mode 100644
index 0000000..6a72d28
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/ReachabilityEduLayout.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.compatui;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.app.TaskInfo;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.animation.AlphaAnimation;
+import android.view.animation.Animation;
+import android.widget.FrameLayout;
+
+import com.android.wm.shell.R;
+
+import java.util.function.BiConsumer;
+import java.util.function.Function;
+
+/**
+ * Container for reachability education which handles all the show/hide animations.
+ */
+public class ReachabilityEduLayout extends FrameLayout {
+
+    private static final float ALPHA_FULL_TRANSPARENT = 0f;
+
+    private static final float ALPHA_FULL_OPAQUE = 1f;
+
+    private static final long VISIBILITY_SHOW_ANIMATION_DURATION_MS = 167;
+
+    private static final long VISIBILITY_SHOW_ANIMATION_DELAY_MS = 250;
+
+    private static final long VISIBILITY_SHOW_DOUBLE_TAP_ANIMATION_DELAY_MS = 80;
+
+    private static final long MARGINS_ANIMATION_DURATION_MS = 250;
+
+    private ReachabilityEduWindowManager mWindowManager;
+
+    private ReachabilityEduHandLayout mMoveLeftButton;
+    private ReachabilityEduHandLayout mMoveRightButton;
+    private ReachabilityEduHandLayout mMoveUpButton;
+    private ReachabilityEduHandLayout mMoveDownButton;
+
+    private int mLastLeftMargin = TaskInfo.PROPERTY_VALUE_UNSET;
+    private int mLastRightMargin = TaskInfo.PROPERTY_VALUE_UNSET;
+    private int mLastTopMargin = TaskInfo.PROPERTY_VALUE_UNSET;
+    private int mLastBottomMargin = TaskInfo.PROPERTY_VALUE_UNSET;
+
+    private boolean mIsLayoutActive;
+
+    public ReachabilityEduLayout(Context context) {
+        this(context, null);
+    }
+
+    public ReachabilityEduLayout(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public ReachabilityEduLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public ReachabilityEduLayout(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    void inject(ReachabilityEduWindowManager windowManager) {
+        mWindowManager = windowManager;
+    }
+
+    void handleVisibility(boolean isActivityLetterboxed, int letterboxVerticalPosition,
+            int letterboxHorizontalPosition, int availableWidth, int availableHeight,
+            boolean isDoubleTap) {
+        // If the app is not letterboxed we hide all the buttons.
+        if (!mIsLayoutActive || !isActivityLetterboxed || (
+                letterboxHorizontalPosition == TaskInfo.PROPERTY_VALUE_UNSET
+                        && letterboxVerticalPosition == TaskInfo.PROPERTY_VALUE_UNSET)) {
+            hideAllImmediately();
+        } else if (letterboxHorizontalPosition != TaskInfo.PROPERTY_VALUE_UNSET) {
+            handleLetterboxHorizontalPosition(availableWidth, letterboxHorizontalPosition,
+                    isDoubleTap);
+        } else {
+            handleLetterboxVerticalPosition(availableHeight, letterboxVerticalPosition,
+                    isDoubleTap);
+        }
+    }
+
+    void hideAllImmediately() {
+        mMoveLeftButton.hide();
+        mMoveRightButton.hide();
+        mMoveUpButton.hide();
+        mMoveDownButton.hide();
+        mLastLeftMargin = TaskInfo.PROPERTY_VALUE_UNSET;
+        mLastRightMargin = TaskInfo.PROPERTY_VALUE_UNSET;
+        mLastTopMargin = TaskInfo.PROPERTY_VALUE_UNSET;
+        mLastBottomMargin = TaskInfo.PROPERTY_VALUE_UNSET;
+    }
+
+    void setIsLayoutActive(boolean isLayoutActive) {
+        this.mIsLayoutActive = isLayoutActive;
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mMoveLeftButton = findViewById(R.id.reachability_move_left_button);
+        mMoveRightButton = findViewById(R.id.reachability_move_right_button);
+        mMoveUpButton = findViewById(R.id.reachability_move_up_button);
+        mMoveDownButton = findViewById(R.id.reachability_move_down_button);
+        mMoveLeftButton.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+        mMoveRightButton.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+        mMoveUpButton.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+        mMoveDownButton.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+    }
+
+    private Animator marginAnimator(View view, Function<LayoutParams, Integer> marginSupplier,
+            BiConsumer<LayoutParams, Integer> marginConsumer, int from, int to) {
+        final LayoutParams layoutParams = ((LayoutParams) view.getLayoutParams());
+        ValueAnimator animator = ValueAnimator.ofInt(marginSupplier.apply(layoutParams), from, to);
+        animator.addUpdateListener(valueAnimator -> {
+            marginConsumer.accept(layoutParams, (Integer) valueAnimator.getAnimatedValue());
+            view.requestLayout();
+        });
+        animator.setDuration(MARGINS_ANIMATION_DURATION_MS);
+        return animator;
+    }
+
+    private void handleLetterboxHorizontalPosition(int availableWidth,
+            int letterboxHorizontalPosition, boolean isDoubleTap) {
+        mMoveUpButton.hide();
+        mMoveDownButton.hide();
+        mLastTopMargin = TaskInfo.PROPERTY_VALUE_UNSET;
+        mLastBottomMargin = TaskInfo.PROPERTY_VALUE_UNSET;
+        // We calculate the available space on the left and right
+        final int horizontalGap = availableWidth / 2;
+        final int leftAvailableSpace = letterboxHorizontalPosition * horizontalGap;
+        final int rightAvailableSpace = availableWidth - leftAvailableSpace;
+        // We show the button if we have enough space
+        if (leftAvailableSpace >= mMoveLeftButton.getMeasuredWidth()) {
+            int newLeftMargin = (horizontalGap - mMoveLeftButton.getMeasuredWidth()) / 2;
+            if (mLastLeftMargin == TaskInfo.PROPERTY_VALUE_UNSET) {
+                mLastLeftMargin = newLeftMargin;
+            }
+            if (mLastLeftMargin != newLeftMargin) {
+                marginAnimator(mMoveLeftButton, layoutParams -> layoutParams.leftMargin,
+                        (layoutParams, margin) -> layoutParams.leftMargin = margin,
+                        mLastLeftMargin, newLeftMargin).start();
+            } else {
+                final LayoutParams leftParams = ((LayoutParams) mMoveLeftButton.getLayoutParams());
+                leftParams.leftMargin = mLastLeftMargin;
+                mMoveLeftButton.setLayoutParams(leftParams);
+            }
+            showItem(mMoveLeftButton, isDoubleTap);
+        } else {
+            mMoveLeftButton.hide();
+            mLastLeftMargin = TaskInfo.PROPERTY_VALUE_UNSET;
+        }
+        if (rightAvailableSpace >= mMoveRightButton.getMeasuredWidth()) {
+            int newRightMargin = (horizontalGap - mMoveRightButton.getMeasuredWidth()) / 2;
+            if (mLastRightMargin == TaskInfo.PROPERTY_VALUE_UNSET) {
+                mLastRightMargin = newRightMargin;
+            }
+            if (mLastRightMargin != newRightMargin) {
+                marginAnimator(mMoveRightButton, layoutParams -> layoutParams.rightMargin,
+                        (layoutParams, margin) -> layoutParams.rightMargin = margin,
+                        mLastRightMargin, newRightMargin).start();
+            } else {
+                final LayoutParams rightParams =
+                        ((LayoutParams) mMoveRightButton.getLayoutParams());
+                rightParams.rightMargin = mLastRightMargin;
+                mMoveRightButton.setLayoutParams(rightParams);
+            }
+            showItem(mMoveRightButton, isDoubleTap);
+        } else {
+            mMoveRightButton.hide();
+            mLastRightMargin = TaskInfo.PROPERTY_VALUE_UNSET;
+        }
+    }
+
+    private void handleLetterboxVerticalPosition(int availableHeight,
+            int letterboxVerticalPosition, boolean isDoubleTap) {
+        mMoveLeftButton.hide();
+        mMoveRightButton.hide();
+        mLastLeftMargin = TaskInfo.PROPERTY_VALUE_UNSET;
+        mLastRightMargin = TaskInfo.PROPERTY_VALUE_UNSET;
+        // We calculate the available space on the left and right
+        final int verticalGap = availableHeight / 2;
+        final int topAvailableSpace = letterboxVerticalPosition * verticalGap;
+        final int bottomAvailableSpace = availableHeight - topAvailableSpace;
+        if (topAvailableSpace >= mMoveUpButton.getMeasuredHeight()) {
+            int newTopMargin = (verticalGap - mMoveUpButton.getMeasuredHeight()) / 2;
+            if (mLastTopMargin == TaskInfo.PROPERTY_VALUE_UNSET) {
+                mLastTopMargin = newTopMargin;
+            }
+            if (mLastTopMargin != newTopMargin) {
+                marginAnimator(mMoveUpButton, layoutParams -> layoutParams.topMargin,
+                        (layoutParams, margin) -> layoutParams.topMargin = margin,
+                        mLastTopMargin, newTopMargin).start();
+            } else {
+                final LayoutParams topParams = ((LayoutParams) mMoveUpButton.getLayoutParams());
+                topParams.topMargin = mLastTopMargin;
+                mMoveUpButton.setLayoutParams(topParams);
+            }
+            showItem(mMoveUpButton, isDoubleTap);
+        } else {
+            mMoveUpButton.hide();
+            mLastTopMargin = TaskInfo.PROPERTY_VALUE_UNSET;
+        }
+        if (bottomAvailableSpace >= mMoveDownButton.getMeasuredHeight()) {
+            int newBottomMargin = (verticalGap - mMoveDownButton.getMeasuredHeight()) / 2;
+            if (mLastBottomMargin == TaskInfo.PROPERTY_VALUE_UNSET) {
+                mLastBottomMargin = newBottomMargin;
+            }
+            if (mLastBottomMargin != newBottomMargin) {
+                marginAnimator(mMoveDownButton, layoutParams -> layoutParams.bottomMargin,
+                        (layoutParams, margin) -> layoutParams.bottomMargin = margin,
+                        mLastBottomMargin, newBottomMargin).start();
+            } else {
+                final LayoutParams bottomParams =
+                        ((LayoutParams) mMoveDownButton.getLayoutParams());
+                bottomParams.bottomMargin = mLastBottomMargin;
+                mMoveDownButton.setLayoutParams(bottomParams);
+            }
+            showItem(mMoveDownButton, isDoubleTap);
+        } else {
+            mMoveDownButton.hide();
+            mLastBottomMargin = TaskInfo.PROPERTY_VALUE_UNSET;
+        }
+    }
+
+    private void showItem(ReachabilityEduHandLayout view, boolean fromDoubleTap) {
+        if (view.getVisibility() == View.VISIBLE) {
+            // Already visible we just start animation
+            view.startAnimation();
+            return;
+        }
+        view.setVisibility(View.VISIBLE);
+        final long delay = fromDoubleTap ? VISIBILITY_SHOW_DOUBLE_TAP_ANIMATION_DELAY_MS
+                : VISIBILITY_SHOW_ANIMATION_DELAY_MS;
+        AlphaAnimation alphaAnimation = new AlphaAnimation(ALPHA_FULL_TRANSPARENT,
+                ALPHA_FULL_OPAQUE);
+        alphaAnimation.setDuration(VISIBILITY_SHOW_ANIMATION_DURATION_MS);
+        alphaAnimation.setStartOffset(delay);
+        alphaAnimation.setFillAfter(true);
+        alphaAnimation.setAnimationListener(new Animation.AnimationListener() {
+            @Override
+            public void onAnimationStart(Animation animation) {
+            }
+
+            @Override
+            public void onAnimationEnd(Animation animation) {
+                // We trigger the hand animation
+                view.setAlpha(ALPHA_FULL_OPAQUE);
+                view.startAnimation();
+            }
+
+            @Override
+            public void onAnimationRepeat(Animation animation) {
+            }
+        });
+        view.startAnimation(alphaAnimation);
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/ReachabilityEduWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/ReachabilityEduWindowManager.java
new file mode 100644
index 0000000..6223efa
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/ReachabilityEduWindowManager.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.compatui;
+
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.TaskInfo;
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.SystemClock;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.wm.shell.R;
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.compatui.CompatUIController.CompatUICallback;
+
+/**
+ * Window manager for the reachability education
+ */
+class ReachabilityEduWindowManager extends CompatUIWindowManagerAbstract {
+
+    /**
+     * The Compat UI should be below the Letterbox Education.
+     */
+    private static final int Z_ORDER = LetterboxEduWindowManager.Z_ORDER - 1;
+
+    // The time to wait before hiding the education
+    private static final long DISAPPEAR_DELAY_MS = 4000L;
+
+    private final CompatUICallback mCallback;
+
+    private final CompatUIConfiguration mCompatUIConfiguration;
+
+    private final ShellExecutor mMainExecutor;
+
+    @NonNull
+    private TaskInfo mTaskInfo;
+
+    private boolean mIsActivityLetterboxed;
+
+    private int mLetterboxVerticalPosition;
+
+    private int mLetterboxHorizontalPosition;
+
+    private int mTopActivityLetterboxWidth;
+
+    private int mTopActivityLetterboxHeight;
+
+    private long mNextHideTime = -1L;
+
+    private boolean mForceUpdate = false;
+
+    // We decided to force the visualization of the double-tap animated icons every time the user
+    // double-taps. We detect a double-tap checking the previous and current state of
+    // mLetterboxVerticalPosition and mLetterboxHorizontalPosition saving the result in this
+    // variable.
+    private boolean mHasUserDoubleTapped;
+
+    // When the size of the letterboxed app changes and the icons are visible
+    // we need to animate them.
+    private boolean mHasLetterboxSizeChanged;
+
+    @Nullable
+    @VisibleForTesting
+    ReachabilityEduLayout mLayout;
+
+    ReachabilityEduWindowManager(Context context, TaskInfo taskInfo,
+            SyncTransactionQueue syncQueue, CompatUICallback callback,
+            ShellTaskOrganizer.TaskListener taskListener, DisplayLayout displayLayout,
+            CompatUIConfiguration compatUIConfiguration, ShellExecutor mainExecutor) {
+        super(context, taskInfo, syncQueue, taskListener, displayLayout);
+        mCallback = callback;
+        mTaskInfo = taskInfo;
+        mIsActivityLetterboxed = taskInfo.isLetterboxDoubleTapEnabled;
+        mLetterboxVerticalPosition = taskInfo.topActivityLetterboxVerticalPosition;
+        mLetterboxHorizontalPosition = taskInfo.topActivityLetterboxHorizontalPosition;
+        mTopActivityLetterboxWidth = taskInfo.topActivityLetterboxWidth;
+        mTopActivityLetterboxHeight = taskInfo.topActivityLetterboxHeight;
+        mCompatUIConfiguration = compatUIConfiguration;
+        mMainExecutor = mainExecutor;
+    }
+
+    @Override
+    protected int getZOrder() {
+        return Z_ORDER;
+    }
+
+    @Override
+    protected @Nullable View getLayout() {
+        return mLayout;
+    }
+
+    @Override
+    protected void removeLayout() {
+        mLayout = null;
+    }
+
+    @Override
+    protected boolean eligibleToShowLayout() {
+        return mCompatUIConfiguration.isReachabilityEducationEnabled()
+                && mIsActivityLetterboxed
+                && (mLetterboxVerticalPosition != -1 || mLetterboxHorizontalPosition != -1);
+    }
+
+    @Override
+    protected View createLayout() {
+        mLayout = inflateLayout();
+        mLayout.inject(this);
+
+        updateVisibilityOfViews();
+
+        return mLayout;
+    }
+
+    @VisibleForTesting
+    ReachabilityEduLayout inflateLayout() {
+        return (ReachabilityEduLayout) LayoutInflater.from(mContext).inflate(
+                R.layout.reachability_ui_layout, null);
+    }
+
+    @Override
+    public boolean updateCompatInfo(TaskInfo taskInfo, ShellTaskOrganizer.TaskListener taskListener,
+            boolean canShow) {
+        mTaskInfo = taskInfo;
+        final boolean prevIsActivityLetterboxed = mIsActivityLetterboxed;
+        final int prevLetterboxVerticalPosition = mLetterboxVerticalPosition;
+        final int prevLetterboxHorizontalPosition = mLetterboxHorizontalPosition;
+        final int prevTopActivityLetterboxWidth = mTopActivityLetterboxWidth;
+        final int prevTopActivityLetterboxHeight = mTopActivityLetterboxHeight;
+        mIsActivityLetterboxed = taskInfo.isLetterboxDoubleTapEnabled;
+        mLetterboxVerticalPosition = taskInfo.topActivityLetterboxVerticalPosition;
+        mLetterboxHorizontalPosition = taskInfo.topActivityLetterboxHorizontalPosition;
+        mTopActivityLetterboxWidth = taskInfo.topActivityLetterboxWidth;
+        mTopActivityLetterboxHeight = taskInfo.topActivityLetterboxHeight;
+
+        mHasUserDoubleTapped =
+                mLetterboxVerticalPosition != prevLetterboxVerticalPosition
+                        || prevLetterboxHorizontalPosition != mLetterboxHorizontalPosition;
+        if (mHasUserDoubleTapped) {
+            // In this case we disable the reachability for the following launch of
+            // the current application. Anyway because a double tap event happened,
+            // the reachability education is displayed
+            mCompatUIConfiguration.setDontShowReachabilityEducationAgain(taskInfo);
+        }
+        if (!super.updateCompatInfo(taskInfo, taskListener, canShow)) {
+            return false;
+        }
+
+        mHasLetterboxSizeChanged = prevTopActivityLetterboxWidth != mTopActivityLetterboxWidth
+                || prevTopActivityLetterboxHeight != mTopActivityLetterboxHeight;
+
+        if (mForceUpdate || prevIsActivityLetterboxed != mIsActivityLetterboxed
+                || prevLetterboxVerticalPosition != mLetterboxVerticalPosition
+                || prevLetterboxHorizontalPosition != mLetterboxHorizontalPosition
+                || prevTopActivityLetterboxWidth != mTopActivityLetterboxWidth
+                || prevTopActivityLetterboxHeight != mTopActivityLetterboxHeight) {
+            updateVisibilityOfViews();
+            mForceUpdate = false;
+        }
+
+        return true;
+    }
+
+    void forceUpdate(boolean forceUpdate) {
+        mForceUpdate = forceUpdate;
+    }
+
+    @Override
+    protected void onParentBoundsChanged() {
+        if (mLayout == null) {
+            return;
+        }
+        // Both the layout dimensions and dialog margins depend on the parent bounds.
+        WindowManager.LayoutParams windowLayoutParams = getWindowLayoutParams();
+        mLayout.setLayoutParams(windowLayoutParams);
+        relayout(windowLayoutParams);
+    }
+
+    /** Gets the layout params. */
+    protected WindowManager.LayoutParams getWindowLayoutParams() {
+        View layout = getLayout();
+        if (layout == null) {
+            return new WindowManager.LayoutParams();
+        }
+        // Measure how big the hint is since its size depends on the text size.
+        final Rect taskBounds = getTaskBounds();
+        layout.measure(View.MeasureSpec.makeMeasureSpec(taskBounds.width(),
+                        View.MeasureSpec.EXACTLY),
+                View.MeasureSpec.makeMeasureSpec(taskBounds.height(),
+                        View.MeasureSpec.EXACTLY));
+        return getWindowLayoutParams(layout.getMeasuredWidth(), layout.getMeasuredHeight());
+    }
+
+    /**
+     * @return Flags to use for the WindowManager layout
+     */
+    @Override
+    protected int getWindowManagerLayoutParamsFlags() {
+        return FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCHABLE;
+    }
+
+    @Override
+    @VisibleForTesting
+    public void updateSurfacePosition() {
+        if (mLayout == null) {
+            return;
+        }
+        updateSurfacePosition(0, 0);
+    }
+
+    void updateHideTime() {
+        mNextHideTime = SystemClock.uptimeMillis() + DISAPPEAR_DELAY_MS;
+    }
+
+    private void updateVisibilityOfViews() {
+        if (mLayout == null) {
+            return;
+        }
+        if (shouldUpdateEducation()) {
+            if (!mHasLetterboxSizeChanged) {
+                mLayout.setIsLayoutActive(true);
+            }
+            int availableWidth = getTaskBounds().width() - mTopActivityLetterboxWidth;
+            int availableHeight = getTaskBounds().height() - mTopActivityLetterboxHeight;
+            mLayout.handleVisibility(mIsActivityLetterboxed, mLetterboxVerticalPosition,
+                    mLetterboxHorizontalPosition, availableWidth, availableHeight,
+                    mHasUserDoubleTapped);
+            if (!mHasLetterboxSizeChanged) {
+                updateHideTime();
+                mMainExecutor.executeDelayed(this::hideReachability, DISAPPEAR_DELAY_MS);
+            }
+            mHasUserDoubleTapped = false;
+        } else {
+            hideReachability();
+        }
+    }
+
+    private void hideReachability() {
+        if (mLayout != null) {
+            mLayout.setIsLayoutActive(false);
+        }
+        if (mLayout == null || !shouldHideEducation()) {
+            return;
+        }
+        mLayout.hideAllImmediately();
+        // We need this in case the icons disappear after the timeout without an explicit
+        // double tap of the user.
+        mCompatUIConfiguration.setDontShowReachabilityEducationAgain(mTaskInfo);
+    }
+
+    private boolean shouldUpdateEducation() {
+        return mForceUpdate || mHasUserDoubleTapped || mHasLetterboxSizeChanged
+                || mCompatUIConfiguration.shouldShowReachabilityEducation(mTaskInfo);
+    }
+
+    private boolean shouldHideEducation() {
+        return SystemClock.uptimeMillis() >= mNextHideTime;
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/RestartDialogWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/RestartDialogWindowManager.java
index 2440838..aab123a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/RestartDialogWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/RestartDialogWindowManager.java
@@ -130,7 +130,7 @@
     protected boolean eligibleToShowLayout() {
         // We don't show this dialog if the user has explicitly selected so clicking on a checkbox.
         return mRequestRestartDialog && !isTaskbarEduShowing() && (mLayout != null
-                || !mCompatUIConfiguration.getDontShowRestartDialogAgain(mTaskInfo));
+                || mCompatUIConfiguration.shouldShowRestartDialogAgain(mTaskInfo));
     }
 
     @Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 72dc771..ef21c7e9 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
@@ -51,6 +51,7 @@
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.SystemWindows;
+import com.android.wm.shell.common.TabletopModeController;
 import com.android.wm.shell.common.TaskStackListenerImpl;
 import com.android.wm.shell.common.TransactionPool;
 import com.android.wm.shell.common.annotations.ShellAnimationThread;
@@ -171,6 +172,18 @@
 
     @WMSingleton
     @Provides
+    static TabletopModeController provideTabletopModeController(
+            Context context,
+            ShellInit shellInit,
+            DevicePostureController postureController,
+            DisplayController displayController,
+            @ShellMainThread ShellExecutor mainExecutor) {
+        return new TabletopModeController(
+                context, shellInit, postureController, displayController, mainExecutor);
+    }
+
+    @WMSingleton
+    @Provides
     static DragAndDropController provideDragAndDropController(Context context,
             ShellInit shellInit,
             ShellController shellController,
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 4578523..8f1e074 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
@@ -44,6 +44,7 @@
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.SystemWindows;
+import com.android.wm.shell.common.TabletopModeController;
 import com.android.wm.shell.common.TaskStackListenerImpl;
 import com.android.wm.shell.common.TransactionPool;
 import com.android.wm.shell.common.annotations.ShellBackgroundThread;
@@ -353,6 +354,7 @@
             TaskStackListenerImpl taskStackListener,
             PipParamsChangedForwarder pipParamsChangedForwarder,
             DisplayInsetsController displayInsetsController,
+            TabletopModeController pipTabletopController,
             Optional<OneHandedController> oneHandedController,
             @ShellMainThread ShellExecutor mainExecutor) {
         return Optional.ofNullable(PipController.create(
@@ -362,7 +364,7 @@
                 pipMediaController, phonePipMenuController, pipTaskOrganizer, pipTransitionState,
                 pipTouchHandler, pipTransitionController, windowManagerShellWrapper,
                 taskStackListener, pipParamsChangedForwarder, displayInsetsController,
-                oneHandedController, mainExecutor));
+                pipTabletopController, oneHandedController, mainExecutor));
     }
 
     @WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 73a7403..31c5e33 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -25,6 +25,7 @@
 import android.app.WindowConfiguration.WindowingMode
 import android.content.Context
 import android.os.IBinder
+import android.os.SystemProperties
 import android.view.SurfaceControl
 import android.view.WindowManager.TRANSIT_CHANGE
 import android.view.WindowManager.TRANSIT_NONE
@@ -32,6 +33,7 @@
 import android.view.WindowManager.TRANSIT_TO_FRONT
 import android.window.TransitionInfo
 import android.window.TransitionRequestInfo
+import android.window.WindowContainerToken
 import android.window.WindowContainerTransaction
 import androidx.annotation.BinderThread
 import com.android.internal.protolog.common.ProtoLog
@@ -115,10 +117,7 @@
         val wct = WindowContainerTransaction()
         // Bring other apps to front first
         bringDesktopAppsToFront(wct)
-
-        wct.setWindowingMode(task.getToken(), WINDOWING_MODE_FREEFORM)
-        wct.reorder(task.getToken(), true /* onTop */)
-
+        addMoveToDesktopChanges(wct, task.token)
         if (Transitions.ENABLE_SHELL_TRANSITIONS) {
             transitions.startTransition(TRANSIT_CHANGE, wct, null /* handler */)
         } else {
@@ -136,8 +135,7 @@
         ProtoLog.v(WM_SHELL_DESKTOP_MODE, "moveToFullscreen: %d", task.taskId)
 
         val wct = WindowContainerTransaction()
-        wct.setWindowingMode(task.getToken(), WINDOWING_MODE_FULLSCREEN)
-        wct.setBounds(task.getToken(), null)
+        addMoveToFullscreenChanges(wct, task.token)
         if (Transitions.ENABLE_SHELL_TRANSITIONS) {
             transitions.startTransition(TRANSIT_CHANGE, wct, null /* handler */)
         } else {
@@ -234,8 +232,8 @@
                         " taskId=%d",
                     task.taskId
                 )
-                return WindowContainerTransaction().apply {
-                    setWindowingMode(task.token, WINDOWING_MODE_FREEFORM)
+                return WindowContainerTransaction().also { wct ->
+                    addMoveToDesktopChanges(wct, task.token)
                 }
             }
         }
@@ -251,15 +249,44 @@
                         " taskId=%d",
                     task.taskId
                 )
-                return WindowContainerTransaction().apply {
-                    setWindowingMode(task.token, WINDOWING_MODE_FULLSCREEN)
-                    setBounds(task.token, null)
+                return WindowContainerTransaction().also { wct ->
+                    addMoveToFullscreenChanges(wct, task.token)
                 }
             }
         }
         return null
     }
 
+    private fun addMoveToDesktopChanges(
+        wct: WindowContainerTransaction,
+        token: WindowContainerToken
+    ) {
+        wct.setWindowingMode(token, WINDOWING_MODE_FREEFORM)
+        wct.reorder(token, true /* onTop */)
+        if (isDesktopDensityOverrideSet()) {
+            wct.setDensityDpi(token, getDesktopDensityDpi())
+        }
+    }
+
+    private fun addMoveToFullscreenChanges(
+        wct: WindowContainerTransaction,
+        token: WindowContainerToken
+    ) {
+        wct.setWindowingMode(token, WINDOWING_MODE_FULLSCREEN)
+        wct.setBounds(token, null)
+        if (isDesktopDensityOverrideSet()) {
+            wct.setDensityDpi(token, getFullscreenDensityDpi())
+        }
+    }
+
+    private fun getFullscreenDensityDpi(): Int {
+        return context.resources.displayMetrics.densityDpi
+    }
+
+    private fun getDesktopDensityDpi(): Int {
+        return DESKTOP_DENSITY_OVERRIDE
+    }
+
     /** Creates a new instance of the external interface to pass to another process. */
     private fun createExternalInterface(): ExternalInterfaceBinder {
         return IDesktopModeImpl(this)
@@ -318,4 +345,18 @@
             return result[0]
         }
     }
+
+    companion object {
+        private val DESKTOP_DENSITY_OVERRIDE =
+            SystemProperties.getInt("persist.wm.debug.desktop_mode_density", 0)
+        private val DESKTOP_DENSITY_ALLOWED_RANGE = (100..1000)
+
+        /**
+         * Check if desktop density override is enabled
+         */
+        @JvmStatic
+        fun isDesktopDensityOverrideSet(): Boolean {
+            return DESKTOP_DENSITY_OVERRIDE in DESKTOP_DENSITY_ALLOWED_RANGE
+        }
+    }
 }
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 ac13f96..0a5cc41 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
@@ -21,6 +21,8 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
 import static android.view.Display.DEFAULT_DISPLAY;
 
 import android.app.ActivityManager;
@@ -33,6 +35,7 @@
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
+import android.view.Display;
 import android.view.InsetsSource;
 import android.view.InsetsState;
 import android.view.SurfaceControl;
@@ -43,6 +46,7 @@
 
 import androidx.annotation.NonNull;
 
+import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.DisplayController;
@@ -80,6 +84,12 @@
     private final DisplayController mDisplayController;
     private final DisplayInsetsController mDisplayInsetsController;
 
+    /**
+     * The value of the {@link R.bool.config_reverseDefaultRotation} property which defines how
+     * {@link Display#getRotation} values are mapped to screen orientations
+     */
+    private final boolean mReverseDefaultRotationEnabled;
+
     @VisibleForTesting
     ActivityManager.RunningTaskInfo mLaunchRootTask;
     @VisibleForTesting
@@ -168,6 +178,8 @@
         mDisplayInsetsController = displayInsetsController;
         mKidsModeSettingsObserver = kidsModeSettingsObserver;
         shellInit.addInitCallback(this::onInit, this);
+        mReverseDefaultRotationEnabled = context.getResources().getBoolean(
+                R.bool.config_reverseDefaultRotation);
     }
 
     public KidsModeTaskOrganizer(
@@ -191,6 +203,8 @@
         mDisplayController = displayController;
         mDisplayInsetsController = displayInsetsController;
         shellInit.addInitCallback(this::onInit, this);
+        mReverseDefaultRotationEnabled = context.getResources().getBoolean(
+                R.bool.config_reverseDefaultRotation);
     }
 
     /**
@@ -247,6 +261,11 @@
             mLaunchRootTask = taskInfo;
         }
 
+        if (mHomeTask != null && mHomeTask.taskId == taskInfo.taskId
+                && !taskInfo.equals(mHomeTask)) {
+            mHomeTask = taskInfo;
+        }
+
         super.onTaskInfoChanged(taskInfo);
     }
 
@@ -269,7 +288,14 @@
         // Needed since many Kids apps aren't optimised to support both orientations and it will be
         // hard for kids to understand the app compat mode.
         // TODO(229961548): Remove ignoreOrientationRequest exception for Kids Mode once possible.
-        setIsIgnoreOrientationRequestDisabled(true);
+        if (mReverseDefaultRotationEnabled) {
+            setOrientationRequestPolicy(/* isIgnoreOrientationRequestDisabled */ true,
+                    /* fromOrientations */ new int[]{SCREEN_ORIENTATION_REVERSE_LANDSCAPE},
+                    /* toOrientations */ new int[]{SCREEN_ORIENTATION_LANDSCAPE});
+        } else {
+            setOrientationRequestPolicy(/* isIgnoreOrientationRequestDisabled */ true,
+                    /* fromOrientations */ null, /* toOrientations */ null);
+        }
         final DisplayLayout displayLayout = mDisplayController.getDisplayLayout(DEFAULT_DISPLAY);
         if (displayLayout != null) {
             mDisplayWidth = displayLayout.width();
@@ -290,7 +316,8 @@
 
     @VisibleForTesting
     void disable() {
-        setIsIgnoreOrientationRequestDisabled(false);
+        setOrientationRequestPolicy(/* isIgnoreOrientationRequestDisabled */ false,
+                /* fromOrientations */ null, /* toOrientations */ null);
         mDisplayInsetsController.removeInsetsChangedListener(DEFAULT_DISPLAY,
                 mOnInsetsChangedListener);
         mDisplayController.removeDisplayWindowListener(mOnDisplaysChangedListener);
@@ -364,6 +391,7 @@
         final WindowContainerTransaction wct = getWindowContainerTransaction();
         final Rect taskBounds = calculateBounds();
         wct.setBounds(mLaunchRootTask.token, taskBounds);
+        wct.setBounds(mHomeTask.token, new Rect(0, 0, mDisplayWidth, mDisplayHeight));
         mSyncQueue.queue(wct);
         final SurfaceControl finalLeash = mLaunchRootLeash;
         mSyncQueue.runInSync(t -> {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl
index 2624ee5..78de5f3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl
@@ -70,4 +70,14 @@
      * Sets the next pip animation type to be the alpha animation.
      */
     oneway void setPipAnimationTypeToAlpha() = 5;
+
+    /**
+     * Sets the height and visibility of the Launcher keep clear area.
+     */
+    oneway void setLauncherKeepClearAreaHeight(boolean visible, int height) = 6;
+
+    /**
+     * Sets the app icon size in pixel used by Launcher
+     */
+     oneway void setLauncherAppIconSize(int iconSizePx) = 7;
 }
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 23f73f6..1187126 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
@@ -36,6 +36,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
+import com.android.launcher3.icons.IconProvider;
 import com.android.wm.shell.animation.Interpolators;
 import com.android.wm.shell.transition.Transitions;
 
@@ -370,9 +371,11 @@
                     new PipContentOverlay.PipSnapshotOverlay(snapshot, sourceRectHint));
         }
 
-        void setAppIconContentOverlay(Context context, Rect bounds, ActivityInfo activityInfo) {
+        void setAppIconContentOverlay(Context context, Rect bounds, ActivityInfo activityInfo,
+                int appIconSizePx) {
             reattachContentOverlay(
-                    new PipContentOverlay.PipAppIconOverlay(context, bounds, activityInfo));
+                    new PipContentOverlay.PipAppIconOverlay(context, bounds,
+                            new IconProvider(context).getIcon(activityInfo), appIconSizePx));
         }
 
         private void reattachContentOverlay(PipContentOverlay overlay) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
index 5be18d8..92cf8cb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
@@ -44,7 +44,9 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 import java.util.function.Consumer;
@@ -84,6 +86,7 @@
     private int mStashedState = STASH_TYPE_NONE;
     private int mStashOffset;
     private @Nullable PipReentryState mPipReentryState;
+    private final LauncherState mLauncherState = new LauncherState();
     private final @Nullable PipSizeSpecHandler mPipSizeSpecHandler;
     private @Nullable ComponentName mLastPipComponentName;
     private int mDisplayId = Display.DEFAULT_DISPLAY;
@@ -115,6 +118,12 @@
      * @see android.view.View#setPreferKeepClearRects
      */
     private final Set<Rect> mUnrestrictedKeepClearAreas = new ArraySet<>();
+    /**
+     * Additional to {@link #mUnrestrictedKeepClearAreas}, allow the caller to append named bounds
+     * as unrestricted keep clear area. Values in this map would be appended to
+     * {@link #getUnrestrictedKeepClearAreas()} and this is meant for internal usage only.
+     */
+    private final Map<String, Rect> mNamedUnrestrictedKeepClearAreas = new HashMap<>();
 
     private @Nullable Runnable mOnMinimalSizeChangeCallback;
     private @Nullable TriConsumer<Boolean, Integer, Boolean> mOnShelfVisibilityChangeCallback;
@@ -393,6 +402,16 @@
         mUnrestrictedKeepClearAreas.addAll(unrestrictedAreas);
     }
 
+    /** Add a named unrestricted keep clear area. */
+    public void addNamedUnrestrictedKeepClearArea(@NonNull String name, Rect unrestrictedArea) {
+        mNamedUnrestrictedKeepClearAreas.put(name, unrestrictedArea);
+    }
+
+    /** Remove a named unrestricted keep clear area. */
+    public void removeNamedUnrestrictedKeepClearArea(@NonNull String name) {
+        mNamedUnrestrictedKeepClearAreas.remove(name);
+    }
+
     @NonNull
     public Set<Rect> getRestrictedKeepClearAreas() {
         return mRestrictedKeepClearAreas;
@@ -400,7 +419,10 @@
 
     @NonNull
     public Set<Rect> getUnrestrictedKeepClearAreas() {
-        return mUnrestrictedKeepClearAreas;
+        if (mNamedUnrestrictedKeepClearAreas.isEmpty()) return mUnrestrictedKeepClearAreas;
+        final Set<Rect> unrestrictedAreas = new ArraySet<>(mUnrestrictedKeepClearAreas);
+        unrestrictedAreas.addAll(mNamedUnrestrictedKeepClearAreas.values());
+        return unrestrictedAreas;
     }
 
     /**
@@ -476,6 +498,10 @@
         mOnPipExclusionBoundsChangeCallbacks.remove(onPipExclusionBoundsChangeCallback);
     }
 
+    public LauncherState getLauncherState() {
+        return mLauncherState;
+    }
+
     /** Source of truth for the current bounds of PIP that may be in motion. */
     public static class MotionBoundsState {
         /** The bounds used when PIP is in motion (e.g. during a drag or animation) */
@@ -528,6 +554,25 @@
         }
     }
 
+    /** Data class for Launcher state. */
+    public static final class LauncherState {
+        private int mAppIconSizePx;
+
+        public void setAppIconSizePx(int appIconSizePx) {
+            mAppIconSizePx = appIconSizePx;
+        }
+
+        public int getAppIconSizePx() {
+            return mAppIconSizePx;
+        }
+
+        void dump(PrintWriter pw, String prefix) {
+            final String innerPrefix = prefix + "    ";
+            pw.println(prefix + LauncherState.class.getSimpleName());
+            pw.println(innerPrefix + "getAppIconSizePx=" + getAppIconSizePx());
+        }
+    }
+
     static final class PipReentryState {
         private static final String TAG = PipReentryState.class.getSimpleName();
 
@@ -582,6 +627,7 @@
         } else {
             mPipReentryState.dump(pw, innerPrefix);
         }
+        mLauncherState.dump(pw, innerPrefix);
         mMotionBoundsState.dump(pw, innerPrefix);
     }
 }
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 480bf93..9fa57ca 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
@@ -20,9 +20,6 @@
 
 import android.annotation.Nullable;
 import android.content.Context;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
@@ -39,6 +36,9 @@
  * Represents the content overlay used during the entering PiP animation.
  */
 public abstract class PipContentOverlay {
+    // Fixed string used in WMShellFlickerTests
+    protected static final String LAYER_NAME = "PipContentOverlay";
+
     protected SurfaceControl mLeash;
 
     /** Attaches the internal {@link #mLeash} to the given parent leash. */
@@ -86,7 +86,7 @@
             mContext = context;
             mLeash = new SurfaceControl.Builder(new SurfaceSession())
                     .setCallsite(TAG)
-                    .setName(TAG)
+                    .setName(LAYER_NAME)
                     .setColorLayer()
                     .build();
         }
@@ -139,7 +139,7 @@
             mSourceRectHint = new Rect(sourceRectHint);
             mLeash = new SurfaceControl.Builder(new SurfaceSession())
                     .setCallsite(TAG)
-                    .setName(TAG)
+                    .setName(LAYER_NAME)
                     .build();
         }
 
@@ -174,7 +174,8 @@
     /** A {@link PipContentOverlay} shows app icon on solid color background. */
     public static final class PipAppIconOverlay extends PipContentOverlay {
         private static final String TAG = PipAppIconOverlay.class.getSimpleName();
-        private static final int APP_ICON_SIZE_DP = 48;
+        // The maximum size for app icon in pixel.
+        private static final int MAX_APP_ICON_SIZE_DP = 72;
 
         private final Context mContext;
         private final int mAppIconSizePx;
@@ -184,17 +185,19 @@
 
         private Bitmap mBitmap;
 
-        public PipAppIconOverlay(Context context, Rect appBounds, ActivityInfo activityInfo) {
+        public PipAppIconOverlay(Context context, Rect appBounds,
+                Drawable appIcon, int appIconSizePx) {
             mContext = context;
-            mAppIconSizePx = (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, APP_ICON_SIZE_DP,
-                    context.getResources().getDisplayMetrics());
+            final int maxAppIconSizePx = (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP,
+                    MAX_APP_ICON_SIZE_DP, context.getResources().getDisplayMetrics());
+            mAppIconSizePx = Math.min(maxAppIconSizePx, appIconSizePx);
             mAppBounds = new Rect(appBounds);
             mBitmap = Bitmap.createBitmap(appBounds.width(), appBounds.height(),
                     Bitmap.Config.ARGB_8888);
-            prepareAppIconOverlay(activityInfo);
+            prepareAppIconOverlay(appIcon);
             mLeash = new SurfaceControl.Builder(new SurfaceSession())
                     .setCallsite(TAG)
-                    .setName(TAG)
+                    .setName(LAYER_NAME)
                     .build();
         }
 
@@ -234,7 +237,7 @@
             }
         }
 
-        private void prepareAppIconOverlay(ActivityInfo activityInfo) {
+        private void prepareAppIconOverlay(Drawable appIcon) {
             final Canvas canvas = new Canvas();
             canvas.setBitmap(mBitmap);
             final TypedArray ta = mContext.obtainStyledAttributes(new int[] {
@@ -248,8 +251,6 @@
             } finally {
                 ta.recycle();
             }
-            final Drawable appIcon = loadActivityInfoIcon(activityInfo,
-                    mContext.getResources().getConfiguration().densityDpi);
             final Rect appIconBounds = new Rect(
                     mAppBounds.centerX() - mAppIconSizePx / 2,
                     mAppBounds.centerY() - mAppIconSizePx / 2,
@@ -259,24 +260,5 @@
             appIcon.draw(canvas);
             mBitmap = mBitmap.copy(Bitmap.Config.HARDWARE, false /* mutable */);
         }
-
-        // Copied from com.android.launcher3.icons.IconProvider#loadActivityInfoIcon
-        private Drawable loadActivityInfoIcon(ActivityInfo ai, int density) {
-            final int iconRes = ai.getIconResource();
-            Drawable icon = null;
-            // Get the preferred density icon from the app's resources
-            if (density != 0 && iconRes != 0) {
-                try {
-                    final Resources resources = mContext.getPackageManager()
-                            .getResourcesForApplication(ai.applicationInfo);
-                    icon = resources.getDrawableForDensity(iconRes, density);
-                } catch (PackageManager.NameNotFoundException | Resources.NotFoundException exc) { }
-            }
-            // Get the default density icon
-            if (icon == null) {
-                icon = ai.loadIcon(mContext.getPackageManager());
-            }
-            return icon;
-        }
     }
 }
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 f11836e..1dd2ef9 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
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.pip;
 
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -538,6 +539,15 @@
             mPipTransitionController.startExitTransition(TRANSIT_EXIT_PIP, wct, destinationBounds);
             return;
         }
+        if (mSplitScreenOptional.isPresent()) {
+            // If pip activity will reparent to origin task case and if the origin task still under
+            // split root, just exit split screen here to ensure it could expand to fullscreen.
+            SplitScreenController split = mSplitScreenOptional.get();
+            if (split.isTaskInSplitScreen(mTaskInfo.lastParentTaskIdBeforePip)) {
+                split.exitSplitScreen(INVALID_TASK_ID,
+                        SplitScreenController.EXIT_REASON_APP_FINISHED);
+            }
+        }
         mSyncTransactionQueue.queue(wct);
         mSyncTransactionQueue.runInSync(t -> {
             // Make sure to grab the latest source hint rect as it could have been
@@ -1179,6 +1189,20 @@
     }
 
     /**
+     * Directly update the animator bounds.
+     */
+    public void updateAnimatorBounds(Rect bounds) {
+        final PipAnimationController.PipTransitionAnimator animator =
+                mPipAnimationController.getCurrentAnimator();
+        if (animator != null && animator.isRunning()) {
+            if (animator.getAnimationType() == ANIM_TYPE_BOUNDS) {
+                animator.updateEndValue(bounds);
+            }
+            animator.setDestinationBounds(bounds);
+        }
+    }
+
+    /**
      * Handles all changes to the PictureInPictureParams.
      */
     protected void applyNewPictureInPictureParams(@NonNull PictureInPictureParams params) {
@@ -1467,9 +1491,13 @@
                 applyFinishBoundsResize(wct, direction, false);
             }
         } else {
-            final boolean isPipTopLeft =
-                    direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN && isPipToTopLeft();
-            applyFinishBoundsResize(wct, direction, isPipTopLeft);
+            applyFinishBoundsResize(wct, direction, isPipToTopLeft());
+            // Use sync transaction to apply finish transaction for enter split case.
+            if (direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN) {
+                mSyncTransactionQueue.runInSync(t -> {
+                    t.merge(tx);
+                });
+            }
         }
 
         finishResizeForMenu(destinationBounds);
@@ -1506,7 +1534,10 @@
         mSurfaceTransactionHelper.round(tx, mLeash, isInPip());
 
         wct.setBounds(mToken, taskBounds);
-        wct.setBoundsChangeTransaction(mToken, tx);
+        // Pip to split should use sync transaction to sync split bounds change.
+        if (direction != TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN) {
+            wct.setBoundsChangeTransaction(mToken, tx);
+        }
     }
 
     /**
@@ -1594,9 +1625,10 @@
             // source rect hint to enter PiP use bounds animation.
             if (sourceHintRect == null) {
                 if (SystemProperties.getBoolean(
-                        "persist.wm.debug.enable_pip_app_icon_overlay", false)) {
+                        "persist.wm.debug.enable_pip_app_icon_overlay", true)) {
                     animator.setAppIconContentOverlay(
-                            mContext, currentBounds, mTaskInfo.topActivityInfo);
+                            mContext, currentBounds, mTaskInfo.topActivityInfo,
+                            mPipBoundsState.getLauncherState().getAppIconSizePx());
                 } else {
                     animator.setColorContentOverlay(mContext);
                 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index e5c0570..8e7b30e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -803,10 +803,18 @@
             if (sourceHintRect == null) {
                 // We use content overlay when there is no source rect hint to enter PiP use bounds
                 // animation.
+                // TODO(b/272819817): cleanup the null-check and extra logging.
+                final boolean hasTopActivityInfo = taskInfo.topActivityInfo != null;
+                if (!hasTopActivityInfo) {
+                    ProtoLog.w(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
+                            "%s: TaskInfo.topActivityInfo is null", TAG);
+                }
                 if (SystemProperties.getBoolean(
-                        "persist.wm.debug.enable_pip_app_icon_overlay", false)) {
+                        "persist.wm.debug.enable_pip_app_icon_overlay", true)
+                        && hasTopActivityInfo) {
                     animator.setAppIconContentOverlay(
-                            mContext, currentBounds, taskInfo.topActivityInfo);
+                            mContext, currentBounds, taskInfo.topActivityInfo,
+                            mPipBoundsState.getLauncherState().getAppIconSizePx());
                 } else {
                     animator.setColorContentOverlay(mContext);
                 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java
index c6b5ce9..db6138a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java
@@ -93,6 +93,11 @@
         return hasEnteredPip(mState);
     }
 
+    /** Returns true if activity is currently entering PiP mode. */
+    public boolean isEnteringPip() {
+        return isEnteringPip(mState);
+    }
+
     public void setInSwipePipToHomeTransition(boolean inSwipePipToHomeTransition) {
         mInSwipePipToHomeTransition = inSwipePipToHomeTransition;
     }
@@ -130,6 +135,11 @@
         return state == ENTERED_PIP;
     }
 
+    /** Returns true if activity is currently entering PiP mode. */
+    public static boolean isEnteringPip(@TransitionState int state) {
+        return state == ENTERING_PIP;
+    }
+
     public interface OnPipTransitionStateChangedListener {
         void onPipTransitionStateChanged(@TransitionState int oldState,
                 @TransitionState int newState);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index fa3efeb..9807320 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -43,6 +43,7 @@
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.RemoteException;
 import android.os.SystemProperties;
@@ -71,6 +72,7 @@
 import com.android.wm.shell.common.RemoteCallable;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SingleInstanceRemoteListener;
+import com.android.wm.shell.common.TabletopModeController;
 import com.android.wm.shell.common.TaskStackListenerCallback;
 import com.android.wm.shell.common.TaskStackListenerImpl;
 import com.android.wm.shell.onehanded.OneHandedController;
@@ -115,11 +117,13 @@
         UserChangeListener {
     private static final String TAG = "PipController";
 
+    private static final String LAUNCHER_KEEP_CLEAR_AREA_TAG = "hotseat";
+
     private static final long PIP_KEEP_CLEAR_AREAS_DELAY =
             SystemProperties.getLong("persist.wm.debug.pip_keep_clear_areas_delay", 200);
 
     private boolean mEnablePipKeepClearAlgorithm =
-            SystemProperties.getBoolean("persist.wm.debug.enable_pip_keep_clear_algorithm", false);
+            SystemProperties.getBoolean("persist.wm.debug.enable_pip_keep_clear_algorithm", true);
 
     @VisibleForTesting
     void setEnablePipKeepClearAlgorithm(boolean value) {
@@ -144,6 +148,7 @@
     private TaskStackListenerImpl mTaskStackListener;
     private PipParamsChangedForwarder mPipParamsChangedForwarder;
     private DisplayInsetsController mDisplayInsetsController;
+    private TabletopModeController mTabletopModeController;
     private Optional<OneHandedController> mOneHandedController;
     private final ShellCommandHandler mShellCommandHandler;
     private final ShellController mShellController;
@@ -156,6 +161,10 @@
             this::onKeepClearAreasChangedCallback;
 
     private void onKeepClearAreasChangedCallback() {
+        if (mIsKeyguardShowingOrAnimating) {
+            // early bail out if the change was caused by keyguard showing up
+            return;
+        }
         if (!mEnablePipKeepClearAlgorithm) {
             // early bail out if the keep clear areas feature is disabled
             return;
@@ -181,14 +190,24 @@
             // early bail out if the keep clear areas feature is disabled
             return;
         }
-        // only move if already in pip, other transitions account for keep clear areas
-        if (mPipTransitionState.hasEnteredPip()) {
+        if (mIsKeyguardShowingOrAnimating) {
+            // early bail out if the change was caused by keyguard showing up
+            return;
+        }
+        // only move if we're in PiP or transitioning into PiP
+        if (!mPipTransitionState.shouldBlockResizeRequest()) {
             Rect destBounds = mPipKeepClearAlgorithm.adjust(mPipBoundsState,
                     mPipBoundsAlgorithm);
             // only move if the bounds are actually different
-            if (destBounds != mPipBoundsState.getBounds()) {
-                mPipTaskOrganizer.scheduleAnimateResizePip(destBounds,
-                        mEnterAnimationDuration, null);
+            if (!destBounds.equals(mPipBoundsState.getBounds())) {
+                if (mPipTransitionState.hasEnteredPip()) {
+                    // if already in PiP, schedule separate animation
+                    mPipTaskOrganizer.scheduleAnimateResizePip(destBounds,
+                            mEnterAnimationDuration, null);
+                } else if (mPipTransitionState.isEnteringPip()) {
+                    // while entering PiP we just need to update animator bounds
+                    mPipTaskOrganizer.updateAnimatorBounds(destBounds);
+                }
             }
         }
     }
@@ -393,6 +412,7 @@
             TaskStackListenerImpl taskStackListener,
             PipParamsChangedForwarder pipParamsChangedForwarder,
             DisplayInsetsController displayInsetsController,
+            TabletopModeController pipTabletopController,
             Optional<OneHandedController> oneHandedController,
             ShellExecutor mainExecutor) {
         if (!context.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) {
@@ -407,7 +427,7 @@
                 pipMotionHelper, pipMediaController, phonePipMenuController, pipTaskOrganizer,
                 pipTransitionState, pipTouchHandler, pipTransitionController,
                 windowManagerShellWrapper, taskStackListener, pipParamsChangedForwarder,
-                displayInsetsController, oneHandedController, mainExecutor)
+                displayInsetsController, pipTabletopController, oneHandedController, mainExecutor)
                 .mImpl;
     }
 
@@ -433,6 +453,7 @@
             TaskStackListenerImpl taskStackListener,
             PipParamsChangedForwarder pipParamsChangedForwarder,
             DisplayInsetsController displayInsetsController,
+            TabletopModeController tabletopModeController,
             Optional<OneHandedController> oneHandedController,
             ShellExecutor mainExecutor
     ) {
@@ -465,6 +486,7 @@
                 .getInteger(R.integer.config_pipEnterAnimationDuration);
         mPipParamsChangedForwarder = pipParamsChangedForwarder;
         mDisplayInsetsController = displayInsetsController;
+        mTabletopModeController = tabletopModeController;
 
         shellInit.addInitCallback(this::onInit, this);
     }
@@ -621,9 +643,11 @@
                         DisplayLayout pendingLayout =
                                 mDisplayController.getDisplayLayout(mPipBoundsState.getDisplayId());
                         if (mIsInFixedRotation
+                                || mIsKeyguardShowingOrAnimating
                                 || pendingLayout.rotation()
                                 != mPipBoundsState.getDisplayLayout().rotation()) {
-                            // bail out if there is a pending rotation or fixed rotation change
+                            // bail out if there is a pending rotation or fixed rotation change or
+                            // there's a keyguard present
                             return;
                         }
                         int oldMaxMovementBound = mPipBoundsState.getMovementBounds().bottom;
@@ -648,6 +672,42 @@
                     }
                 });
 
+        mTabletopModeController.registerOnTabletopModeChangedListener((isInTabletopMode) -> {
+            if (!mTabletopModeController.enableMoveFloatingWindowInTabletop()) return;
+            final String tag = "tabletop-mode";
+            if (!isInTabletopMode) {
+                mPipBoundsState.removeNamedUnrestrictedKeepClearArea(tag);
+                return;
+            }
+
+            // To prepare for the entry bounds.
+            final Rect displayBounds = mPipBoundsState.getDisplayBounds();
+            if (mTabletopModeController.getPreferredHalfInTabletopMode()
+                    == TabletopModeController.PREFERRED_TABLETOP_HALF_TOP) {
+                // Prefer top, avoid the bottom half of the display.
+                mPipBoundsState.addNamedUnrestrictedKeepClearArea(tag, new Rect(
+                        displayBounds.left, displayBounds.centerY(),
+                        displayBounds.right, displayBounds.bottom));
+            } else {
+                // Prefer bottom, avoid the top half of the display.
+                mPipBoundsState.addNamedUnrestrictedKeepClearArea(tag, new Rect(
+                        displayBounds.left, displayBounds.top,
+                        displayBounds.right, displayBounds.centerY()));
+            }
+
+            // Try to move the PiP window if we have entered PiP mode.
+            if (mPipTransitionState.hasEnteredPip()) {
+                final Rect pipBounds = mPipBoundsState.getBounds();
+                final Point edgeInsets = mPipSizeSpecHandler.getScreenEdgeInsets();
+                if ((pipBounds.height() + 2 * edgeInsets.y) > (displayBounds.height() / 2)) {
+                    // PiP bounds is too big to fit either half, bail early.
+                    return;
+                }
+                mMainExecutor.removeCallbacks(mMovePipInResponseToKeepClearAreasChangeCallback);
+                mMainExecutor.execute(mMovePipInResponseToKeepClearAreasChangeCallback);
+            }
+        });
+
         mOneHandedController.ifPresent(controller -> {
             controller.registerTransitionCallback(
                     new OneHandedTransitionCallback() {
@@ -874,6 +934,23 @@
         }
     }
 
+    private void setLauncherKeepClearAreaHeight(boolean visible, int height) {
+        if (visible) {
+            Rect rect = new Rect(
+                    0, mPipBoundsState.getDisplayBounds().bottom - height,
+                    mPipBoundsState.getDisplayBounds().right,
+                    mPipBoundsState.getDisplayBounds().bottom);
+            mPipBoundsState.addNamedUnrestrictedKeepClearArea(LAUNCHER_KEEP_CLEAR_AREA_TAG, rect);
+        } else {
+            mPipBoundsState.removeNamedUnrestrictedKeepClearArea(LAUNCHER_KEEP_CLEAR_AREA_TAG);
+        }
+        updatePipPositionForKeepClearAreas();
+    }
+
+    private void setLauncherAppIconSize(int iconSizePx) {
+        mPipBoundsState.getLauncherState().setAppIconSizePx(iconSizePx);
+    }
+
     private void setOnIsInPipStateChangedListener(Consumer<Boolean> callback) {
         mOnIsInPipStateChangedListener = callback;
         if (mOnIsInPipStateChangedListener != null) {
@@ -1222,18 +1299,26 @@
         public void stopSwipePipToHome(int taskId, ComponentName componentName,
                 Rect destinationBounds, SurfaceControl overlay) {
             executeRemoteCallWithTaskPermission(mController, "stopSwipePipToHome",
-                    (controller) -> {
-                        controller.stopSwipePipToHome(taskId, componentName, destinationBounds,
-                                overlay);
-                    });
+                    (controller) -> controller.stopSwipePipToHome(
+                            taskId, componentName, destinationBounds, overlay));
         }
 
         @Override
         public void setShelfHeight(boolean visible, int height) {
             executeRemoteCallWithTaskPermission(mController, "setShelfHeight",
-                    (controller) -> {
-                        controller.setShelfHeight(visible, height);
-                    });
+                    (controller) -> controller.setShelfHeight(visible, height));
+        }
+
+        @Override
+        public void setLauncherKeepClearAreaHeight(boolean visible, int height) {
+            executeRemoteCallWithTaskPermission(mController, "setLauncherKeepClearAreaHeight",
+                    (controller) -> controller.setLauncherKeepClearAreaHeight(visible, height));
+        }
+
+        @Override
+        public void setLauncherAppIconSize(int iconSizePx) {
+            executeRemoteCallWithTaskPermission(mController, "setLauncherAppIconSize",
+                    (controller) -> controller.setLauncherAppIconSize(iconSizePx));
         }
 
         @Override
@@ -1251,9 +1336,7 @@
         @Override
         public void setPipAnimationTypeToAlpha() {
             executeRemoteCallWithTaskPermission(mController, "setPipAnimationTypeToAlpha",
-                    (controller) -> {
-                        controller.setPinnedStackAnimationType(ANIM_TYPE_ALPHA);
-                    });
+                    (controller) -> controller.setPinnedStackAnimationType(ANIM_TYPE_ALPHA));
         }
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
index 979b7c7..167c032 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
@@ -282,7 +282,8 @@
 
     public void onFocusTaskChanged(ActivityManager.RunningTaskInfo taskInfo) {
         final boolean isSplitScreen = mSplitScreenControllerOptional.isPresent()
-                && mSplitScreenControllerOptional.get().isTaskInSplitScreen(taskInfo.taskId);
+                && mSplitScreenControllerOptional.get().isTaskInSplitScreenForeground(
+                taskInfo.taskId);
         mFocusedTaskAllowSplitScreen = isSplitScreen
                 || (taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
                 && taskInfo.supportsMultiWindow
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java
index d03d075..ff5138d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java
@@ -212,24 +212,25 @@
          */
         @Override
         public Size getSizeForAspectRatio(Size size, float aspectRatio) {
-            // getting the percentage of the max size that current size takes
             float currAspectRatio = (float) size.getWidth() / size.getHeight();
+
+            // getting the percentage of the max size that current size takes
             Size currentMaxSize = getMaxSize(currAspectRatio);
             float currentPercent = (float) size.getWidth() / currentMaxSize.getWidth();
 
             // getting the max size for the target aspect ratio
             Size updatedMaxSize = getMaxSize(aspectRatio);
 
-            int width = (int) (updatedMaxSize.getWidth() * currentPercent);
-            int height = (int) (updatedMaxSize.getHeight() * currentPercent);
+            int width = Math.round(updatedMaxSize.getWidth() * currentPercent);
+            int height = Math.round(updatedMaxSize.getHeight() * currentPercent);
 
             // adjust the dimensions if below allowed min edge size
             if (width < getMinEdgeSize() && aspectRatio <= 1) {
                 width = getMinEdgeSize();
-                height = (int) (width / aspectRatio);
+                height = Math.round(width / aspectRatio);
             } else if (height < getMinEdgeSize() && aspectRatio > 1) {
                 height = getMinEdgeSize();
-                width = (int) (height * aspectRatio);
+                width = Math.round(height * aspectRatio);
             }
 
             // reduce the dimensions of the updated size to the calculated percentage
@@ -365,7 +366,7 @@
         mContext = context;
 
         boolean enablePipSizeLargeScreen = SystemProperties
-                .getBoolean("persist.wm.debug.enable_pip_size_large_screen", false);
+                .getBoolean("persist.wm.debug.enable_pip_size_large_screen", true);
 
         // choose between two implementations of size spec logic
         if (enablePipSizeLargeScreen) {
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 0e8d13d..466da0e 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
@@ -71,8 +71,13 @@
     private static final String TAG = "PipTouchHandler";
     private static final float DEFAULT_STASH_VELOCITY_THRESHOLD = 18000.f;
 
-    private static final boolean ENABLE_PIP_KEEP_CLEAR_ALGORITHM =
-            SystemProperties.getBoolean("persist.wm.debug.enable_pip_keep_clear_algorithm", false);
+    private boolean mEnablePipKeepClearAlgorithm =
+            SystemProperties.getBoolean("persist.wm.debug.enable_pip_keep_clear_algorithm", true);
+
+    @VisibleForTesting
+    void setEnablePipKeepClearAlgorithm(boolean value) {
+        mEnablePipKeepClearAlgorithm = value;
+    }
 
     // Allow PIP to resize to a slightly bigger state upon touch
     private boolean mEnableResize;
@@ -427,7 +432,7 @@
             if (mTouchState.isUserInteracting() && mTouchState.isDragging()) {
                 // Defer the update of the current movement bounds until after the user finishes
                 // touching the screen
-            } else if (ENABLE_PIP_KEEP_CLEAR_ALGORITHM) {
+            } else if (mEnablePipKeepClearAlgorithm) {
                 // Ignore moving PiP if keep clear algorithm is enabled, since IME and shelf height
                 // now are accounted for in the keep clear algorithm calculations
             } else {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
index 75f9a4c..c9b3a1a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
@@ -50,6 +50,8 @@
             Consts.TAG_WM_SHELL),
     WM_SHELL_FLOATING_APPS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
             Consts.TAG_WM_SHELL),
+    WM_SHELL_FOLDABLE(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+            Consts.TAG_WM_SHELL),
     TEST_GROUP(true, true, false, "WindowManagerShellProtoLogTest");
 
     private final boolean mEnabled;
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 94b9e90..7d5ab84 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
@@ -31,7 +31,6 @@
 import static com.android.wm.shell.common.split.SplitScreenUtils.isValidToSplit;
 import static com.android.wm.shell.common.split.SplitScreenUtils.reverseSplitPosition;
 import static com.android.wm.shell.common.split.SplitScreenUtils.samePackage;
-import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
 import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_SPLIT_SCREEN;
 import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
@@ -89,7 +88,6 @@
 import com.android.wm.shell.draganddrop.DragAndDropPolicy;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 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;
@@ -329,9 +327,14 @@
         return mTaskOrganizer.getRunningTaskInfo(taskId);
     }
 
+    /** Check task is under split or not by taskId. */
     public boolean isTaskInSplitScreen(int taskId) {
-        return isSplitScreenVisible()
-                && mStageCoordinator.getStageOfTask(taskId) != STAGE_TYPE_UNDEFINED;
+        return mStageCoordinator.getStageOfTask(taskId) != STAGE_TYPE_UNDEFINED;
+    }
+
+    /** Check split is foreground and task is under split or not by taskId. */
+    public boolean isTaskInSplitScreenForeground(int taskId) {
+        return isTaskInSplitScreen(taskId) && isSplitScreenVisible();
     }
 
     public @SplitPosition int getSplitPosition(int taskId) {
@@ -339,8 +342,7 @@
     }
 
     public boolean moveToSideStage(int taskId, @SplitPosition int sideStagePosition) {
-        return moveToStage(taskId, STAGE_TYPE_SIDE, sideStagePosition,
-                new WindowContainerTransaction());
+        return moveToStage(taskId, sideStagePosition, new WindowContainerTransaction());
     }
 
     /**
@@ -351,13 +353,13 @@
         mStageCoordinator.updateSurfaces(transaction);
     }
 
-    private boolean moveToStage(int taskId, @StageType int stageType,
-            @SplitPosition int stagePosition, WindowContainerTransaction wct) {
+    private boolean moveToStage(int taskId, @SplitPosition int stagePosition,
+            WindowContainerTransaction wct) {
         final ActivityManager.RunningTaskInfo task = mTaskOrganizer.getRunningTaskInfo(taskId);
         if (task == null) {
             throw new IllegalArgumentException("Unknown taskId" + taskId);
         }
-        return mStageCoordinator.moveToStage(task, stageType, stagePosition, wct);
+        return mStageCoordinator.moveToStage(task, stagePosition, wct);
     }
 
     public boolean removeFromSideStage(int taskId) {
@@ -382,10 +384,9 @@
     }
 
     public void enterSplitScreen(int taskId, boolean leftOrTop, WindowContainerTransaction wct) {
-        final int stageType = isSplitScreenVisible() ? STAGE_TYPE_UNDEFINED : STAGE_TYPE_SIDE;
         final int stagePosition =
                 leftOrTop ? SPLIT_POSITION_TOP_OR_LEFT : SPLIT_POSITION_BOTTOM_OR_RIGHT;
-        moveToStage(taskId, stageType, stagePosition, wct);
+        moveToStage(taskId, stagePosition, wct);
     }
 
     public void exitSplitScreen(int toTopTaskId, @ExitReason int exitReason) {
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 7d3e7ca..f159f54 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
@@ -207,6 +207,7 @@
     private boolean mIsDividerRemoteAnimating;
     private boolean mIsDropEntering;
     private boolean mIsExiting;
+    private boolean mIsRootTranslucent;
 
     private DefaultMixedHandler mMixedHandler;
     private final Toast mSplitUnsupportedToast;
@@ -398,66 +399,43 @@
         return STAGE_TYPE_UNDEFINED;
     }
 
-    boolean moveToStage(ActivityManager.RunningTaskInfo task, @StageType int stageType,
-            @SplitPosition int stagePosition, WindowContainerTransaction wct) {
+    boolean moveToStage(ActivityManager.RunningTaskInfo task, @SplitPosition int stagePosition,
+            WindowContainerTransaction wct) {
         StageTaskListener targetStage;
         int sideStagePosition;
-        if (stageType == STAGE_TYPE_MAIN) {
-            targetStage = mMainStage;
-            sideStagePosition = reverseSplitPosition(stagePosition);
-        } else if (stageType == STAGE_TYPE_SIDE) {
+        if (isSplitScreenVisible()) {
+            // If the split screen is foreground, retrieves target stage based on position.
+            targetStage = stagePosition == mSideStagePosition ? mSideStage : mMainStage;
+            sideStagePosition = mSideStagePosition;
+        } else {
             targetStage = mSideStage;
             sideStagePosition = stagePosition;
+        }
+
+        if (!isSplitActive()) {
+            mSplitLayout.init();
+            prepareEnterSplitScreen(wct, task, stagePosition);
+            mSyncQueue.queue(wct);
+            mSyncQueue.runInSync(t -> {
+                updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
+            });
         } else {
-            if (isSplitScreenVisible()) {
-                // If the split screen is activated, retrieves target stage based on position.
-                targetStage = stagePosition == mSideStagePosition ? mSideStage : mMainStage;
-                sideStagePosition = mSideStagePosition;
-            } else {
-                // Exit split if it running background.
-                exitSplitScreen(null /* childrenToTop */, EXIT_REASON_RECREATE_SPLIT);
-
-                targetStage = mSideStage;
-                sideStagePosition = stagePosition;
+            setSideStagePosition(sideStagePosition, wct);
+            targetStage.addTask(task, wct);
+            targetStage.evictAllChildren(wct);
+            if (!isSplitScreenVisible()) {
+                final StageTaskListener anotherStage = targetStage == mMainStage
+                        ? mSideStage : mMainStage;
+                anotherStage.reparentTopTask(wct);
+                anotherStage.evictAllChildren(wct);
+                wct.reorder(mRootTaskInfo.token, true);
             }
+            setRootForceTranslucent(false, wct);
+            mSyncQueue.queue(wct);
         }
 
-        setSideStagePosition(sideStagePosition, wct);
-        final WindowContainerTransaction evictWct = new WindowContainerTransaction();
-        targetStage.evictAllChildren(evictWct);
-
-        // Apply surface bounds before animation start.
-        SurfaceControl.Transaction startT = mTransactionPool.acquire();
-        if (startT != null) {
-            updateSurfaceBounds(mSplitLayout, startT, false /* applyResizingOffset */);
-            startT.apply();
-            mTransactionPool.release(startT);
-        }
-        // reparent the task to an invisible split root will make the activity invisible.  Reorder
-        // the root task to front to make the entering transition from pip to split smooth.
-        wct.reorder(mRootTaskInfo.token, true);
-        wct.setForceTranslucent(mRootTaskInfo.token, true);
-        wct.reorder(targetStage.mRootTaskInfo.token, true);
-        wct.setForceTranslucent(targetStage.mRootTaskInfo.token, true);
-        // prevent the fling divider to center transition
-        mIsDropEntering = true;
-
-        targetStage.addTask(task, wct);
-
-        if (ENABLE_SHELL_TRANSITIONS) {
-            prepareEnterSplitScreen(wct);
-            mSplitTransitions.startEnterTransition(TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE, wct,
-                    null, this, null /* consumedCallback */, (finishWct, finishT) -> {
-                        if (!evictWct.isEmpty()) {
-                            finishWct.merge(evictWct, true);
-                        }
-                    } /* finishedCallback */);
-        } else {
-            if (!evictWct.isEmpty()) {
-                wct.merge(evictWct, true /* transfer */);
-            }
-            mTaskOrganizer.applyTransaction(wct);
-        }
+        // Due to drag already pip task entering split by this method so need to reset flag here.
+        mIsDropEntering = false;
         return true;
     }
 
@@ -716,7 +694,7 @@
         mSplitLayout.setDivideRatio(splitRatio);
         updateWindowBounds(mSplitLayout, wct);
         wct.reorder(mRootTaskInfo.token, true);
-        wct.setForceTranslucent(mRootTaskInfo.token, false);
+        setRootForceTranslucent(false, wct);
 
         // Make sure the launch options will put tasks in the corresponding split roots
         mainOptions = mainOptions != null ? mainOptions : new Bundle();
@@ -764,17 +742,9 @@
         final WindowContainerTransaction wct = new WindowContainerTransaction();
         if (options1 == null) options1 = new Bundle();
         if (pendingIntent2 == null) {
-            // Launching a solo task.
-            ActivityOptions activityOptions = ActivityOptions.fromBundle(options1);
-            activityOptions.update(ActivityOptions.makeRemoteAnimation(adapter));
-            options1 = activityOptions.toBundle();
-            addActivityOptions(options1, null /* launchTarget */);
-            if (shortcutInfo1 != null) {
-                wct.startShortcut(mContext.getPackageName(), shortcutInfo1, options1);
-            } else {
-                wct.sendPendingIntent(pendingIntent1, fillInIntent1, options1);
-            }
-            mSyncQueue.queue(wct);
+            // Launching a solo intent or shortcut as fullscreen.
+            launchAsFullscreenWithRemoteAnimation(pendingIntent1, fillInIntent1, shortcutInfo1,
+                    options1, adapter, wct);
             return;
         }
 
@@ -797,13 +767,9 @@
         final WindowContainerTransaction wct = new WindowContainerTransaction();
         if (options1 == null) options1 = new Bundle();
         if (taskId == INVALID_TASK_ID) {
-            // Launching a solo task.
-            ActivityOptions activityOptions = ActivityOptions.fromBundle(options1);
-            activityOptions.update(ActivityOptions.makeRemoteAnimation(adapter));
-            options1 = activityOptions.toBundle();
-            addActivityOptions(options1, null /* launchTarget */);
-            wct.sendPendingIntent(pendingIntent, fillInIntent, options1);
-            mSyncQueue.queue(wct);
+            // Launching a solo intent as fullscreen.
+            launchAsFullscreenWithRemoteAnimation(pendingIntent, fillInIntent, null, options1,
+                    adapter, wct);
             return;
         }
 
@@ -822,13 +788,8 @@
         final WindowContainerTransaction wct = new WindowContainerTransaction();
         if (options1 == null) options1 = new Bundle();
         if (taskId == INVALID_TASK_ID) {
-            // Launching a solo task.
-            ActivityOptions activityOptions = ActivityOptions.fromBundle(options1);
-            activityOptions.update(ActivityOptions.makeRemoteAnimation(adapter));
-            options1 = activityOptions.toBundle();
-            addActivityOptions(options1, null /* launchTarget */);
-            wct.startShortcut(mContext.getPackageName(), shortcutInfo, options1);
-            mSyncQueue.queue(wct);
+            // Launching a solo shortcut as fullscreen.
+            launchAsFullscreenWithRemoteAnimation(null, null, shortcutInfo, options1, adapter, wct);
             return;
         }
 
@@ -838,6 +799,49 @@
                 instanceId);
     }
 
+    private void launchAsFullscreenWithRemoteAnimation(@Nullable PendingIntent pendingIntent,
+            @Nullable Intent fillInIntent, @Nullable ShortcutInfo shortcutInfo,
+            @Nullable Bundle options, RemoteAnimationAdapter adapter,
+            WindowContainerTransaction wct) {
+        LegacyTransitions.ILegacyTransition transition =
+                (transit, apps, wallpapers, nonApps, finishedCallback, t) -> {
+                    if (apps == null || apps.length == 0) {
+                        onRemoteAnimationFinished(apps);
+                        t.apply();
+                        try {
+                            adapter.getRunner().onAnimationCancelled(mKeyguardShowing);
+                        } catch (RemoteException e) {
+                            Slog.e(TAG, "Error starting remote animation", e);
+                        }
+                        return;
+                    }
+
+                    for (int i = 0; i < apps.length; ++i) {
+                        if (apps[i].mode == MODE_OPENING) {
+                            t.show(apps[i].leash);
+                        }
+                    }
+                    t.apply();
+
+                    try {
+                        adapter.getRunner().onAnimationStart(
+                                transit, apps, wallpapers, nonApps, finishedCallback);
+                    } catch (RemoteException e) {
+                        Slog.e(TAG, "Error starting remote animation", e);
+                    }
+                };
+
+        addActivityOptions(options, null /* launchTarget */);
+        if (shortcutInfo != null) {
+            wct.startShortcut(mContext.getPackageName(), shortcutInfo, options);
+        } else if (pendingIntent != null) {
+            wct.sendPendingIntent(pendingIntent, fillInIntent, options);
+        } else {
+            Slog.e(TAG, "Pending intent and shortcut are null is invalid case.");
+        }
+        mSyncQueue.queue(transition, WindowManager.TRANSIT_OPEN, wct);
+    }
+
     private void startWithLegacyTransition(WindowContainerTransaction wct,
             @Nullable PendingIntent mainPendingIntent, @Nullable Intent mainFillInIntent,
             @Nullable ShortcutInfo mainShortcutInfo, @Nullable Bundle mainOptions,
@@ -894,23 +898,25 @@
 
         if (options == null) options = new Bundle();
         addActivityOptions(options, mMainStage);
-        options = wrapAsSplitRemoteAnimation(adapter, options);
 
         updateWindowBounds(mSplitLayout, wct);
+        wct.reorder(mRootTaskInfo.token, true);
+        setRootForceTranslucent(false, wct);
 
         // TODO(b/268008375): Merge APIs to start a split pair into one.
         if (mainTaskId != INVALID_TASK_ID) {
+            options = wrapAsSplitRemoteAnimation(adapter, options);
             wct.startTask(mainTaskId, options);
-        } else if (mainShortcutInfo != null) {
-            wct.startShortcut(mContext.getPackageName(), mainShortcutInfo, options);
+            mSyncQueue.queue(wct);
         } else {
-            wct.sendPendingIntent(mainPendingIntent, mainFillInIntent, options);
+            if (mainShortcutInfo != null) {
+                wct.startShortcut(mContext.getPackageName(), mainShortcutInfo, options);
+            } else {
+                wct.sendPendingIntent(mainPendingIntent, mainFillInIntent, options);
+            }
+            mSyncQueue.queue(wrapAsSplitRemoteAnimation(adapter), WindowManager.TRANSIT_OPEN, wct);
         }
 
-        wct.reorder(mRootTaskInfo.token, true);
-        wct.setForceTranslucent(mRootTaskInfo.token, false);
-
-        mSyncQueue.queue(wct);
         mSyncQueue.runInSync(t -> {
             setDividerVisibility(true, t);
         });
@@ -967,6 +973,54 @@
         return activityOptions.toBundle();
     }
 
+    private LegacyTransitions.ILegacyTransition wrapAsSplitRemoteAnimation(
+            RemoteAnimationAdapter adapter) {
+        LegacyTransitions.ILegacyTransition transition =
+                (transit, apps, wallpapers, nonApps, finishedCallback, t) -> {
+                    if (apps == null || apps.length == 0) {
+                        onRemoteAnimationFinished(apps);
+                        t.apply();
+                        try {
+                            adapter.getRunner().onAnimationCancelled(mKeyguardShowing);
+                        } catch (RemoteException e) {
+                            Slog.e(TAG, "Error starting remote animation", e);
+                        }
+                        return;
+                    }
+
+                    // Wrap the divider bar into non-apps target to animate together.
+                    nonApps = ArrayUtils.appendElement(RemoteAnimationTarget.class, nonApps,
+                            getDividerBarLegacyTarget());
+
+                    for (int i = 0; i < apps.length; ++i) {
+                        if (apps[i].mode == MODE_OPENING) {
+                            t.show(apps[i].leash);
+                            // Reset the surface position of the opening app to prevent offset.
+                            t.setPosition(apps[i].leash, 0, 0);
+                        }
+                    }
+                    t.apply();
+
+                    IRemoteAnimationFinishedCallback wrapCallback =
+                            new IRemoteAnimationFinishedCallback.Stub() {
+                                @Override
+                                public void onAnimationFinished() throws RemoteException {
+                                    onRemoteAnimationFinished(apps);
+                                    finishedCallback.onAnimationFinished();
+                                }
+                            };
+                    Transitions.setRunningRemoteTransitionDelegate(adapter.getCallingApplication());
+                    try {
+                        adapter.getRunner().onAnimationStart(
+                                transit, apps, wallpapers, nonApps, wrapCallback);
+                    } catch (RemoteException e) {
+                        Slog.e(TAG, "Error starting remote animation", e);
+                    }
+                };
+
+        return transition;
+    }
+
     private void setEnterInstanceId(InstanceId instanceId) {
         if (instanceId != null) {
             mLogger.enterRequested(instanceId, ENTER_REASON_LAUNCHER);
@@ -993,6 +1047,27 @@
         }
     }
 
+    private void onRemoteAnimationFinished(RemoteAnimationTarget[] apps) {
+        mIsDividerRemoteAnimating = false;
+        mShouldUpdateRecents = true;
+        mSplitRequest = null;
+        // If any stage has no child after finished animation, that side of the split will display
+        // nothing. This might happen if starting the same app on the both sides while not
+        // supporting multi-instance. Exit the split screen and expand that app to full screen.
+        if (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0) {
+            mMainExecutor.execute(() -> exitSplitScreen(mMainStage.getChildCount() == 0
+                    ? mSideStage : mMainStage, EXIT_REASON_UNKNOWN));
+            mSplitUnsupportedToast.show();
+            return;
+        }
+
+        final WindowContainerTransaction evictWct = new WindowContainerTransaction();
+        prepareEvictNonOpeningChildTasks(SPLIT_POSITION_TOP_OR_LEFT, apps, evictWct);
+        prepareEvictNonOpeningChildTasks(SPLIT_POSITION_BOTTOM_OR_RIGHT, apps, evictWct);
+        mSyncQueue.queue(evictWct);
+    }
+
+
     /**
      * Collects all the current child tasks of a specific split and prepares transaction to evict
      * them to display.
@@ -1247,7 +1322,7 @@
             mSideStage.removeAllTasks(wct, false /* toTop */);
             mMainStage.deactivate(wct, false /* toTop */);
             wct.reorder(mRootTaskInfo.token, false /* onTop */);
-            wct.setForceTranslucent(mRootTaskInfo.token, true);
+            setRootForceTranslucent(true, wct);
             wct.setBounds(mSideStage.mRootTaskInfo.token, mTempRect1);
             onTransitionAnimationComplete();
         } else {
@@ -1279,7 +1354,7 @@
                     mMainStage.deactivate(finishedWCT, childrenToTop == mMainStage /* toTop */);
                     mSideStage.removeAllTasks(finishedWCT, childrenToTop == mSideStage /* toTop */);
                     finishedWCT.reorder(mRootTaskInfo.token, false /* toTop */);
-                    finishedWCT.setForceTranslucent(mRootTaskInfo.token, true);
+                    setRootForceTranslucent(true, finishedWCT);
                     finishedWCT.setBounds(mSideStage.mRootTaskInfo.token, mTempRect1);
                     mSyncQueue.queue(finishedWCT);
                     mSyncQueue.runInSync(at -> {
@@ -1391,7 +1466,7 @@
         mMainStage.activate(wct, true /* includingTopTask */);
         updateWindowBounds(mSplitLayout, wct);
         wct.reorder(mRootTaskInfo.token, true);
-        wct.setForceTranslucent(mRootTaskInfo.token, false);
+        setRootForceTranslucent(false, wct);
     }
 
     void finishEnterSplitScreen(SurfaceControl.Transaction t) {
@@ -1595,6 +1670,7 @@
 
         mRootTaskInfo = null;
         mRootTaskLeash = null;
+        mIsRootTranslucent = false;
     }
 
 
@@ -1613,7 +1689,7 @@
         // Make the stages adjacent to each other so they occlude what's behind them.
         wct.setAdjacentRoots(mMainStage.mRootTaskInfo.token, mSideStage.mRootTaskInfo.token);
         wct.setLaunchAdjacentFlagRoot(mSideStage.mRootTaskInfo.token);
-        wct.setForceTranslucent(mRootTaskInfo.token, true);
+        setRootForceTranslucent(true, wct);
         mSplitLayout.getInvisibleBounds(mTempRect1);
         wct.setBounds(mSideStage.mRootTaskInfo.token, mTempRect1);
         mSyncQueue.queue(wct);
@@ -1637,7 +1713,7 @@
             mSideStage.evictOtherChildren(wct, taskId);
             updateWindowBounds(mSplitLayout, wct);
             wct.reorder(mRootTaskInfo.token, true);
-            wct.setForceTranslucent(mRootTaskInfo.token, false);
+            setRootForceTranslucent(false, wct);
 
             mSyncQueue.queue(wct);
             mSyncQueue.runInSync(t -> {
@@ -1661,6 +1737,13 @@
         mDisplayInsetsController.removeInsetsChangedListener(mDisplayId, mSplitLayout);
     }
 
+    private void setRootForceTranslucent(boolean translucent, WindowContainerTransaction wct) {
+        if (mIsRootTranslucent == translucent) return;
+
+        mIsRootTranslucent = translucent;
+        wct.setForceTranslucent(mRootTaskInfo.token, translucent);
+    }
+
     private void onStageVisibilityChanged(StageListenerImpl stageListener) {
         // If split didn't active, just ignore this callback because we should already did these
         // on #applyExitSplitScreen.
@@ -1687,10 +1770,11 @@
             // Split entering background.
             wct.setReparentLeafTaskIfRelaunch(mRootTaskInfo.token,
                     true /* setReparentLeafTaskIfRelaunch */);
-            wct.setForceTranslucent(mRootTaskInfo.token, true);
+            setRootForceTranslucent(true, wct);
         } else {
             wct.setReparentLeafTaskIfRelaunch(mRootTaskInfo.token,
                     false /* setReparentLeafTaskIfRelaunch */);
+            setRootForceTranslucent(false, wct);
         }
 
         mSyncQueue.queue(wct);
@@ -1822,7 +1906,7 @@
                 mMainStage.activate(wct, true /* includingTopTask */);
                 updateWindowBounds(mSplitLayout, wct);
                 wct.reorder(mRootTaskInfo.token, true);
-                wct.setForceTranslucent(mRootTaskInfo.token, false);
+                setRootForceTranslucent(false, wct);
             }
 
             mSyncQueue.queue(wct);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index a841b7f..d6f4d6d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -220,12 +220,20 @@
                 mCallbacks.onNoLongerSupportMultiWindow();
                 return;
             }
-            mChildrenTaskInfo.put(taskInfo.taskId, taskInfo);
+            if (taskInfo.topActivity == null && mChildrenTaskInfo.contains(taskInfo.taskId)
+                    && mChildrenTaskInfo.get(taskInfo.taskId).topActivity != null) {
+                // If top activity become null, it means the task is about to vanish, we use this
+                // signal to remove it from children list earlier for smooth dismiss transition.
+                mChildrenTaskInfo.remove(taskInfo.taskId);
+                mChildrenLeashes.remove(taskInfo.taskId);
+            } else {
+                mChildrenTaskInfo.put(taskInfo.taskId, taskInfo);
+            }
             mCallbacks.onChildTaskStatusChanged(taskInfo.taskId, true /* present */,
                     taskInfo.isVisible);
-            if (!ENABLE_SHELL_TRANSITIONS) {
-                updateChildTaskSurface(
-                        taskInfo, mChildrenLeashes.get(taskInfo.taskId), false /* firstAppeared */);
+            if (!ENABLE_SHELL_TRANSITIONS && mChildrenLeashes.contains(taskInfo.taskId)) {
+                updateChildTaskSurface(taskInfo, mChildrenLeashes.get(taskInfo.taskId),
+                        false /* firstAppeared */);
             }
         } else {
             throw new IllegalArgumentException(this + "\n Unknown task: " + taskInfo
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldBackgroundController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldBackgroundController.java
index 86ca292..fe0a3fb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldBackgroundController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldBackgroundController.java
@@ -79,7 +79,7 @@
     }
 
     private float[] getBackgroundColor(Context context) {
-        int colorInt = context.getResources().getColor(R.color.taskbar_background);
+        int colorInt = context.getResources().getColor(R.color.unfold_background);
         return new float[]{
                 (float) red(colorInt) / 255.0F,
                 (float) green(colorInt) / 255.0F,
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 9224b3c..6b7ca42 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
@@ -193,6 +193,7 @@
         private final DragDetector mDragDetector;
 
         private int mDragPointerId = -1;
+        private boolean mIsDragging;
 
         private CaptionTouchEventListener(
                 RunningTaskInfo taskInfo,
@@ -223,19 +224,15 @@
             if (v.getId() != R.id.caption) {
                 return false;
             }
-            mDragDetector.onMotionEvent(e);
-
-            if (e.getAction() != MotionEvent.ACTION_DOWN) {
-                return false;
+            if (e.getAction() == MotionEvent.ACTION_DOWN) {
+                final RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId);
+                if (!taskInfo.isFocused) {
+                    final WindowContainerTransaction wct = new WindowContainerTransaction();
+                    wct.reorder(mTaskToken, true /* onTop */);
+                    mSyncQueue.queue(wct);
+                }
             }
-            final RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId);
-            if (taskInfo.isFocused) {
-                return false;
-            }
-            final WindowContainerTransaction wct = new WindowContainerTransaction();
-            wct.reorder(mTaskToken, true /* onTop */);
-            mSyncQueue.queue(wct);
-            return true;
+            return mDragDetector.onMotionEvent(e);
         }
 
         /**
@@ -253,20 +250,24 @@
                     mDragPointerId = e.getPointerId(0);
                     mDragPositioningCallback.onDragPositioningStart(
                             0 /* ctrlType */, e.getRawX(0), e.getRawY(0));
-                    break;
+                    mIsDragging = false;
+                    return false;
                 }
                 case MotionEvent.ACTION_MOVE: {
                     int dragPointerIdx = e.findPointerIndex(mDragPointerId);
                     mDragPositioningCallback.onDragPositioningMove(
                             e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx));
-                    break;
+                    mIsDragging = true;
+                    return true;
                 }
                 case MotionEvent.ACTION_UP:
                 case MotionEvent.ACTION_CANCEL: {
                     int dragPointerIdx = e.findPointerIndex(mDragPointerId);
                     mDragPositioningCallback.onDragPositioningEnd(
                             e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx));
-                    break;
+                    final boolean wasDragging = mIsDragging;
+                    mIsDragging = false;
+                    return wasDragging;
                 }
             }
             return true;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index c517f7b..dee5f8f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -223,6 +223,7 @@
         private final DragPositioningCallback mDragPositioningCallback;
         private final DragDetector mDragDetector;
 
+        private boolean mIsDragging;
         private int mDragPointerId = -1;
 
         private DesktopModeTouchEventListener(
@@ -273,23 +274,7 @@
             if (id != R.id.caption_handle && id != R.id.desktop_mode_caption) {
                 return false;
             }
-            switch (e.getAction()) {
-                case MotionEvent.ACTION_DOWN:
-                    mDragDetector.onMotionEvent(e);
-                    final RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId);
-                    if (taskInfo.isFocused) {
-                        return mDragDetector.isDragEvent();
-                    }
-                    return false;
-                case MotionEvent.ACTION_UP:
-                case MotionEvent.ACTION_CANCEL:
-                    boolean res = mDragDetector.isDragEvent();
-                    mDragDetector.onMotionEvent(e);
-                    return res;
-                default:
-                    mDragDetector.onMotionEvent(e);
-                    return mDragDetector.isDragEvent();
-            }
+            return mDragDetector.onMotionEvent(e);
         }
 
         /**
@@ -313,13 +298,15 @@
                     mDragPointerId = e.getPointerId(0);
                     mDragPositioningCallback.onDragPositioningStart(
                             0 /* ctrlType */, e.getRawX(0), e.getRawY(0));
-                    break;
+                    mIsDragging = false;
+                    return false;
                 }
                 case MotionEvent.ACTION_MOVE: {
                     final int dragPointerIdx = e.findPointerIndex(mDragPointerId);
                     mDragPositioningCallback.onDragPositioningMove(
                             e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx));
-                    break;
+                    mIsDragging = true;
+                    return true;
                 }
                 case MotionEvent.ACTION_UP:
                 case MotionEvent.ACTION_CANCEL: {
@@ -336,7 +323,9 @@
                                     c -> c.moveToFullscreen(taskInfo));
                         }
                     }
-                    break;
+                    final boolean wasDragging = mIsDragging;
+                    mIsDragging = false;
+                    return wasDragging;
                 }
             }
             return true;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index 72da108..3c0ef96 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -23,6 +23,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.ColorStateList;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Color;
 import android.graphics.Point;
@@ -46,6 +47,7 @@
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.desktopmode.DesktopModeStatus;
+import com.android.wm.shell.desktopmode.DesktopTasksController;
 
 /**
  * Defines visuals and behaviors of a window decoration of a caption bar and shadows. It works with
@@ -95,6 +97,17 @@
         mDesktopActive = DesktopModeStatus.isActive(mContext);
     }
 
+    @Override
+    protected Configuration getConfigurationWithOverrides(
+            ActivityManager.RunningTaskInfo taskInfo) {
+        Configuration configuration = taskInfo.getConfiguration();
+        if (DesktopTasksController.isDesktopDensityOverrideSet()) {
+            // Density is overridden for desktop tasks. Keep system density for window decoration.
+            configuration.densityDpi = mContext.getResources().getConfiguration().densityDpi;
+        }
+        return configuration;
+    }
+
     void setCaptionListeners(
             View.OnClickListener onCaptionButtonClickListener,
             View.OnTouchListener onCaptionTouchListener) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
index cf1850b..65b5a7a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
@@ -56,10 +56,15 @@
      * {@link #mEventHandler} handles the previous down event if the event shouldn't be passed
     */
     boolean onMotionEvent(MotionEvent ev) {
+        final boolean isTouchScreen =
+                (ev.getSource() & SOURCE_TOUCHSCREEN) == SOURCE_TOUCHSCREEN;
+        if (!isTouchScreen) {
+            // Only touches generate noisy moves, so mouse/trackpad events don't need to filtered
+            // to take the slop threshold into consideration.
+            return mEventHandler.handleMotionEvent(ev);
+        }
         switch (ev.getActionMasked()) {
             case ACTION_DOWN: {
-                // Only touch screens generate noisy moves.
-                mIsDragEvent = (ev.getSource() & SOURCE_TOUCHSCREEN) != SOURCE_TOUCHSCREEN;
                 mDragPointerId = ev.getPointerId(0);
                 float rawX = ev.getRawX(0);
                 float rawY = ev.getRawY(0);
@@ -72,8 +77,12 @@
                     int dragPointerIndex = ev.findPointerIndex(mDragPointerId);
                     float dx = ev.getRawX(dragPointerIndex) - mInputDownPoint.x;
                     float dy = ev.getRawY(dragPointerIndex) - mInputDownPoint.y;
+                    // Touches generate noisy moves, so only once the move is past the touch
+                    // slop threshold should it be considered a drag.
                     mIsDragEvent = Math.hypot(dx, dy) > mTouchSlop;
                 }
+                // The event handler should only be notified about 'move' events if a drag has been
+                // detected.
                 if (mIsDragEvent) {
                     return mEventHandler.handleMotionEvent(ev);
                 } else {
@@ -94,10 +103,6 @@
         mTouchSlop = touchSlop;
     }
 
-    boolean isDragEvent() {
-        return mIsDragEvent;
-    }
-
     private void resetState() {
         mIsDragEvent = false;
         mInputDownPoint.set(0, 0);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/OWNERS
new file mode 100644
index 0000000..4417209
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/OWNERS
@@ -0,0 +1 @@
+jorgegil@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java
index a3d364a..0bce3ac 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java
@@ -40,6 +40,7 @@
     private final DisplayController mDisplayController;
     private final WindowDecoration mWindowDecoration;
 
+    private final Rect mTempBounds = new Rect();
     private final Rect mTaskBoundsAtDragStart = new Rect();
     private final PointF mRepositionStartPoint = new PointF();
     private final Rect mRepositionTaskBounds = new Rect();
@@ -117,17 +118,32 @@
         final float deltaX = x - mRepositionStartPoint.x;
         final float deltaY = y - mRepositionStartPoint.y;
         mRepositionTaskBounds.set(mTaskBoundsAtDragStart);
+
+        final Rect stableBounds = mTempBounds;
+        // Make sure the new resizing destination in any direction falls within the stable bounds.
+        // If not, set the bounds back to the old location that was valid to avoid conflicts with
+        // some regions such as the gesture area.
+        mDisplayController.getDisplayLayout(mWindowDecoration.mDisplay.getDisplayId())
+                .getStableBounds(stableBounds);
         if ((mCtrlType & CTRL_TYPE_LEFT) != 0) {
-            mRepositionTaskBounds.left += deltaX;
+            final int candidateLeft = mRepositionTaskBounds.left + (int) deltaX;
+            mRepositionTaskBounds.left = (candidateLeft > stableBounds.left)
+                    ? candidateLeft : oldLeft;
         }
         if ((mCtrlType & CTRL_TYPE_RIGHT) != 0) {
-            mRepositionTaskBounds.right += deltaX;
+            final int candidateRight = mRepositionTaskBounds.right + (int) deltaX;
+            mRepositionTaskBounds.right = (candidateRight < stableBounds.right)
+                    ? candidateRight : oldRight;
         }
         if ((mCtrlType & CTRL_TYPE_TOP) != 0) {
-            mRepositionTaskBounds.top += deltaY;
+            final int candidateTop = mRepositionTaskBounds.top + (int) deltaY;
+            mRepositionTaskBounds.top = (candidateTop > stableBounds.top)
+                    ? candidateTop : oldTop;
         }
         if ((mCtrlType & CTRL_TYPE_BOTTOM) != 0) {
-            mRepositionTaskBounds.bottom += deltaY;
+            final int candidateBottom = mRepositionTaskBounds.bottom + (int) deltaY;
+            mRepositionTaskBounds.bottom = (candidateBottom < stableBounds.bottom)
+                    ? candidateBottom : oldBottom;
         }
         if (mCtrlType == CTRL_TYPE_UNDEFINED) {
             mRepositionTaskBounds.offset((int) deltaX, (int) deltaY);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
index 133826f..f8e6ecc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
@@ -131,7 +131,17 @@
         mSurfaceControlViewHostFactory = surfaceControlViewHostFactory;
 
         mDisplay = mDisplayController.getDisplay(mTaskInfo.displayId);
-        mDecorWindowContext = mContext.createConfigurationContext(mTaskInfo.getConfiguration());
+        mDecorWindowContext = mContext.createConfigurationContext(
+                getConfigurationWithOverrides(mTaskInfo));
+    }
+
+    /**
+     * Get {@link Configuration} from supplied {@link RunningTaskInfo}.
+     *
+     * Allows values to be overridden before returning the configuration.
+     */
+    protected Configuration getConfigurationWithOverrides(RunningTaskInfo taskInfo) {
+        return taskInfo.getConfiguration();
     }
 
     /**
@@ -165,7 +175,7 @@
 
         outResult.mRootView = rootView;
         rootView = null; // Clear it just in case we use it accidentally
-        final Configuration taskConfig = mTaskInfo.getConfiguration();
+        final Configuration taskConfig = getConfigurationWithOverrides(mTaskInfo);
         if (oldTaskConfig.densityDpi != taskConfig.densityDpi
                 || mDisplay == null
                 || mDisplay.getDisplayId() != mTaskInfo.displayId) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/TabletopModeControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/TabletopModeControllerTest.java
new file mode 100644
index 0000000..96d202c
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/TabletopModeControllerTest.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.common;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import static com.android.wm.shell.common.DevicePostureController.DEVICE_POSTURE_CLOSED;
+import static com.android.wm.shell.common.DevicePostureController.DEVICE_POSTURE_HALF_OPENED;
+import static com.android.wm.shell.common.DevicePostureController.DEVICE_POSTURE_OPENED;
+
+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.clearInvocations;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.Surface;
+
+import androidx.test.filters.SmallTest;
+
+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.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for {@link TabletopModeController}.
+ */
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class TabletopModeControllerTest extends ShellTestCase {
+    // It's considered tabletop mode if the display rotation angle matches what's in this array.
+    // It's defined as com.android.internal.R.array.config_deviceTabletopRotations on real devices.
+    private static final int[] TABLETOP_MODE_ROTATIONS = new int[] {
+            90 /* Surface.ROTATION_90 */,
+            270 /* Surface.ROTATION_270 */
+    };
+
+    private TestShellExecutor mMainExecutor;
+
+    private Configuration mConfiguration;
+
+    private TabletopModeController mPipTabletopController;
+
+    @Mock
+    private Context mContext;
+
+    @Mock
+    private ShellInit mShellInit;
+
+    @Mock
+    private Resources mResources;
+
+    @Mock
+    private DevicePostureController mDevicePostureController;
+
+    @Mock
+    private DisplayController mDisplayController;
+
+    @Mock
+    private TabletopModeController.OnTabletopModeChangedListener mOnTabletopModeChangedListener;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        when(mResources.getIntArray(com.android.internal.R.array.config_deviceTabletopRotations))
+                .thenReturn(TABLETOP_MODE_ROTATIONS);
+        when(mContext.getResources()).thenReturn(mResources);
+        mMainExecutor = new TestShellExecutor();
+        mConfiguration = new Configuration();
+        mPipTabletopController = new TabletopModeController(mContext, mShellInit,
+                mDevicePostureController, mDisplayController, mMainExecutor);
+        mPipTabletopController.onInit();
+    }
+
+    @Test
+    public void instantiateController_addInitCallback() {
+        verify(mShellInit, times(1)).addInitCallback(any(), eq(mPipTabletopController));
+    }
+
+    @Test
+    public void registerOnTabletopModeChangedListener_notInTabletopMode_callbackFalse() {
+        mPipTabletopController.onDevicePostureChanged(DEVICE_POSTURE_CLOSED);
+        mConfiguration.windowConfiguration.setDisplayRotation(Surface.ROTATION_0);
+        mPipTabletopController.onDisplayConfigurationChanged(DEFAULT_DISPLAY, mConfiguration);
+
+        mPipTabletopController.registerOnTabletopModeChangedListener(
+                mOnTabletopModeChangedListener);
+
+        verify(mOnTabletopModeChangedListener, times(1))
+                .onTabletopModeChanged(false);
+    }
+
+    @Test
+    public void registerOnTabletopModeChangedListener_inTabletopMode_callbackTrue() {
+        mPipTabletopController.onDevicePostureChanged(DEVICE_POSTURE_HALF_OPENED);
+        mConfiguration.windowConfiguration.setDisplayRotation(Surface.ROTATION_90);
+        mPipTabletopController.onDisplayConfigurationChanged(DEFAULT_DISPLAY, mConfiguration);
+
+        mPipTabletopController.registerOnTabletopModeChangedListener(
+                mOnTabletopModeChangedListener);
+
+        verify(mOnTabletopModeChangedListener, times(1))
+                .onTabletopModeChanged(true);
+    }
+
+    @Test
+    public void registerOnTabletopModeChangedListener_notInTabletopModeTwice_callbackOnce() {
+        mPipTabletopController.onDevicePostureChanged(DEVICE_POSTURE_CLOSED);
+        mConfiguration.windowConfiguration.setDisplayRotation(Surface.ROTATION_90);
+        mPipTabletopController.onDisplayConfigurationChanged(DEFAULT_DISPLAY, mConfiguration);
+
+        mPipTabletopController.registerOnTabletopModeChangedListener(
+                mOnTabletopModeChangedListener);
+        clearInvocations(mOnTabletopModeChangedListener);
+        mConfiguration.windowConfiguration.setDisplayRotation(Surface.ROTATION_0);
+        mPipTabletopController.onDisplayConfigurationChanged(DEFAULT_DISPLAY, mConfiguration);
+
+        verifyZeroInteractions(mOnTabletopModeChangedListener);
+    }
+
+    // Test cases starting from folded state (DEVICE_POSTURE_CLOSED)
+    @Test
+    public void foldedRotation90_halfOpen_scheduleTabletopModeChange() {
+        mPipTabletopController.onDevicePostureChanged(DEVICE_POSTURE_CLOSED);
+        mConfiguration.windowConfiguration.setDisplayRotation(Surface.ROTATION_90);
+        mPipTabletopController.onDisplayConfigurationChanged(DEFAULT_DISPLAY, mConfiguration);
+
+        mPipTabletopController.onDevicePostureChanged(DEVICE_POSTURE_HALF_OPENED);
+
+        assertTrue(mMainExecutor.hasCallback(mPipTabletopController.mOnEnterTabletopModeCallback));
+    }
+
+    @Test
+    public void foldedRotation0_halfOpen_noScheduleTabletopModeChange() {
+        mPipTabletopController.onDevicePostureChanged(DEVICE_POSTURE_CLOSED);
+        mConfiguration.windowConfiguration.setDisplayRotation(Surface.ROTATION_0);
+        mPipTabletopController.onDisplayConfigurationChanged(DEFAULT_DISPLAY, mConfiguration);
+
+        mPipTabletopController.onDevicePostureChanged(DEVICE_POSTURE_HALF_OPENED);
+
+        assertFalse(mMainExecutor.hasCallback(mPipTabletopController.mOnEnterTabletopModeCallback));
+    }
+
+    @Test
+    public void foldedRotation90_halfOpenThenUnfold_cancelTabletopModeChange() {
+        mPipTabletopController.onDevicePostureChanged(DEVICE_POSTURE_CLOSED);
+        mConfiguration.windowConfiguration.setDisplayRotation(Surface.ROTATION_90);
+        mPipTabletopController.onDisplayConfigurationChanged(DEFAULT_DISPLAY, mConfiguration);
+
+        mPipTabletopController.onDevicePostureChanged(DEVICE_POSTURE_HALF_OPENED);
+        mPipTabletopController.onDevicePostureChanged(DEVICE_POSTURE_OPENED);
+
+        assertFalse(mMainExecutor.hasCallback(mPipTabletopController.mOnEnterTabletopModeCallback));
+    }
+
+    @Test
+    public void foldedRotation90_halfOpenThenFold_cancelTabletopModeChange() {
+        mPipTabletopController.onDevicePostureChanged(DEVICE_POSTURE_CLOSED);
+        mConfiguration.windowConfiguration.setDisplayRotation(Surface.ROTATION_90);
+        mPipTabletopController.onDisplayConfigurationChanged(DEFAULT_DISPLAY, mConfiguration);
+
+        mPipTabletopController.onDevicePostureChanged(DEVICE_POSTURE_HALF_OPENED);
+        mPipTabletopController.onDevicePostureChanged(DEVICE_POSTURE_CLOSED);
+
+        assertFalse(mMainExecutor.hasCallback(mPipTabletopController.mOnEnterTabletopModeCallback));
+    }
+
+    @Test
+    public void foldedRotation90_halfOpenThenRotate_cancelTabletopModeChange() {
+        mPipTabletopController.onDevicePostureChanged(DEVICE_POSTURE_CLOSED);
+        mConfiguration.windowConfiguration.setDisplayRotation(Surface.ROTATION_90);
+        mPipTabletopController.onDisplayConfigurationChanged(DEFAULT_DISPLAY, mConfiguration);
+
+        mPipTabletopController.onDevicePostureChanged(DEVICE_POSTURE_HALF_OPENED);
+        mConfiguration.windowConfiguration.setDisplayRotation(Surface.ROTATION_0);
+        mPipTabletopController.onDisplayConfigurationChanged(DEFAULT_DISPLAY, mConfiguration);
+
+        assertFalse(mMainExecutor.hasCallback(mPipTabletopController.mOnEnterTabletopModeCallback));
+    }
+
+    // Test cases starting from unfolded state (DEVICE_POSTURE_OPENED)
+    @Test
+    public void unfoldedRotation90_halfOpen_scheduleTabletopModeChange() {
+        mPipTabletopController.onDevicePostureChanged(DEVICE_POSTURE_OPENED);
+        mConfiguration.windowConfiguration.setDisplayRotation(Surface.ROTATION_90);
+        mPipTabletopController.onDisplayConfigurationChanged(DEFAULT_DISPLAY, mConfiguration);
+
+        mPipTabletopController.onDevicePostureChanged(DEVICE_POSTURE_HALF_OPENED);
+
+        assertTrue(mMainExecutor.hasCallback(mPipTabletopController.mOnEnterTabletopModeCallback));
+    }
+
+    @Test
+    public void unfoldedRotation0_halfOpen_noScheduleTabletopModeChange() {
+        mPipTabletopController.onDevicePostureChanged(DEVICE_POSTURE_OPENED);
+        mConfiguration.windowConfiguration.setDisplayRotation(Surface.ROTATION_0);
+        mPipTabletopController.onDisplayConfigurationChanged(DEFAULT_DISPLAY, mConfiguration);
+
+        mPipTabletopController.onDevicePostureChanged(DEVICE_POSTURE_HALF_OPENED);
+
+        assertFalse(mMainExecutor.hasCallback(mPipTabletopController.mOnEnterTabletopModeCallback));
+    }
+
+    @Test
+    public void unfoldedRotation90_halfOpenThenUnfold_cancelTabletopModeChange() {
+        mPipTabletopController.onDevicePostureChanged(DEVICE_POSTURE_OPENED);
+        mConfiguration.windowConfiguration.setDisplayRotation(Surface.ROTATION_90);
+        mPipTabletopController.onDisplayConfigurationChanged(DEFAULT_DISPLAY, mConfiguration);
+
+        mPipTabletopController.onDevicePostureChanged(DEVICE_POSTURE_HALF_OPENED);
+        mPipTabletopController.onDevicePostureChanged(DEVICE_POSTURE_OPENED);
+
+        assertFalse(mMainExecutor.hasCallback(mPipTabletopController.mOnEnterTabletopModeCallback));
+    }
+
+    @Test
+    public void unfoldedRotation90_halfOpenThenFold_cancelTabletopModeChange() {
+        mPipTabletopController.onDevicePostureChanged(DEVICE_POSTURE_OPENED);
+        mConfiguration.windowConfiguration.setDisplayRotation(Surface.ROTATION_90);
+        mPipTabletopController.onDisplayConfigurationChanged(DEFAULT_DISPLAY, mConfiguration);
+
+        mPipTabletopController.onDevicePostureChanged(DEVICE_POSTURE_HALF_OPENED);
+        mPipTabletopController.onDevicePostureChanged(DEVICE_POSTURE_CLOSED);
+
+        assertFalse(mMainExecutor.hasCallback(mPipTabletopController.mOnEnterTabletopModeCallback));
+    }
+
+    @Test
+    public void unfoldedRotation90_halfOpenThenRotate_cancelTabletopModeChange() {
+        mPipTabletopController.onDevicePostureChanged(DEVICE_POSTURE_OPENED);
+        mConfiguration.windowConfiguration.setDisplayRotation(Surface.ROTATION_90);
+        mPipTabletopController.onDisplayConfigurationChanged(DEFAULT_DISPLAY, mConfiguration);
+
+        mPipTabletopController.onDevicePostureChanged(DEVICE_POSTURE_HALF_OPENED);
+        mConfiguration.windowConfiguration.setDisplayRotation(Surface.ROTATION_0);
+        mPipTabletopController.onDisplayConfigurationChanged(DEFAULT_DISPLAY, mConfiguration);
+
+        assertFalse(mMainExecutor.hasCallback(mPipTabletopController.mOnEnterTabletopModeCallback));
+    }
+}
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 98de584..4cf9e6a 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
@@ -54,7 +54,6 @@
 import com.android.wm.shell.common.DockStateReader;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.compatui.letterboxedu.LetterboxEduWindowManager;
 import com.android.wm.shell.sysui.ShellController;
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.transition.Transitions;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayoutTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/LetterboxEduDialogLayoutTest.java
similarity index 91%
rename from libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayoutTest.java
rename to libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/LetterboxEduDialogLayoutTest.java
index a58620d..172c263 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayoutTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/LetterboxEduDialogLayoutTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.wm.shell.compatui.letterboxedu;
+package com.android.wm.shell.compatui;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -58,9 +58,8 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
-        mLayout = (LetterboxEduDialogLayout)
-                LayoutInflater.from(mContext).inflate(R.layout.letterbox_education_dialog_layout,
-                        null);
+        mLayout = (LetterboxEduDialogLayout) LayoutInflater.from(mContext)
+                .inflate(R.layout.letterbox_education_dialog_layout, null);
         mDismissButton = mLayout.findViewById(R.id.letterbox_education_dialog_dismiss_button);
         mDialogContainer = mLayout.findViewById(R.id.letterbox_education_dialog_container);
         mLayout.setDismissOnClickListener(mDismissCallback);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/LetterboxEduWindowManagerTest.java
similarity index 85%
rename from libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManagerTest.java
rename to libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/LetterboxEduWindowManagerTest.java
index 14190f1..3f79df6 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManagerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/LetterboxEduWindowManagerTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.wm.shell.compatui.letterboxedu;
+package com.android.wm.shell.compatui;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 
@@ -31,14 +31,12 @@
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 
-import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.TaskInfo;
-import android.content.Context;
-import android.content.SharedPreferences;
 import android.graphics.Insets;
 import android.graphics.Rect;
 import android.testing.AndroidTestingRunner;
+import android.util.Pair;
 import android.view.DisplayCutout;
 import android.view.DisplayInfo;
 import android.view.SurfaceControlViewHost;
@@ -53,10 +51,10 @@
 import com.android.wm.shell.R;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.TestShellExecutor;
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.common.DockStateReader;
 import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.compatui.DialogAnimationController;
 import com.android.wm.shell.transition.Transitions;
 
 import org.junit.After;
@@ -68,6 +66,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.function.Consumer;
+
 /**
  * Tests for {@link LetterboxEduWindowManager}.
  *
@@ -81,8 +81,10 @@
     private static final int USER_ID_1 = 1;
     private static final int USER_ID_2 = 2;
 
-    private static final String PREF_KEY_1 = String.valueOf(USER_ID_1);
-    private static final String PREF_KEY_2 = String.valueOf(USER_ID_2);
+    private static final String TEST_COMPAT_UI_SHARED_PREFERENCES = "test_compat_ui_configuration";
+
+    private static final String TEST_HAS_SEEN_LETTERBOX_SHARED_PREFERENCES =
+            "test_has_seen_letterbox";
 
     private static final int TASK_ID = 1;
 
@@ -104,46 +106,34 @@
     @Mock private ShellTaskOrganizer.TaskListener mTaskListener;
     @Mock private SurfaceControlViewHost mViewHost;
     @Mock private Transitions mTransitions;
-    @Mock private Runnable mOnDismissCallback;
+    @Mock private Consumer<Pair<TaskInfo, ShellTaskOrganizer.TaskListener>> mOnDismissCallback;
     @Mock private DockStateReader mDockStateReader;
 
-    private SharedPreferences mSharedPreferences;
-    @Nullable
-    private Boolean mInitialPrefValue1 = null;
-    @Nullable
-    private Boolean mInitialPrefValue2 = null;
+    private CompatUIConfiguration mCompatUIConfiguration;
+    private TestShellExecutor mExecutor;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
+        mExecutor = new TestShellExecutor();
+        mCompatUIConfiguration = new CompatUIConfiguration(mContext, mExecutor) {
 
-        mSharedPreferences = mContext.getSharedPreferences(
-                LetterboxEduWindowManager.HAS_SEEN_LETTERBOX_EDUCATION_PREF_NAME,
-                Context.MODE_PRIVATE);
-        if (mSharedPreferences.contains(PREF_KEY_1)) {
-            mInitialPrefValue1 = mSharedPreferences.getBoolean(PREF_KEY_1, /* default= */ false);
-            mSharedPreferences.edit().remove(PREF_KEY_1).apply();
-        }
-        if (mSharedPreferences.contains(PREF_KEY_2)) {
-            mInitialPrefValue2 = mSharedPreferences.getBoolean(PREF_KEY_2, /* default= */ false);
-            mSharedPreferences.edit().remove(PREF_KEY_2).apply();
-        }
+            @Override
+            protected String getCompatUISharedPreferenceName() {
+                return TEST_COMPAT_UI_SHARED_PREFERENCES;
+            }
+
+            @Override
+            protected String getHasSeenLetterboxEducationSharedPreferencedName() {
+                return TEST_HAS_SEEN_LETTERBOX_SHARED_PREFERENCES;
+            }
+        };
     }
 
     @After
     public void tearDown() {
-        SharedPreferences.Editor editor = mSharedPreferences.edit();
-        if (mInitialPrefValue1 == null) {
-            editor.remove(PREF_KEY_1);
-        } else {
-            editor.putBoolean(PREF_KEY_1, mInitialPrefValue1);
-        }
-        if (mInitialPrefValue2 == null) {
-            editor.remove(PREF_KEY_2);
-        } else {
-            editor.putBoolean(PREF_KEY_2, mInitialPrefValue2);
-        }
-        editor.apply();
+        mContext.deleteSharedPreferences(TEST_COMPAT_UI_SHARED_PREFERENCES);
+        mContext.deleteSharedPreferences(TEST_HAS_SEEN_LETTERBOX_SHARED_PREFERENCES);
     }
 
     @Test
@@ -167,8 +157,8 @@
 
     @Test
     public void testCreateLayout_taskBarEducationIsShowing_doesNotCreateLayout() {
-        LetterboxEduWindowManager windowManager = createWindowManager(/* eligible= */
-                true, USER_ID_1, /* isTaskbarEduShowing= */ true);
+        LetterboxEduWindowManager windowManager = createWindowManager(/* eligible= */ true,
+                USER_ID_1, /* isTaskbarEduShowing= */ true);
 
         assertFalse(windowManager.createLayout(/* canShow= */ true));
 
@@ -181,7 +171,7 @@
 
         assertTrue(windowManager.createLayout(/* canShow= */ false));
 
-        assertFalse(mSharedPreferences.getBoolean(PREF_KEY_1, /* default= */ false));
+        assertFalse(mCompatUIConfiguration.getHasSeenLetterboxEducation(USER_ID_1));
         assertNull(windowManager.mLayout);
     }
 
@@ -202,7 +192,7 @@
         spyOn(dialogTitle);
 
         // The education shouldn't be marked as seen until enter animation is done.
-        assertFalse(mSharedPreferences.getBoolean(PREF_KEY_1, /* default= */ false));
+        assertFalse(mCompatUIConfiguration.getHasSeenLetterboxEducation(USER_ID_1));
         // Clicking the layout does nothing until enter animation is done.
         layout.performClick();
         verify(mAnimationController, never()).startExitAnimation(any(), any());
@@ -211,7 +201,7 @@
 
         verifyAndFinishEnterAnimation(layout);
 
-        assertTrue(mSharedPreferences.getBoolean(PREF_KEY_1, /* default= */ false));
+        assertFalse(mCompatUIConfiguration.getHasSeenLetterboxEducation(USER_ID_1));
         verify(dialogTitle).sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
         // Exit animation should start following a click on the layout.
         layout.performClick();
@@ -219,13 +209,16 @@
         // Window manager isn't released until exit animation is done.
         verify(windowManager, never()).release();
 
+        // After dismissed the user has seen the dialog
+        assertTrue(mCompatUIConfiguration.getHasSeenLetterboxEducation(USER_ID_1));
+
         // Verify multiple clicks are ignored.
         layout.performClick();
 
         verifyAndFinishExitAnimation(layout);
 
         verify(windowManager).release();
-        verify(mOnDismissCallback).run();
+        verify(mOnDismissCallback).accept(any());
     }
 
     @Test
@@ -237,7 +230,10 @@
 
         assertNotNull(windowManager.mLayout);
         verifyAndFinishEnterAnimation(windowManager.mLayout);
-        assertTrue(mSharedPreferences.getBoolean(PREF_KEY_1, /* default= */ false));
+
+        // We dismiss
+        windowManager.mLayout.findViewById(R.id.letterbox_education_dialog_dismiss_button)
+                .performClick();
 
         windowManager.release();
         windowManager = createWindowManager(/* eligible= */ true,
@@ -255,7 +251,7 @@
 
         assertNotNull(windowManager.mLayout);
         verifyAndFinishEnterAnimation(windowManager.mLayout);
-        assertTrue(mSharedPreferences.getBoolean(PREF_KEY_1, /* default= */ false));
+        assertTrue(mCompatUIConfiguration.getHasSeenLetterboxEducation(USER_ID_1));
     }
 
     @Test
@@ -272,7 +268,7 @@
         mRunOnIdleCaptor.getValue().run();
 
         verify(mAnimationController, never()).startEnterAnimation(any(), any());
-        assertFalse(mSharedPreferences.getBoolean(PREF_KEY_1, /* default= */ false));
+        assertFalse(mCompatUIConfiguration.getHasSeenLetterboxEducation(USER_ID_1));
     }
 
     @Test
@@ -298,7 +294,7 @@
                 mTaskListener, /* canShow= */ true));
 
         verify(windowManager).release();
-        verify(mOnDismissCallback, never()).run();
+        verify(mOnDismissCallback, never()).accept(any());
         verify(mAnimationController, never()).startExitAnimation(any(), any());
         assertNull(windowManager.mLayout);
     }
@@ -396,23 +392,22 @@
     }
 
     private LetterboxEduWindowManager createWindowManager(boolean eligible, boolean isDocked) {
-        return createWindowManager(eligible, USER_ID_1, /* isTaskbarEduShowing= */
-                false, isDocked);
+        return createWindowManager(eligible, USER_ID_1, /* isTaskbarEduShowing= */ false, isDocked);
     }
 
-    private LetterboxEduWindowManager createWindowManager(boolean eligible,
-            int userId, boolean isTaskbarEduShowing) {
+    private LetterboxEduWindowManager createWindowManager(boolean eligible, int userId,
+            boolean isTaskbarEduShowing) {
         return createWindowManager(eligible, userId, isTaskbarEduShowing, /* isDocked */false);
     }
 
-    private LetterboxEduWindowManager createWindowManager(boolean eligible,
-            int userId, boolean isTaskbarEduShowing, boolean isDocked) {
+    private LetterboxEduWindowManager createWindowManager(boolean eligible, int userId,
+            boolean isTaskbarEduShowing, boolean isDocked) {
         doReturn(isDocked).when(mDockStateReader).isDocked();
-        LetterboxEduWindowManager windowManager = new LetterboxEduWindowManager(mContext,
+        LetterboxEduWindowManager
+                windowManager = new LetterboxEduWindowManager(mContext,
                 createTaskInfo(eligible, userId), mSyncTransactionQueue, mTaskListener,
-                createDisplayLayout(), mTransitions, mOnDismissCallback,
-                mAnimationController, mDockStateReader);
-
+                createDisplayLayout(), mTransitions, mOnDismissCallback, mAnimationController,
+                mDockStateReader, mCompatUIConfiguration);
         spyOn(windowManager);
         doReturn(mViewHost).when(windowManager).createSurfaceViewHost();
         doReturn(isTaskbarEduShowing).when(windowManager).isTaskbarEduShowing();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/ReachabilityEduLayoutTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/ReachabilityEduLayoutTest.java
new file mode 100644
index 0000000..0be08ba
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/ReachabilityEduLayoutTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.compatui;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+
+import android.testing.AndroidTestingRunner;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.R;
+import com.android.wm.shell.ShellTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for {@link LetterboxEduDialogLayout}.
+ *
+ * Build/Install/Run:
+ * atest WMShellUnitTests:ReachabilityEduLayoutTest
+ */
+@RunWith(AndroidTestingRunner.class)
+@SmallTest
+public class ReachabilityEduLayoutTest extends ShellTestCase {
+
+    private ReachabilityEduLayout mLayout;
+    private View mMoveUpButton;
+    private View mMoveDownButton;
+    private View mMoveLeftButton;
+    private View mMoveRightButton;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mLayout = (ReachabilityEduLayout) LayoutInflater.from(mContext)
+                .inflate(R.layout.reachability_ui_layout, null);
+        mMoveLeftButton = mLayout.findViewById(R.id.reachability_move_left_button);
+        mMoveRightButton = mLayout.findViewById(R.id.reachability_move_right_button);
+        mMoveUpButton = mLayout.findViewById(R.id.reachability_move_up_button);
+        mMoveDownButton = mLayout.findViewById(R.id.reachability_move_down_button);
+    }
+
+    @Test
+    public void testOnFinishInflate() {
+        assertNotNull(mMoveUpButton);
+        assertNotNull(mMoveDownButton);
+        assertNotNull(mMoveLeftButton);
+        assertNotNull(mMoveRightButton);
+    }
+
+    @Test
+    public void handleVisibility_activityNotLetterboxed_buttonsAreHidden() {
+        mLayout.handleVisibility(/* isActivityLetterboxed */ false,
+                /* letterboxVerticalPosition */  -1, /* letterboxHorizontalPosition */ -1,
+                /* availableWidth */  0, /* availableHeight */ 0, /* fromDoubleTap */ false);
+        assertEquals(View.INVISIBLE, mMoveUpButton.getVisibility());
+        assertEquals(View.INVISIBLE, mMoveDownButton.getVisibility());
+        assertEquals(View.INVISIBLE, mMoveLeftButton.getVisibility());
+        assertEquals(View.INVISIBLE, mMoveRightButton.getVisibility());
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/ReachabilityEduWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/ReachabilityEduWindowManagerTest.java
new file mode 100644
index 0000000..91e1e19
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/ReachabilityEduWindowManagerTest.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.compatui;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.verify;
+
+import android.app.ActivityManager;
+import android.app.TaskInfo;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.TestShellExecutor;
+import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.common.SyncTransactionQueue;
+
+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;
+
+/**
+ * Tests for {@link ReachabilityEduWindowManager}.
+ *
+ * Build/Install/Run:
+ * atest WMShellUnitTests:ReachabilityEduWindowManagerTest
+ */
+@RunWith(AndroidTestingRunner.class)
+@SmallTest
+public class ReachabilityEduWindowManagerTest extends ShellTestCase {
+
+    private static final int USER_ID = 1;
+    private static final int TASK_ID = 1;
+
+    @Mock
+    private SyncTransactionQueue mSyncTransactionQueue;
+    @Mock
+    private ShellTaskOrganizer.TaskListener mTaskListener;
+    @Mock
+    private CompatUIController.CompatUICallback mCallback;
+    @Mock
+    private CompatUIConfiguration mCompatUIConfiguration;
+    @Mock
+    private DisplayLayout mDisplayLayout;
+
+    private TestShellExecutor mExecutor;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mExecutor = new TestShellExecutor();
+    }
+
+    @After
+    public void tearDown() {
+    }
+
+    @Test
+    public void testCreateLayout_notEligible_doesNotCreateLayout() {
+        final ReachabilityEduWindowManager windowManager = createReachabilityEduWindowManager(
+                createTaskInfo(/* userId= */ USER_ID, /*isLetterboxDoubleTapEnabled  */ false));
+
+        assertFalse(windowManager.createLayout(/* canShow= */ true));
+
+        assertNull(windowManager.mLayout);
+    }
+
+    @Test
+    public void testCreateLayout_letterboxPositionChanged_doubleTapIsDetected() {
+        // Initial left position
+        final TaskInfo initialTaskInfo = createTaskInfoForHorizontalTapping(USER_ID, 0, 1000);
+        final ReachabilityEduWindowManager windowManager =
+                createReachabilityEduWindowManager(initialTaskInfo);
+        // Move to the right
+        final TaskInfo newPositionTaskInfo = createTaskInfoForHorizontalTapping(USER_ID, 1, 1000);
+        windowManager.updateCompatInfo(newPositionTaskInfo, mTaskListener, /* canShow */ true);
+
+        verify(mCompatUIConfiguration).setDontShowReachabilityEducationAgain(newPositionTaskInfo);
+    }
+
+
+    private ReachabilityEduWindowManager createReachabilityEduWindowManager(TaskInfo taskInfo) {
+        return new ReachabilityEduWindowManager(mContext, taskInfo,
+                mSyncTransactionQueue, mCallback, mTaskListener, mDisplayLayout,
+                mCompatUIConfiguration, mExecutor);
+    }
+
+    private static TaskInfo createTaskInfo(int userId, boolean isLetterboxDoubleTapEnabled) {
+        return createTaskInfo(userId, /* isLetterboxDoubleTapEnabled */ isLetterboxDoubleTapEnabled,
+                /* topActivityLetterboxVerticalPosition */ -1,
+                /* topActivityLetterboxHorizontalPosition */ -1,
+                /* topActivityLetterboxWidth */ -1,
+                /* topActivityLetterboxHeight */ -1);
+    }
+
+    private static TaskInfo createTaskInfoForHorizontalTapping(int userId,
+            int topActivityLetterboxHorizontalPosition, int topActivityLetterboxWidth) {
+        return createTaskInfo(userId, /* isLetterboxDoubleTapEnabled */ true,
+                /* topActivityLetterboxVerticalPosition */ -1,
+                topActivityLetterboxHorizontalPosition, topActivityLetterboxWidth,
+                /* topActivityLetterboxHeight */ -1);
+    }
+
+    private static TaskInfo createTaskInfo(int userId, boolean isLetterboxDoubleTapEnabled,
+            int topActivityLetterboxVerticalPosition, int topActivityLetterboxHorizontalPosition,
+            int topActivityLetterboxWidth, int topActivityLetterboxHeight) {
+        ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
+        taskInfo.userId = userId;
+        taskInfo.taskId = TASK_ID;
+        taskInfo.isLetterboxDoubleTapEnabled = isLetterboxDoubleTapEnabled;
+        taskInfo.topActivityLetterboxVerticalPosition = topActivityLetterboxVerticalPosition;
+        taskInfo.topActivityLetterboxHorizontalPosition = topActivityLetterboxHorizontalPosition;
+        taskInfo.topActivityLetterboxWidth = topActivityLetterboxWidth;
+        taskInfo.topActivityLetterboxHeight = topActivityLetterboxHeight;
+        return taskInfo;
+    }
+}
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 ecfb427..58e91cb 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
@@ -31,6 +31,7 @@
 import android.app.ActivityManager;
 import android.content.Context;
 import android.content.pm.ParceledListSlice;
+import android.content.res.Resources;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -77,6 +78,7 @@
     @Mock private ShellInit mShellInit;
     @Mock private ShellCommandHandler mShellCommandHandler;
     @Mock private DisplayInsetsController mDisplayInsetsController;
+    @Mock private Resources mResources;
 
     KidsModeTaskOrganizer mOrganizer;
 
@@ -89,10 +91,12 @@
         } catch (RemoteException e) {
         }
         // NOTE: KidsModeTaskOrganizer should have a null CompatUIController.
-        mOrganizer = spy(new KidsModeTaskOrganizer(mContext, mShellInit, mShellCommandHandler,
-                mTaskOrganizerController, mSyncTransactionQueue, mDisplayController,
-                mDisplayInsetsController, Optional.empty(), Optional.empty(), mObserver,
-                mTestExecutor, mHandler));
+        doReturn(mResources).when(mContext).getResources();
+        final KidsModeTaskOrganizer kidsModeTaskOrganizer = new KidsModeTaskOrganizer(mContext,
+                mShellInit, mShellCommandHandler, mTaskOrganizerController, mSyncTransactionQueue,
+                mDisplayController, mDisplayInsetsController, Optional.empty(), Optional.empty(),
+                mObserver, mTestExecutor, mHandler);
+        mOrganizer = spy(kidsModeTaskOrganizer);
         doReturn(mTransaction).when(mOrganizer).getWindowContainerTransaction();
         doReturn(new InsetsState()).when(mDisplayController).getInsetsState(DEFAULT_DISPLAY);
     }
@@ -112,6 +116,8 @@
         verify(mOrganizer, times(1)).registerOrganizer();
         verify(mOrganizer, times(1)).createRootTask(
                 eq(DEFAULT_DISPLAY), eq(WINDOWING_MODE_FULLSCREEN), eq(mOrganizer.mCookie));
+        verify(mOrganizer, times(1))
+                .setOrientationRequestPolicy(eq(true), any(), any());
 
         final ActivityManager.RunningTaskInfo rootTask = createTaskInfo(12,
                 WINDOWING_MODE_FULLSCREEN, mOrganizer.mCookie);
@@ -132,10 +138,11 @@
         doReturn(false).when(mObserver).isEnabled();
         mOrganizer.updateKidsModeState();
 
-
         verify(mOrganizer, times(1)).disable();
         verify(mOrganizer, times(1)).unregisterOrganizer();
         verify(mOrganizer, times(1)).deleteRootTask(rootTask.token);
+        verify(mOrganizer, times(1))
+                .setOrientationRequestPolicy(eq(false), any(), any());
         assertThat(mOrganizer.mLaunchRootLeash).isNull();
         assertThat(mOrganizer.mLaunchRootTask).isNull();
     }
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 4a68287..a41a30e 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
@@ -53,6 +53,7 @@
 import com.android.wm.shell.common.DisplayInsetsController;
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.TabletopModeController;
 import com.android.wm.shell.common.TaskStackListenerImpl;
 import com.android.wm.shell.onehanded.OneHandedController;
 import com.android.wm.shell.pip.PipAnimationController;
@@ -113,6 +114,7 @@
     @Mock private Optional<OneHandedController> mMockOneHandedController;
     @Mock private PipParamsChangedForwarder mMockPipParamsChangedForwarder;
     @Mock private DisplayInsetsController mMockDisplayInsetsController;
+    @Mock private TabletopModeController mMockTabletopModeController;
 
     @Mock private DisplayLayout mMockDisplayLayout1;
     @Mock private DisplayLayout mMockDisplayLayout2;
@@ -135,7 +137,7 @@
                 mMockPipTransitionState, mMockPipTouchHandler, mMockPipTransitionController,
                 mMockWindowManagerShellWrapper, mMockTaskStackListener,
                 mMockPipParamsChangedForwarder, mMockDisplayInsetsController,
-                mMockOneHandedController, mMockExecutor);
+                mMockTabletopModeController, mMockOneHandedController, mMockExecutor);
         mShellInit.init();
         when(mMockPipBoundsAlgorithm.getSnapAlgorithm()).thenReturn(mMockPipSnapAlgorithm);
         when(mMockPipTouchHandler.getMotionHelper()).thenReturn(mMockPipMotionHelper);
@@ -226,7 +228,7 @@
                 mMockPipTransitionState, mMockPipTouchHandler, mMockPipTransitionController,
                 mMockWindowManagerShellWrapper, mMockTaskStackListener,
                 mMockPipParamsChangedForwarder, mMockDisplayInsetsController,
-                mMockOneHandedController, mMockExecutor));
+                mMockTabletopModeController, mMockOneHandedController, mMockExecutor));
     }
 
     @Test
@@ -312,6 +314,7 @@
 
     @Test
     public void onKeepClearAreasChanged_featureDisabled_pipBoundsStateDoesntChange() {
+        mPipController.setEnablePipKeepClearAlgorithm(false);
         final int displayId = 1;
         final Rect keepClearArea = new Rect(0, 0, 10, 10);
         when(mMockPipBoundsState.getDisplayId()).thenReturn(displayId);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
index 5c4863f..1515d60 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
@@ -173,6 +173,7 @@
 
     @Test
     public void updateMovementBounds_withImeAdjustment_movesPip() {
+        mPipTouchHandler.setEnablePipKeepClearAlgorithm(false);
         mFromImeAdjustment = true;
         mPipTouchHandler.onImeVisibilityChanged(true /* imeVisible */, mImeHeight);
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index 0bb809d..0b528ba 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -144,39 +144,48 @@
     }
 
     @Test
-    public void testMoveToStage() {
+    public void testMoveToStage_splitActiveBackground() {
+        when(mStageCoordinator.isSplitActive()).thenReturn(true);
+
         final ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().build();
+        final WindowContainerTransaction wct = new WindowContainerTransaction();
 
-        mStageCoordinator.moveToStage(task, STAGE_TYPE_MAIN, SPLIT_POSITION_BOTTOM_OR_RIGHT,
-                new WindowContainerTransaction());
-        verify(mMainStage).addTask(eq(task), any(WindowContainerTransaction.class));
-        assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getMainStagePosition());
-
-        mStageCoordinator.moveToStage(task, STAGE_TYPE_SIDE, SPLIT_POSITION_BOTTOM_OR_RIGHT,
-                new WindowContainerTransaction());
-        verify(mSideStage).addTask(eq(task), any(WindowContainerTransaction.class));
+        mStageCoordinator.moveToStage(task, SPLIT_POSITION_BOTTOM_OR_RIGHT, wct);
+        verify(mSideStage).addTask(eq(task), eq(wct));
         assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getSideStagePosition());
+        assertEquals(SPLIT_POSITION_TOP_OR_LEFT, mStageCoordinator.getMainStagePosition());
     }
 
     @Test
-    public void testMoveToUndefinedStage() {
-        final ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().build();
-
-        // Verify move to undefined stage while split screen not activated moves task to side stage.
-        when(mStageCoordinator.isSplitScreenVisible()).thenReturn(false);
-        mStageCoordinator.setSideStagePosition(SPLIT_POSITION_TOP_OR_LEFT, null);
-        mStageCoordinator.moveToStage(task, STAGE_TYPE_UNDEFINED, SPLIT_POSITION_BOTTOM_OR_RIGHT,
-                new WindowContainerTransaction());
-        verify(mSideStage).addTask(eq(task), any(WindowContainerTransaction.class));
-        assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getSideStagePosition());
-
-        // Verify move to undefined stage after split screen activated moves task based on position.
+    public void testMoveToStage_splitActiveForeground() {
+        when(mStageCoordinator.isSplitActive()).thenReturn(true);
         when(mStageCoordinator.isSplitScreenVisible()).thenReturn(true);
-        assertEquals(SPLIT_POSITION_TOP_OR_LEFT, mStageCoordinator.getMainStagePosition());
-        mStageCoordinator.moveToStage(task, STAGE_TYPE_UNDEFINED, SPLIT_POSITION_TOP_OR_LEFT,
-                new WindowContainerTransaction());
-        verify(mMainStage).addTask(eq(task), any(WindowContainerTransaction.class));
-        assertEquals(SPLIT_POSITION_TOP_OR_LEFT, mStageCoordinator.getMainStagePosition());
+        // Assume current side stage is top or left.
+        mStageCoordinator.setSideStagePosition(SPLIT_POSITION_TOP_OR_LEFT, null);
+
+        final ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().build();
+        final WindowContainerTransaction wct = new WindowContainerTransaction();
+
+        mStageCoordinator.moveToStage(task, SPLIT_POSITION_BOTTOM_OR_RIGHT, wct);
+        verify(mMainStage).addTask(eq(task), eq(wct));
+        assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getMainStagePosition());
+        assertEquals(SPLIT_POSITION_TOP_OR_LEFT, mStageCoordinator.getSideStagePosition());
+
+        mStageCoordinator.moveToStage(task, SPLIT_POSITION_TOP_OR_LEFT, wct);
+        verify(mSideStage).addTask(eq(task), eq(wct));
+        assertEquals(SPLIT_POSITION_TOP_OR_LEFT, mStageCoordinator.getSideStagePosition());
+        assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getMainStagePosition());
+    }
+
+    @Test
+    public void testMoveToStage_splitInctive() {
+        final ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().build();
+        final WindowContainerTransaction wct = new WindowContainerTransaction();
+
+        mStageCoordinator.moveToStage(task, SPLIT_POSITION_BOTTOM_OR_RIGHT, wct);
+        verify(mStageCoordinator).prepareEnterSplitScreen(eq(wct), eq(task),
+                eq(SPLIT_POSITION_BOTTOM_OR_RIGHT));
+        assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getSideStagePosition());
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/TaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/TaskPositionerTest.kt
index 8f66f4e..94c064b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/TaskPositionerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/TaskPositionerTest.kt
@@ -5,13 +5,16 @@
 import android.graphics.Rect
 import android.os.IBinder
 import android.testing.AndroidTestingRunner
+import android.view.Display
 import android.window.WindowContainerToken
+import android.window.WindowContainerTransaction
 import android.window.WindowContainerTransaction.Change.CHANGE_DRAG_RESIZING
 import androidx.test.filters.SmallTest
 import com.android.wm.shell.common.DisplayController
 import com.android.wm.shell.common.DisplayLayout
 import com.android.wm.shell.ShellTaskOrganizer
 import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.windowdecor.TaskPositioner.CTRL_TYPE_BOTTOM
 import com.android.wm.shell.windowdecor.TaskPositioner.CTRL_TYPE_RIGHT
 import com.android.wm.shell.windowdecor.TaskPositioner.CTRL_TYPE_TOP
 import com.android.wm.shell.windowdecor.TaskPositioner.CTRL_TYPE_UNDEFINED
@@ -19,10 +22,11 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.any
 import org.mockito.Mockito.argThat
 import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when`
 import org.mockito.MockitoAnnotations
 
 /**
@@ -51,6 +55,8 @@
     private lateinit var mockDisplayController: DisplayController
     @Mock
     private lateinit var mockDisplayLayout: DisplayLayout
+    @Mock
+    private lateinit var mockDisplay: Display
 
     private lateinit var taskPositioner: TaskPositioner
 
@@ -68,6 +74,9 @@
         `when`(taskToken.asBinder()).thenReturn(taskBinder)
         `when`(mockDisplayController.getDisplayLayout(DISPLAY_ID)).thenReturn(mockDisplayLayout)
         `when`(mockDisplayLayout.densityDpi()).thenReturn(DENSITY_DPI)
+        `when`(mockDisplayLayout.getStableBounds(any())).thenAnswer { i ->
+            (i.arguments.first() as Rect).set(STABLE_BOUNDS)
+        }
 
         mockWindowDecoration.mTaskInfo = ActivityManager.RunningTaskInfo().apply {
             taskId = TASK_ID
@@ -78,6 +87,8 @@
             displayId = DISPLAY_ID
             configuration.windowConfiguration.bounds = STARTING_BOUNDS
         }
+        mockWindowDecoration.mDisplay = mockDisplay
+        `when`(mockDisplay.displayId).thenAnswer { DISPLAY_ID }
     }
 
     @Test
@@ -451,6 +462,72 @@
         })
     }
 
+    fun testDragResize_toDisallowedBounds_freezesAtLimit() {
+        taskPositioner.onDragPositioningStart(
+                CTRL_TYPE_RIGHT or CTRL_TYPE_BOTTOM, // Resize right-bottom corner
+                STARTING_BOUNDS.right.toFloat(),
+                STARTING_BOUNDS.bottom.toFloat()
+        )
+
+        // Resize the task by 10px to the right and bottom, a valid destination
+        val newBounds = Rect(
+                STARTING_BOUNDS.left,
+                STARTING_BOUNDS.top,
+                STARTING_BOUNDS.right + 10,
+                STARTING_BOUNDS.bottom + 10)
+        taskPositioner.onDragPositioningMove(
+                newBounds.right.toFloat(),
+                newBounds.bottom.toFloat()
+        )
+
+        // Resize the task by another 10px to the right (allowed) and to just in the disallowed
+        // area of the Y coordinate.
+        val newBounds2 = Rect(
+                newBounds.left,
+                newBounds.top,
+                newBounds.right + 10,
+                DISALLOWED_RESIZE_AREA.top
+        )
+        taskPositioner.onDragPositioningMove(
+                newBounds2.right.toFloat(),
+                newBounds2.bottom.toFloat()
+        )
+
+        taskPositioner.onDragPositioningEnd(newBounds2.right.toFloat(), newBounds2.bottom.toFloat())
+
+        // The first resize falls in the allowed area, verify there's a change for it.
+        verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
+            return@argThat wct.changes.any { (token, change) ->
+                token == taskBinder && change.ofBounds(newBounds)
+            }
+        })
+        // The second resize falls in the disallowed area, verify there's no change for it.
+        verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct ->
+            return@argThat wct.changes.any { (token, change) ->
+                token == taskBinder && change.ofBounds(newBounds2)
+            }
+        })
+        // Instead, there should be a change for its allowed portion (the X movement) with the Y
+        // staying frozen in the last valid resize position.
+        verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
+            return@argThat wct.changes.any { (token, change) ->
+                token == taskBinder && change.ofBounds(
+                        Rect(
+                                newBounds2.left,
+                                newBounds2.top,
+                                newBounds2.right,
+                                newBounds.bottom // Stayed at the first resize destination.
+                        )
+                )
+            }
+        })
+    }
+
+    private fun WindowContainerTransaction.Change.ofBounds(bounds: Rect): Boolean {
+        return ((windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0) &&
+                bounds == configuration.windowConfiguration.bounds
+    }
+
     companion object {
         private const val TASK_ID = 5
         private const val MIN_WIDTH = 10
@@ -458,6 +535,19 @@
         private const val DENSITY_DPI = 20
         private const val DEFAULT_MIN = 40
         private const val DISPLAY_ID = 1
+        private const val NAVBAR_HEIGHT = 50
+        private val DISPLAY_BOUNDS = Rect(0, 0, 2400, 1600)
         private val STARTING_BOUNDS = Rect(0, 0, 100, 100)
+        private val DISALLOWED_RESIZE_AREA = Rect(
+                DISPLAY_BOUNDS.left,
+                DISPLAY_BOUNDS.bottom - NAVBAR_HEIGHT,
+                DISPLAY_BOUNDS.right,
+                DISPLAY_BOUNDS.bottom)
+        private val STABLE_BOUNDS = Rect(
+                DISPLAY_BOUNDS.left,
+                DISPLAY_BOUNDS.top,
+                DISPLAY_BOUNDS.right,
+                DISPLAY_BOUNDS.bottom - NAVBAR_HEIGHT
+        )
     }
 }
diff --git a/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.java b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.java
index 5ecec4d..3125f08 100644
--- a/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.java
+++ b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.java
@@ -72,6 +72,7 @@
     public static final int AMBIENT_LIGHT_MODE_LOW_LIGHT = 2;
 
     private final DreamManager mDreamManager;
+    private final LowLightTransitionCoordinator mLowLightTransitionCoordinator;
 
     @Nullable
     private final ComponentName mLowLightDreamComponent;
@@ -81,8 +82,10 @@
     @Inject
     public LowLightDreamManager(
             DreamManager dreamManager,
+            LowLightTransitionCoordinator lowLightTransitionCoordinator,
             @Named(LOW_LIGHT_DREAM_COMPONENT) @Nullable ComponentName lowLightDreamComponent) {
         mDreamManager = dreamManager;
+        mLowLightTransitionCoordinator = lowLightTransitionCoordinator;
         mLowLightDreamComponent = lowLightDreamComponent;
     }
 
@@ -111,7 +114,9 @@
 
         mAmbientLightMode = ambientLightMode;
 
-        mDreamManager.setSystemDreamComponent(mAmbientLightMode == AMBIENT_LIGHT_MODE_LOW_LIGHT
-                ? mLowLightDreamComponent : null);
+        boolean shouldEnterLowLight = mAmbientLightMode == AMBIENT_LIGHT_MODE_LOW_LIGHT;
+        mLowLightTransitionCoordinator.notifyBeforeLowLightTransition(shouldEnterLowLight,
+                () -> mDreamManager.setSystemDreamComponent(
+                        shouldEnterLowLight ? mLowLightDreamComponent : null));
     }
 }
diff --git a/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.java b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.java
new file mode 100644
index 0000000..874a2d5
--- /dev/null
+++ b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dream.lowlight;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.annotation.Nullable;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Helper class that allows listening and running animations before entering or exiting low light.
+ */
+@Singleton
+public class LowLightTransitionCoordinator {
+    /**
+     * Listener that is notified before low light entry.
+     */
+    public interface LowLightEnterListener {
+        /**
+         * Callback that is notified before the device enters low light.
+         *
+         * @return an optional animator that will be waited upon before entering low light.
+         */
+        Animator onBeforeEnterLowLight();
+    }
+
+    /**
+     * Listener that is notified before low light exit.
+     */
+    public interface LowLightExitListener {
+        /**
+         * Callback that is notified before the device exits low light.
+         *
+         * @return an optional animator that will be waited upon before exiting low light.
+         */
+        Animator onBeforeExitLowLight();
+    }
+
+    private LowLightEnterListener mLowLightEnterListener;
+    private LowLightExitListener mLowLightExitListener;
+
+    @Inject
+    public LowLightTransitionCoordinator() {
+    }
+
+    /**
+     * Sets the listener for the low light enter event.
+     *
+     * Only one listener can be set at a time. This method will overwrite any previously set
+     * listener. Null can be used to unset the listener.
+     */
+    public void setLowLightEnterListener(@Nullable LowLightEnterListener lowLightEnterListener) {
+        mLowLightEnterListener = lowLightEnterListener;
+    }
+
+    /**
+     * Sets the listener for the low light exit event.
+     *
+     * Only one listener can be set at a time. This method will overwrite any previously set
+     * listener. Null can be used to unset the listener.
+     */
+    public void setLowLightExitListener(@Nullable LowLightExitListener lowLightExitListener) {
+        mLowLightExitListener = lowLightExitListener;
+    }
+
+    /**
+     * Notifies listeners that the device is about to enter or exit low light.
+     *
+     * @param entering true if listeners should be notified before entering low light, false if this
+     *                 is notifying before exiting.
+     * @param callback callback that will be run after listeners complete.
+     */
+    void notifyBeforeLowLightTransition(boolean entering, Runnable callback) {
+        Animator animator = null;
+
+        if (entering && mLowLightEnterListener != null) {
+            animator = mLowLightEnterListener.onBeforeEnterLowLight();
+        } else if (!entering && mLowLightExitListener != null) {
+            animator = mLowLightExitListener.onBeforeExitLowLight();
+        }
+
+        // If the listener returned an animator to indicate it was running an animation, run the
+        // callback after the animation completes, otherwise call the callback directly.
+        if (animator != null) {
+            animator.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animator) {
+                    callback.run();
+                }
+            });
+        } else {
+            callback.run();
+        }
+    }
+}
diff --git a/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.java b/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.java
index 91a170f..4b95d8c 100644
--- a/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.java
+++ b/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.java
@@ -21,7 +21,10 @@
 import static com.android.dream.lowlight.LowLightDreamManager.AMBIENT_LIGHT_MODE_UNKNOWN;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 
@@ -44,44 +47,52 @@
     private DreamManager mDreamManager;
 
     @Mock
+    private LowLightTransitionCoordinator mTransitionCoordinator;
+
+    @Mock
     private ComponentName mDreamComponent;
 
+    LowLightDreamManager mLowLightDreamManager;
+
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
+
+        // Automatically run any provided Runnable to mTransitionCoordinator to simplify testing.
+        doAnswer(invocation -> {
+            ((Runnable) invocation.getArgument(1)).run();
+            return null;
+        }).when(mTransitionCoordinator).notifyBeforeLowLightTransition(anyBoolean(),
+                any(Runnable.class));
+
+        mLowLightDreamManager = new LowLightDreamManager(mDreamManager, mTransitionCoordinator,
+                mDreamComponent);
     }
 
     @Test
     public void setAmbientLightMode_lowLight_setSystemDream() {
-        final LowLightDreamManager lowLightDreamManager = new LowLightDreamManager(mDreamManager,
-                mDreamComponent);
+        mLowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_LOW_LIGHT);
 
-        lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_LOW_LIGHT);
-
+        verify(mTransitionCoordinator).notifyBeforeLowLightTransition(eq(true), any());
         verify(mDreamManager).setSystemDreamComponent(mDreamComponent);
     }
 
     @Test
     public void setAmbientLightMode_regularLight_clearSystemDream() {
-        final LowLightDreamManager lowLightDreamManager = new LowLightDreamManager(mDreamManager,
-                mDreamComponent);
+        mLowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_REGULAR);
 
-        lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_REGULAR);
-
+        verify(mTransitionCoordinator).notifyBeforeLowLightTransition(eq(false), any());
         verify(mDreamManager).setSystemDreamComponent(null);
     }
 
     @Test
     public void setAmbientLightMode_defaultUnknownMode_clearSystemDream() {
-        final LowLightDreamManager lowLightDreamManager = new LowLightDreamManager(mDreamManager,
-                mDreamComponent);
-
         // Set to low light first.
-        lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_LOW_LIGHT);
+        mLowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_LOW_LIGHT);
         clearInvocations(mDreamManager);
 
         // Return to default unknown mode.
-        lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_UNKNOWN);
+        mLowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_UNKNOWN);
 
         verify(mDreamManager).setSystemDreamComponent(null);
     }
@@ -89,7 +100,7 @@
     @Test
     public void setAmbientLightMode_dreamComponentNotSet_doNothing() {
         final LowLightDreamManager lowLightDreamManager = new LowLightDreamManager(mDreamManager,
-                null /*dream component*/);
+                mTransitionCoordinator, null /*dream component*/);
 
         lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_LOW_LIGHT);
 
diff --git a/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightTransitionCoordinatorTest.java b/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightTransitionCoordinatorTest.java
new file mode 100644
index 0000000..81e1e33
--- /dev/null
+++ b/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightTransitionCoordinatorTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dream.lowlight;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+import android.animation.Animator;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class LowLightTransitionCoordinatorTest {
+    @Mock
+    private LowLightTransitionCoordinator.LowLightEnterListener mEnterListener;
+
+    @Mock
+    private LowLightTransitionCoordinator.LowLightExitListener mExitListener;
+
+    @Mock
+    private Animator mAnimator;
+
+    @Captor
+    private ArgumentCaptor<Animator.AnimatorListener> mAnimatorListenerCaptor;
+
+    @Mock
+    private Runnable mRunnable;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void onEnterCalledOnListeners() {
+        LowLightTransitionCoordinator coordinator = new LowLightTransitionCoordinator();
+
+        coordinator.setLowLightEnterListener(mEnterListener);
+
+        coordinator.notifyBeforeLowLightTransition(true, mRunnable);
+
+        verify(mEnterListener).onBeforeEnterLowLight();
+        verify(mRunnable).run();
+    }
+
+    @Test
+    public void onExitCalledOnListeners() {
+        LowLightTransitionCoordinator coordinator = new LowLightTransitionCoordinator();
+
+        coordinator.setLowLightExitListener(mExitListener);
+
+        coordinator.notifyBeforeLowLightTransition(false, mRunnable);
+
+        verify(mExitListener).onBeforeExitLowLight();
+        verify(mRunnable).run();
+    }
+
+    @Test
+    public void listenerNotCalledAfterRemoval() {
+        LowLightTransitionCoordinator coordinator = new LowLightTransitionCoordinator();
+
+        coordinator.setLowLightEnterListener(mEnterListener);
+        coordinator.setLowLightEnterListener(null);
+
+        coordinator.notifyBeforeLowLightTransition(true, mRunnable);
+
+        verifyZeroInteractions(mEnterListener);
+        verify(mRunnable).run();
+    }
+
+    @Test
+    public void runnableCalledAfterAnimationEnds() {
+        when(mEnterListener.onBeforeEnterLowLight()).thenReturn(mAnimator);
+
+        LowLightTransitionCoordinator coordinator = new LowLightTransitionCoordinator();
+        coordinator.setLowLightEnterListener(mEnterListener);
+
+        coordinator.notifyBeforeLowLightTransition(true, mRunnable);
+
+        // Animator listener is added and the runnable is not run yet.
+        verify(mAnimator).addListener(mAnimatorListenerCaptor.capture());
+        verifyZeroInteractions(mRunnable);
+
+        // Runnable is run once the animation ends.
+        mAnimatorListenerCaptor.getValue().onAnimationEnd(null);
+        verify(mRunnable).run();
+    }
+}
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index a285462..d101a1b 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -39,6 +39,9 @@
 #include "VectorDrawable.h"
 #include "pipeline/skia/AnimatedDrawables.h"
 #include "pipeline/skia/FunctorDrawable.h"
+#ifdef __ANDROID__
+#include "renderthread/CanvasContext.h"
+#endif
 
 namespace android {
 namespace uirenderer {
@@ -434,7 +437,19 @@
     size_t count;
     SkPaint paint;
     void draw(SkCanvas* c, const SkMatrix&) const {
-        c->drawPoints(mode, count, pod<SkPoint>(this), paint);
+        if (paint.isAntiAlias()) {
+            c->drawPoints(mode, count, pod<SkPoint>(this), paint);
+        } else {
+            c->save();
+#ifdef __ANDROID__
+            auto pixelSnap = renderthread::CanvasContext::getActiveContext()->getPixelSnapMatrix();
+            auto transform = c->getLocalToDevice();
+            transform.postConcat(pixelSnap);
+            c->setMatrix(transform);
+#endif
+            c->drawPoints(mode, count, pod<SkPoint>(this), paint);
+            c->restore();
+        }
     }
 };
 struct DrawVertices final : Op {
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
index a80c613..fe41420 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
@@ -53,6 +53,14 @@
     bool isSurfaceReady() override;
     bool isContextReady() override;
 
+    const SkM44& getPixelSnapMatrix() const override {
+        // Small (~1/16th) nudge to ensure that pixel-aligned non-AA'd draws fill the
+        // desired fragment
+        static const SkScalar kOffset = 0.063f;
+        static const SkM44 sSnapMatrix = SkM44::Translate(kOffset, kOffset);
+        return sSnapMatrix;
+    }
+
     static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor);
 
 protected:
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index cc2565d..18e0b91 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -180,6 +180,10 @@
     }
 }
 
+const SkM44& SkiaVulkanPipeline::getPixelSnapMatrix() const {
+    return mVkSurface->getPixelSnapMatrix();
+}
+
 } /* namespace skiapipeline */
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
index a6e685d..7c8f65b 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -49,6 +49,7 @@
     void onStop() override;
     bool isSurfaceReady() override;
     bool isContextReady() override;
+    const SkM44& getPixelSnapMatrix() const override;
 
     static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor);
     static sk_sp<Bitmap> allocateHardwareBitmap(renderthread::RenderThread& thread,
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 602554a..f56d19b 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -793,6 +793,10 @@
     return size;
 }
 
+const SkM44& CanvasContext::getPixelSnapMatrix() const {
+    return mRenderPipeline->getPixelSnapMatrix();
+}
+
 void CanvasContext::prepareAndDraw(RenderNode* node) {
     ATRACE_CALL();
 
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 951ee21..d85e579 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -195,6 +195,9 @@
 
     SkISize getNextFrameSize() const;
 
+    // Returns the matrix to use to nudge non-AA'd points/lines towards the fragment center
+    const SkM44& getPixelSnapMatrix() const;
+
     // Called when SurfaceStats are available.
     static void onSurfaceStatsAvailable(void* context, int32_t surfaceControlId,
                                         ASurfaceControlStats* stats);
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index ef58bc5..54adec2 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -88,6 +88,8 @@
     virtual void setPictureCapturedCallback(
             const std::function<void(sk_sp<SkPicture>&&)>& callback) = 0;
 
+    virtual const SkM44& getPixelSnapMatrix() const = 0;
+
     virtual ~IRenderPipeline() {}
 };
 
diff --git a/libs/hwui/renderthread/VulkanSurface.cpp b/libs/hwui/renderthread/VulkanSurface.cpp
index 7dd3561..666f329 100644
--- a/libs/hwui/renderthread/VulkanSurface.cpp
+++ b/libs/hwui/renderthread/VulkanSurface.cpp
@@ -63,6 +63,18 @@
     return SkMatrix::I();
 }
 
+static SkM44 GetPixelSnapMatrix(SkISize windowSize, int transform) {
+    // Small (~1/16th) nudge to ensure that pixel-aligned non-AA'd draws fill the
+    // desired fragment
+    static const SkScalar kOffset = 0.063f;
+    SkMatrix preRotation = GetPreTransformMatrix(windowSize, transform);
+    SkMatrix invert;
+    LOG_ALWAYS_FATAL_IF(!preRotation.invert(&invert));
+    return SkM44::Translate(kOffset, kOffset)
+            .postConcat(SkM44(preRotation))
+            .preConcat(SkM44(invert));
+}
+
 static bool ConnectAndSetWindowDefaults(ANativeWindow* window) {
     ATRACE_CALL();
 
@@ -178,6 +190,8 @@
 
     outWindowInfo->preTransform =
             GetPreTransformMatrix(outWindowInfo->size, outWindowInfo->transform);
+    outWindowInfo->pixelSnapMatrix =
+            GetPixelSnapMatrix(outWindowInfo->size, outWindowInfo->transform);
 
     err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value);
     if (err != 0 || query_value < 0) {
@@ -406,6 +420,7 @@
         }
 
         mWindowInfo.preTransform = GetPreTransformMatrix(mWindowInfo.size, mWindowInfo.transform);
+        mWindowInfo.pixelSnapMatrix = GetPixelSnapMatrix(mWindowInfo.size, mWindowInfo.transform);
     }
 
     uint32_t idx;
diff --git a/libs/hwui/renderthread/VulkanSurface.h b/libs/hwui/renderthread/VulkanSurface.h
index beb71b72..b8ccf78 100644
--- a/libs/hwui/renderthread/VulkanSurface.h
+++ b/libs/hwui/renderthread/VulkanSurface.h
@@ -45,6 +45,8 @@
     }
     const SkMatrix& getCurrentPreTransform() { return mWindowInfo.preTransform; }
 
+    const SkM44& getPixelSnapMatrix() const { return mWindowInfo.pixelSnapMatrix; }
+
 private:
     /*
      * All structs/methods in this private section are specifically for use by the VulkanManager
@@ -101,6 +103,7 @@
         SkISize actualSize;
         // transform to be applied to the SkSurface to map the coordinates to the provided transform
         SkMatrix preTransform;
+        SkM44 pixelSnapMatrix;
     };
 
     VulkanSurface(ANativeWindow* window, const WindowInfo& windowInfo, GrDirectContext* grContext);
diff --git a/media/java/android/media/projection/OWNERS b/media/java/android/media/projection/OWNERS
index 9ca3910..2273f81 100644
--- a/media/java/android/media/projection/OWNERS
+++ b/media/java/android/media/projection/OWNERS
@@ -1,2 +1,4 @@
 michaelwr@google.com
 santoscordon@google.com
+chaviw@google.com
+nmusgrave@google.com
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
index 2b7bcbe..cc7a7d5 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
@@ -161,7 +161,8 @@
                             ICameraService.USE_CALLING_UID,
                             ICameraService.USE_CALLING_PID,
                             getContext().getApplicationInfo().targetSdkVersion,
-                            /*overrideToPortrait*/false);
+                            /*overrideToPortrait*/false,
+                            /*forceSlowJpegMode*/false);
             assertNotNull(String.format("Camera %s was null", cameraId), cameraUser);
 
             Log.v(TAG, String.format("Camera %s connected", cameraId));
diff --git a/packages/CompanionDeviceManager/res/values-vi/strings.xml b/packages/CompanionDeviceManager/res/values-vi/strings.xml
index 4306614..854bbb5 100644
--- a/packages/CompanionDeviceManager/res/values-vi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-vi/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
+    <string name="app_label" msgid="4470785958457506021">"Trình quản lý thiết bị đồng hành"</string>
     <string name="confirmation_title" msgid="3785000297483688997">"Cho phép &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; truy cập &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; của bạn"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"đồng hồ"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Chọn một <xliff:g id="PROFILE_NAME">%1$s</xliff:g> sẽ do &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; quản lý"</string>
diff --git a/packages/SettingsLib/DeviceStateRotationLock/Android.bp b/packages/SettingsLib/DeviceStateRotationLock/Android.bp
index c642bd1..103309a 100644
--- a/packages/SettingsLib/DeviceStateRotationLock/Android.bp
+++ b/packages/SettingsLib/DeviceStateRotationLock/Android.bp
@@ -10,7 +10,10 @@
 android_library {
     name: "SettingsLibDeviceStateRotationLock",
 
-    srcs: ["src/**/*.java"],
+    srcs: [
+        "src/**/*.java",
+        "src/**/*.kt",
+    ],
 
     min_sdk_version: "21",
 }
diff --git a/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/DeviceStateRotationLockSettingsManager.java b/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/DeviceStateRotationLockSettingsManager.java
index 4ed7e19..76e1df1 100644
--- a/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/DeviceStateRotationLockSettingsManager.java
+++ b/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/DeviceStateRotationLockSettingsManager.java
@@ -29,6 +29,7 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.TextUtils;
+import android.util.IndentingPrintWriter;
 import android.util.Log;
 import android.util.SparseIntArray;
 
@@ -36,6 +37,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
@@ -55,16 +57,19 @@
     private final Handler mMainHandler = new Handler(Looper.getMainLooper());
     private final Set<DeviceStateRotationLockSettingsListener> mListeners = new HashSet<>();
     private final SecureSettings mSecureSettings;
-    private String[] mDeviceStateRotationLockDefaults;
-    private SparseIntArray mDeviceStateRotationLockSettings;
-    private SparseIntArray mDeviceStateRotationLockFallbackSettings;
+    private final PosturesHelper mPosturesHelper;
+    private String[] mPostureRotationLockDefaults;
+    private SparseIntArray mPostureRotationLockSettings;
+    private SparseIntArray mPostureDefaultRotationLockSettings;
+    private SparseIntArray mPostureRotationLockFallbackSettings;
     private String mLastSettingValue;
     private List<SettableDeviceState> mSettableDeviceStates;
 
     @VisibleForTesting
     DeviceStateRotationLockSettingsManager(Context context, SecureSettings secureSettings) {
-        this.mSecureSettings = secureSettings;
-        mDeviceStateRotationLockDefaults =
+        mSecureSettings = secureSettings;
+        mPosturesHelper = new PosturesHelper(context);
+        mPostureRotationLockDefaults =
                 context.getResources()
                         .getStringArray(R.array.config_perDeviceStateRotationLockDefaults);
         loadDefaults();
@@ -93,9 +98,7 @@
     /** Returns true if device-state based rotation lock settings are enabled. */
     public static boolean isDeviceStateRotationLockEnabled(Context context) {
         return context.getResources()
-                        .getStringArray(R.array.config_perDeviceStateRotationLockDefaults)
-                        .length
-                > 0;
+                .getStringArray(R.array.config_perDeviceStateRotationLockDefaults).length > 0;
     }
 
     private void listenForSettingsChange() {
@@ -133,13 +136,14 @@
 
     /** Updates the rotation lock setting for a specified device state. */
     public void updateSetting(int deviceState, boolean rotationLocked) {
-        if (mDeviceStateRotationLockFallbackSettings.indexOfKey(deviceState) >= 0) {
-            // The setting for this device state is IGNORED, and has a fallback device state.
-            // The setting for that fallback device state should be the changed in this case.
-            deviceState = mDeviceStateRotationLockFallbackSettings.get(deviceState);
+        int posture = mPosturesHelper.deviceStateToPosture(deviceState);
+        if (mPostureRotationLockFallbackSettings.indexOfKey(posture) >= 0) {
+            // The setting for this device posture is IGNORED, and has a fallback posture.
+            // The setting for that fallback posture should be the changed in this case.
+            posture = mPostureRotationLockFallbackSettings.get(posture);
         }
-        mDeviceStateRotationLockSettings.put(
-                deviceState,
+        mPostureRotationLockSettings.put(
+                posture,
                 rotationLocked
                         ? DEVICE_STATE_ROTATION_LOCK_LOCKED
                         : DEVICE_STATE_ROTATION_LOCK_UNLOCKED);
@@ -158,22 +162,23 @@
      */
     @Settings.Secure.DeviceStateRotationLockSetting
     public int getRotationLockSetting(int deviceState) {
-        int rotationLockSetting = mDeviceStateRotationLockSettings.get(
-                deviceState, /* valueIfKeyNotFound= */ DEVICE_STATE_ROTATION_LOCK_IGNORED);
+        int devicePosture = mPosturesHelper.deviceStateToPosture(deviceState);
+        int rotationLockSetting = mPostureRotationLockSettings.get(
+                devicePosture, /* valueIfKeyNotFound= */ DEVICE_STATE_ROTATION_LOCK_IGNORED);
         if (rotationLockSetting == DEVICE_STATE_ROTATION_LOCK_IGNORED) {
-            rotationLockSetting = getFallbackRotationLockSetting(deviceState);
+            rotationLockSetting = getFallbackRotationLockSetting(devicePosture);
         }
         return rotationLockSetting;
     }
 
-    private int getFallbackRotationLockSetting(int deviceState) {
-        int indexOfFallbackState = mDeviceStateRotationLockFallbackSettings.indexOfKey(deviceState);
-        if (indexOfFallbackState < 0) {
+    private int getFallbackRotationLockSetting(int devicePosture) {
+        int indexOfFallback = mPostureRotationLockFallbackSettings.indexOfKey(devicePosture);
+        if (indexOfFallback < 0) {
             Log.w(TAG, "Setting is ignored, but no fallback was specified.");
             return DEVICE_STATE_ROTATION_LOCK_IGNORED;
         }
-        int fallbackState = mDeviceStateRotationLockFallbackSettings.valueAt(indexOfFallbackState);
-        return mDeviceStateRotationLockSettings.get(fallbackState,
+        int fallbackPosture = mPostureRotationLockFallbackSettings.valueAt(indexOfFallback);
+        return mPostureRotationLockSettings.get(fallbackPosture,
                 /* valueIfKeyNotFound= */ DEVICE_STATE_ROTATION_LOCK_IGNORED);
     }
 
@@ -188,8 +193,8 @@
      * DEVICE_STATE_ROTATION_LOCK_UNLOCKED}.
      */
     public boolean isRotationLockedForAllStates() {
-        for (int i = 0; i < mDeviceStateRotationLockSettings.size(); i++) {
-            if (mDeviceStateRotationLockSettings.valueAt(i)
+        for (int i = 0; i < mPostureRotationLockSettings.size(); i++) {
+            if (mPostureRotationLockSettings.valueAt(i)
                     == DEVICE_STATE_ROTATION_LOCK_UNLOCKED) {
                 return false;
             }
@@ -220,7 +225,7 @@
             fallbackOnDefaults();
             return;
         }
-        mDeviceStateRotationLockSettings = new SparseIntArray(values.length / 2);
+        mPostureRotationLockSettings = new SparseIntArray(values.length / 2);
         int key;
         int value;
 
@@ -228,7 +233,16 @@
             try {
                 key = Integer.parseInt(values[i++]);
                 value = Integer.parseInt(values[i++]);
-                mDeviceStateRotationLockSettings.put(key, value);
+                boolean isPersistedValueIgnored = value == DEVICE_STATE_ROTATION_LOCK_IGNORED;
+                boolean isDefaultValueIgnored = mPostureDefaultRotationLockSettings.get(key)
+                        == DEVICE_STATE_ROTATION_LOCK_IGNORED;
+                if (isPersistedValueIgnored != isDefaultValueIgnored) {
+                    Log.w(TAG, "Conflict for ignored device state " + key
+                            + ". Falling back on defaults");
+                    fallbackOnDefaults();
+                    return;
+                }
+                mPostureRotationLockSettings.put(key, value);
             } catch (NumberFormatException e) {
                 Log.wtf(TAG, "Error deserializing one of the saved settings", e);
                 fallbackOnDefaults();
@@ -243,7 +257,7 @@
      */
     @VisibleForTesting
     public void resetStateForTesting(Resources resources) {
-        mDeviceStateRotationLockDefaults =
+        mPostureRotationLockDefaults =
                 resources.getStringArray(R.array.config_perDeviceStateRotationLockDefaults);
         fallbackOnDefaults();
     }
@@ -254,28 +268,31 @@
     }
 
     private void persistSettings() {
-        if (mDeviceStateRotationLockSettings.size() == 0) {
+        if (mPostureRotationLockSettings.size() == 0) {
             persistSettingIfChanged(/* newSettingValue= */ "");
             return;
         }
 
         StringBuilder stringBuilder = new StringBuilder();
         stringBuilder
-                .append(mDeviceStateRotationLockSettings.keyAt(0))
+                .append(mPostureRotationLockSettings.keyAt(0))
                 .append(SEPARATOR_REGEX)
-                .append(mDeviceStateRotationLockSettings.valueAt(0));
+                .append(mPostureRotationLockSettings.valueAt(0));
 
-        for (int i = 1; i < mDeviceStateRotationLockSettings.size(); i++) {
+        for (int i = 1; i < mPostureRotationLockSettings.size(); i++) {
             stringBuilder
                     .append(SEPARATOR_REGEX)
-                    .append(mDeviceStateRotationLockSettings.keyAt(i))
+                    .append(mPostureRotationLockSettings.keyAt(i))
                     .append(SEPARATOR_REGEX)
-                    .append(mDeviceStateRotationLockSettings.valueAt(i));
+                    .append(mPostureRotationLockSettings.valueAt(i));
         }
         persistSettingIfChanged(stringBuilder.toString());
     }
 
     private void persistSettingIfChanged(String newSettingValue) {
+        Log.v(TAG, "persistSettingIfChanged: "
+                + "last=" + mLastSettingValue + ", "
+                + "new=" + newSettingValue);
         if (TextUtils.equals(mLastSettingValue, newSettingValue)) {
             return;
         }
@@ -287,20 +304,20 @@
     }
 
     private void loadDefaults() {
-        mSettableDeviceStates = new ArrayList<>(mDeviceStateRotationLockDefaults.length);
-        mDeviceStateRotationLockSettings = new SparseIntArray(
-                mDeviceStateRotationLockDefaults.length);
-        mDeviceStateRotationLockFallbackSettings = new SparseIntArray(1);
-        for (String entry : mDeviceStateRotationLockDefaults) {
+        mSettableDeviceStates = new ArrayList<>(mPostureRotationLockDefaults.length);
+        mPostureDefaultRotationLockSettings = new SparseIntArray(
+                mPostureRotationLockDefaults.length);
+        mPostureRotationLockSettings = new SparseIntArray(mPostureRotationLockDefaults.length);
+        mPostureRotationLockFallbackSettings = new SparseIntArray(1);
+        for (String entry : mPostureRotationLockDefaults) {
             String[] values = entry.split(SEPARATOR_REGEX);
             try {
-                int deviceState = Integer.parseInt(values[0]);
+                int posture = Integer.parseInt(values[0]);
                 int rotationLockSetting = Integer.parseInt(values[1]);
                 if (rotationLockSetting == DEVICE_STATE_ROTATION_LOCK_IGNORED) {
                     if (values.length == 3) {
-                        int fallbackDeviceState = Integer.parseInt(values[2]);
-                        mDeviceStateRotationLockFallbackSettings.put(deviceState,
-                                fallbackDeviceState);
+                        int fallbackPosture = Integer.parseInt(values[2]);
+                        mPostureRotationLockFallbackSettings.put(posture, fallbackPosture);
                     } else {
                         Log.w(TAG,
                                 "Rotation lock setting is IGNORED, but values have unexpected "
@@ -309,8 +326,14 @@
                     }
                 }
                 boolean isSettable = rotationLockSetting != DEVICE_STATE_ROTATION_LOCK_IGNORED;
-                mSettableDeviceStates.add(new SettableDeviceState(deviceState, isSettable));
-                mDeviceStateRotationLockSettings.put(deviceState, rotationLockSetting);
+                Integer deviceState = mPosturesHelper.postureToDeviceState(posture);
+                if (deviceState != null) {
+                    mSettableDeviceStates.add(new SettableDeviceState(deviceState, isSettable));
+                } else {
+                    Log.wtf(TAG, "No matching device state for posture: " + posture);
+                }
+                mPostureRotationLockSettings.put(posture, rotationLockSetting);
+                mPostureDefaultRotationLockSettings.put(posture, rotationLockSetting);
             } catch (NumberFormatException e) {
                 Log.wtf(TAG, "Error parsing settings entry. Entry was: " + entry, e);
                 return;
@@ -318,6 +341,20 @@
         }
     }
 
+    /** Dumps internal state. */
+    public void dump(IndentingPrintWriter pw) {
+        pw.println("DeviceStateRotationLockSettingsManager");
+        pw.increaseIndent();
+        pw.println("mPostureRotationLockDefaults: "
+                + Arrays.toString(mPostureRotationLockDefaults));
+        pw.println("mPostureDefaultRotationLockSettings: " + mPostureDefaultRotationLockSettings);
+        pw.println("mDeviceStateRotationLockSettings: " + mPostureRotationLockSettings);
+        pw.println("mPostureRotationLockFallbackSettings: " + mPostureRotationLockFallbackSettings);
+        pw.println("mSettableDeviceStates: " + mSettableDeviceStates);
+        pw.println("mLastSettingValue: " + mLastSettingValue);
+        pw.decreaseIndent();
+    }
+
     /**
      * Called when the persisted settings have changed, requiring a reinitialization of the
      * in-memory map.
@@ -372,5 +409,13 @@
         public int hashCode() {
             return Objects.hash(mDeviceState, mIsSettable);
         }
+
+        @Override
+        public String toString() {
+            return "SettableDeviceState{"
+                    + "mDeviceState=" + mDeviceState
+                    + ", mIsSettable=" + mIsSettable
+                    + '}';
+        }
     }
 }
diff --git a/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/PosturesHelper.kt b/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/PosturesHelper.kt
new file mode 100644
index 0000000..9c70be9
--- /dev/null
+++ b/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/PosturesHelper.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.devicestate
+
+import android.content.Context
+import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_FOLDED
+import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_HALF_FOLDED
+import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_UNFOLDED
+import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_UNKNOWN
+import android.provider.Settings.Secure.DeviceStateRotationLockKey
+import com.android.internal.R
+
+/** Helps to convert between device state and posture. */
+class PosturesHelper(context: Context) {
+
+    private val foldedDeviceStates =
+        context.resources.getIntArray(R.array.config_foldedDeviceStates)
+    private val halfFoldedDeviceStates =
+        context.resources.getIntArray(R.array.config_halfFoldedDeviceStates)
+    private val unfoldedDeviceStates =
+        context.resources.getIntArray(R.array.config_openDeviceStates)
+
+    @DeviceStateRotationLockKey
+    fun deviceStateToPosture(deviceState: Int): Int {
+        return when (deviceState) {
+            in foldedDeviceStates -> DEVICE_STATE_ROTATION_KEY_FOLDED
+            in halfFoldedDeviceStates -> DEVICE_STATE_ROTATION_KEY_HALF_FOLDED
+            in unfoldedDeviceStates -> DEVICE_STATE_ROTATION_KEY_UNFOLDED
+            else -> DEVICE_STATE_ROTATION_KEY_UNKNOWN
+        }
+    }
+
+    fun postureToDeviceState(@DeviceStateRotationLockKey posture: Int): Int? {
+        return when (posture) {
+            DEVICE_STATE_ROTATION_KEY_FOLDED -> foldedDeviceStates.firstOrNull()
+            DEVICE_STATE_ROTATION_KEY_HALF_FOLDED -> halfFoldedDeviceStates.firstOrNull()
+            DEVICE_STATE_ROTATION_KEY_UNFOLDED -> unfoldedDeviceStates.firstOrNull()
+            else -> null
+        }
+    }
+}
diff --git a/packages/SettingsLib/res/values-ar/arrays.xml b/packages/SettingsLib/res/values-ar/arrays.xml
index 27a236b..97a9109 100644
--- a/packages/SettingsLib/res/values-ar/arrays.xml
+++ b/packages/SettingsLib/res/values-ar/arrays.xml
@@ -60,7 +60,7 @@
   </string-array>
   <string-array name="bt_hci_snoop_log_entries">
     <item msgid="695678520785580527">"غير مفعّل"</item>
-    <item msgid="6336372935919715515">"تمّ تفعيل التصفية"</item>
+    <item msgid="6336372935919715515">"تمّ تفعيل الفلترة"</item>
     <item msgid="2779123106632690576">"مفعّل"</item>
   </string-array>
   <string-array name="bluetooth_avrcp_versions">
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 753ce73..0eb541a 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -476,7 +476,7 @@
     <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="4374784375644214578">"Es posible que el dispositivo se apague pronto (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string>
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> hasta la carga completa"</string>
-    <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> hasta la carga completa"</string>
+    <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> hasta la carga completa"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - Carga optimizada"</string>
     <string name="power_charging_future_paused" msgid="4730177778538118032">"<xliff:g id="LEVEL">%1$s</xliff:g> - Carga optimizada"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Desconocido"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index a37b500..8f3ef12 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -477,8 +477,8 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> guztiz kargatu arte"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> guztiz kargatu arte"</string>
-    <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - Kargatze optimizatua"</string>
-    <string name="power_charging_future_paused" msgid="4730177778538118032">"<xliff:g id="LEVEL">%1$s</xliff:g> - Kargatze optimizatua"</string>
+    <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - Kargatzeko modu optimizatua"</string>
+    <string name="power_charging_future_paused" msgid="4730177778538118032">"<xliff:g id="LEVEL">%1$s</xliff:g> - Kargatzeko modu optimizatua"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Ezezaguna"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Kargatzen"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Bizkor kargatzen"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 9d398ad..985dc66 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -278,7 +278,7 @@
     <string name="mock_location_app_set" msgid="4706722469342913843">"برنامه موقعیت مکانی ساختگی: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="debug_networking_category" msgid="6829757985772659599">"شبکه"</string>
     <string name="wifi_display_certification" msgid="1805579519992520381">"گواهینامه نمایش بی‌سیم"</string>
-    <string name="wifi_verbose_logging" msgid="1785910450009679371">"‏فعال کردن گزارش‌گیری طولانی Wi‑Fi"</string>
+    <string name="wifi_verbose_logging" msgid="1785910450009679371">"‏فعال کردن گزارش‌گیری مفصل Wi‑Fi"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"‏محدود کردن اسکن کردن Wi‑Fi"</string>
     <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"‏تصادفی‌سازی MAC غیرپایای Wi-Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"داده تلفن همراه همیشه فعال باشد"</string>
@@ -388,7 +388,7 @@
     <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>
+    <string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"فعال کردن گزارش‌گیری مفصل فروشنده"</string>
     <string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"شامل گزارشات اشکال تکمیلی ورود به سیستم فروشنده ویژه دستگاه می‌شود که ممکن است دربرگیرنده اطلاعات خصوصی، استفاده بیشتر از باتری، و/یا استفاده بیشتر از فضای ذخیره‌سازی باشد."</string>
     <string name="window_animation_scale_title" msgid="5236381298376812508">"مقیاس پویانمایی پنجره"</string>
     <string name="transition_animation_scale_title" msgid="1278477690695439337">"مقیاس پویانمایی انتقالی"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index e93b87c..51d2bcf 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -477,8 +477,8 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"完了まであと <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - 完了まであと <xliff:g id="TIME">%2$s</xliff:g>"</string>
-    <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - 充電最適化済み"</string>
-    <string name="power_charging_future_paused" msgid="4730177778538118032">"<xliff:g id="LEVEL">%1$s</xliff:g> - 充電最適化済み"</string>
+    <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - 充電が最適化されています"</string>
+    <string name="power_charging_future_paused" msgid="4730177778538118032">"<xliff:g id="LEVEL">%1$s</xliff:g> - 充電が最適化されています"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"不明"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"充電中"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"急速充電中"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index e8092d0..7994c11 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -477,7 +477,7 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Толық зарядталғанға дейін <xliff:g id="TIME">%1$s</xliff:g> қалды."</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – толық зарядталғанға дейін <xliff:g id="TIME">%2$s</xliff:g> қалды."</string>
-    <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> – зарядтау оңтайландырылды."</string>
+    <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> – зарядтау оңтайландырылды"</string>
     <string name="power_charging_future_paused" msgid="4730177778538118032">"<xliff:g id="LEVEL">%1$s</xliff:g> – зарядтау оңтайландырылды."</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Белгісіз"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Зарядталуда"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 145dc5d..8618438 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -255,12 +255,12 @@
     <string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Wi‑Fi-tilkoblingskode"</string>
     <string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"Tilkoblingen mislyktes"</string>
     <string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"Sørg for at enheten er koblet til samme nettverk."</string>
-    <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Koble til enheten via Wifi ved å skanne en QR-kode"</string>
+    <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Koble til enheten via wifi ved å skanne en QR-kode"</string>
     <string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"Kobler til enheten …"</string>
     <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Kunne ikke koble til enheten. Enten var QR-koden feil, eller enheten er ikke koblet til samme nettverk."</string>
     <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP-adresse og port"</string>
     <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Skann QR-koden"</string>
-    <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Koble til enheten via Wifi ved å skanne en QR-kode"</string>
+    <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Koble til enheten via wifi ved å skanne en QR-kode"</string>
     <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Koble til et Wifi-nettverk"</string>
     <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, feilsøking, utvikler"</string>
     <string name="bugreport_in_power" msgid="8664089072534638709">"Snarvei til feilrapport"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/arrays.xml b/packages/SettingsLib/res/values-pt-rPT/arrays.xml
index 8b63f7f..81658f4 100644
--- a/packages/SettingsLib/res/values-pt-rPT/arrays.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/arrays.xml
@@ -55,7 +55,7 @@
   </string-array>
   <string-array name="hdcp_checking_summaries">
     <item msgid="4045840870658484038">"Nunca utilizar a verificação HDCP"</item>
-    <item msgid="8254225038262324761">"Utilizar a verificação HDCP para conteúdo DRM apenas"</item>
+    <item msgid="8254225038262324761">"Usar a verificação HDCP para conteúdo DRM apenas"</item>
     <item msgid="6421717003037072581">"Usar sempre a verificação HDCP"</item>
   </string-array>
   <string-array name="bt_hci_snoop_log_entries">
@@ -86,7 +86,7 @@
     <item msgid="8147982633566548515">"map14"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="2494959071796102843">"Utilizar seleção do sistema (predefinido)"</item>
+    <item msgid="2494959071796102843">"Usar 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>
@@ -96,7 +96,7 @@
     <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="8868109554557331312">"Usar 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>
@@ -106,38 +106,38 @@
     <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="926809261293414607">"Usar seleção do sistema (predefinido)"</item>
     <item msgid="8003118270854840095">"44,1 kHz"</item>
     <item msgid="3208896645474529394">"48,0 kHz"</item>
     <item msgid="8420261949134022577">"88,2 kHz"</item>
     <item msgid="8887519571067543785">"96,0 kHz"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="2284090879080331090">"Utilizar seleção do sistema (predefinido)"</item>
+    <item msgid="2284090879080331090">"Usar seleção do sistema (predefinido)"</item>
     <item msgid="1872276250541651186">"44,1 kHz"</item>
     <item msgid="8736780630001704004">"48,0 kHz"</item>
     <item msgid="7698585706868856888">"88,2 kHz"</item>
     <item msgid="8946330945963372966">"96,0 kHz"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="2574107108483219051">"Utilizar seleção do sistema (predefinido)"</item>
+    <item msgid="2574107108483219051">"Usar seleção do sistema (predefinido)"</item>
     <item msgid="4671992321419011165">"16 bits/amostra"</item>
     <item msgid="1933898806184763940">"24 bits/amostra"</item>
     <item msgid="1212577207279552119">"32 bits/amostra"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="9196208128729063711">"Utilizar seleção do sistema (predefinido)"</item>
+    <item msgid="9196208128729063711">"Usar seleção do sistema (predefinido)"</item>
     <item msgid="1084497364516370912">"16 bits/amostra"</item>
     <item msgid="2077889391457961734">"24 bits/amostra"</item>
     <item msgid="3836844909491316925">"32 bits/amostra"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="3014194562841654656">"Utilizar seleção do sistema (predefinido)"</item>
+    <item msgid="3014194562841654656">"Usar seleção do sistema (predefinido)"</item>
     <item msgid="5982952342181788248">"Mono"</item>
     <item msgid="927546067692441494">"Estéreo"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="1997302811102880485">"Utilizar seleção do sistema (predefinido)"</item>
+    <item msgid="1997302811102880485">"Usar seleção do sistema (predefinido)"</item>
     <item msgid="8005696114958453588">"Mono"</item>
     <item msgid="1333279807604675720">"Estéreo"</item>
   </string-array>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index f70fae0..2bbff56 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -137,15 +137,15 @@
     <string name="bluetooth_hid_profile_summary_connected" msgid="3923653977051684833">"Ligado a um dispositivo de entrada"</string>
     <string name="bluetooth_pan_user_profile_summary_connected" msgid="380469653827505727">"Lig. ao disposit. p/ acesso à Internet"</string>
     <string name="bluetooth_pan_nap_profile_summary_connected" msgid="3744773111299503493">"A partilhar lig. à Internet local c/ dispos."</string>
-    <string name="bluetooth_pan_profile_summary_use_for" msgid="7422039765025340313">"Utilizar para acesso à Internet"</string>
-    <string name="bluetooth_map_profile_summary_use_for" msgid="4453622103977592583">"Utilizar para o mapa"</string>
-    <string name="bluetooth_sap_profile_summary_use_for" msgid="6204902866176714046">"Utilizar para acesso ao SIM"</string>
-    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="7324694226276491807">"Utilizar para áudio de multimédia"</string>
-    <string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Utilizar para áudio do telefone"</string>
-    <string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Utilizar para transferência de ficheiros"</string>
-    <string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Utilizar para entrada"</string>
-    <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Utilizar para aparelhos auditivos"</string>
-    <string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Utilizar para LE_AUDIO"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="7422039765025340313">"Usar para acesso à Internet"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="4453622103977592583">"Usar para o mapa"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="6204902866176714046">"Usar para acesso ao SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="7324694226276491807">"Usar para áudio de multimédia"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Usar para áudio do telefone"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Usar para transferência de ficheiros"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Usar para entrada"</string>
+    <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Usar para aparelhos auditivos"</string>
+    <string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Usar para LE_AUDIO"</string>
     <string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Sincr."</string>
     <string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"SINCRONIZAR"</string>
     <string name="bluetooth_pairing_decline" msgid="6483118841204885890">"Cancelar"</string>
@@ -442,7 +442,7 @@
     <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Definir implementação WebView"</string>
     <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Esta opção já não é válida. Tente novamente."</string>
     <string name="picture_color_mode" msgid="1013807330552931903">"Modo de cor da imagem"</string>
-    <string name="picture_color_mode_desc" msgid="151780973768136200">"Utilizar sRGB"</string>
+    <string name="picture_color_mode_desc" msgid="151780973768136200">"Usar sRGB"</string>
     <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Desativado"</string>
     <string name="daltonizer_mode_monochromacy" msgid="362060873835885014">"Monocromacia"</string>
     <string name="daltonizer_mode_deuteranomaly" msgid="3507284319584683963">"Deuteranomalia (vermelho-verde)"</string>
@@ -514,9 +514,9 @@
     <string name="retail_demo_reset_next" msgid="3688129033843885362">"Próximo"</string>
     <string name="retail_demo_reset_title" msgid="1866911701095959800">"Palavra-passe obrigatória"</string>
     <string name="active_input_method_subtypes" msgid="4232680535471633046">"Métodos de introdução activos"</string>
-    <string name="use_system_language_to_select_input_method_subtypes" msgid="4865195835541387040">"Utilizar idiomas do sistema"</string>
+    <string name="use_system_language_to_select_input_method_subtypes" msgid="4865195835541387040">"Usar idiomas do sistema"</string>
     <string name="failed_to_open_app_settings_toast" msgid="764897252657692092">"Falha ao abrir as definições para <xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g>"</string>
-    <string name="ime_security_warning" msgid="6547562217880551450">"Este método de introdução pode permitir a recolha de todo o texto que digitar, incluindo dados pessoais como, por exemplo, palavras-passe e números de cartões de crédito. Decorre da aplicação <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g>. Utilizar este método de introdução?"</string>
+    <string name="ime_security_warning" msgid="6547562217880551450">"Este método de introdução pode permitir a recolha de todo o texto que digitar, incluindo dados pessoais como, por exemplo, palavras-passe e números de cartões de crédito. Decorre da aplicação <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g>. Usar este método de introdução?"</string>
     <string name="direct_boot_unaware_dialog_message" msgid="7845398276735021548">"Nota: após reiniciar, só é possível iniciar esta aplicação quando o telemóvel for desbloqueado."</string>
     <string name="ims_reg_title" msgid="8197592958123671062">"Estado do registo IMS"</string>
     <string name="ims_reg_status_registered" msgid="884916398194885457">"Registado"</string>
@@ -662,7 +662,7 @@
     <string name="physical_keyboard_title" msgid="4811935435315835220">"Teclado físico"</string>
     <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Escolha um esquema de teclado"</string>
     <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Predefinição"</string>
-    <string name="turn_screen_on_title" msgid="3266937298097573424">"Ative o ecrã"</string>
+    <string name="turn_screen_on_title" msgid="3266937298097573424">"Ativação do ecrã"</string>
     <string name="allow_turn_screen_on" msgid="6194845766392742639">"Permitir a ativação do ecrã"</string>
     <string name="allow_turn_screen_on_description" msgid="43834403291575164">"Permita que uma app ative o ecrã. Se a autorização for concedida, a app pode ativar o ecrã em qualquer altura sem a sua intenção explícita."</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Interromper a transmissão da app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index fabfcde..c5f20da 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -526,7 +526,7 @@
     <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{Niciun dispozitiv conectat}=1{Un dispozitiv conectat}few{# dispozitive conectate}other{# de dispozitive conectate}}"</string>
     <string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Mai mult timp."</string>
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Mai puțin timp."</string>
-    <string name="cancel" msgid="5665114069455378395">"Anulați"</string>
+    <string name="cancel" msgid="5665114069455378395">"Anulează"</string>
     <string name="okay" msgid="949938843324579502">"OK"</string>
     <string name="done" msgid="381184316122520313">"Gata"</string>
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarme și mementouri"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 84c7dd3..72f156c 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -223,7 +223,7 @@
     <item msgid="581904787661470707">"Kasi zaidi"</item>
   </string-array>
     <string name="choose_profile" msgid="343803890897657450">"Chagua wasifu"</string>
-    <string name="category_personal" msgid="6236798763159385225">"Ya Binafsi"</string>
+    <string name="category_personal" msgid="6236798763159385225">"Binafsi"</string>
     <string name="category_work" msgid="4014193632325996115">"Ya Kazini"</string>
     <string name="development_settings_title" msgid="140296922921597393">"Chaguo za wasanidi"</string>
     <string name="development_settings_enable" msgid="4285094651288242183">"Washa chaguo za wasanidi programu"</string>
@@ -528,7 +528,7 @@
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Muda kidogo."</string>
     <string name="cancel" msgid="5665114069455378395">"Ghairi"</string>
     <string name="okay" msgid="949938843324579502">"Sawa"</string>
-    <string name="done" msgid="381184316122520313">"Imemaliza"</string>
+    <string name="done" msgid="381184316122520313">"Nimemaliza"</string>
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Ving\'ora na vikumbusho"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Ruhusu iweke kengele na vikumbusho"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Kengele na vikumbusho"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index c308c7f..4f62d51 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -299,7 +299,7 @@
     <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"ทริกเกอร์การเลือกตัวแปลงรหัส\nเสียงบลูทูธ: บิตต่อตัวอย่าง"</string>
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"โหมดช่องสัญญาณเสียงบลูทูธ"</string>
     <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="2076949781460359589">"ทริกเกอร์การเลือกตัวแปลงรหัส\nเสียงบลูทูธ: โหมดช่องสัญญาณ"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3233402355917446304">"ตัวแปลงรหัสเสียงบลูทูธที่ใช้ LDAC: คุณภาพการเล่น"</string>
+    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3233402355917446304">"ตัวแปลงสัญญาณเสียงบลูทูธที่ใช้ LDAC: คุณภาพการเล่น"</string>
     <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="7274396574659784285">"ทริกเกอร์การเลือกตัวแปลงรหัส LDAC\nเสียงบลูทูธ: คุณภาพการเล่น"</string>
     <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="2040810756832027227">"สตรีมมิง: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
     <string name="select_private_dns_configuration_title" msgid="7887550926056143018">"DNS ส่วนตัว"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ServiceListing.java b/packages/SettingsLib/src/com/android/settingslib/applications/ServiceListing.java
index bd9e760..c8bcabf 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ServiceListing.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ServiceListing.java
@@ -35,6 +35,7 @@
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
+import java.util.function.Predicate;
 
 /**
  * Class for managing services matching a given intent and requesting a given permission.
@@ -51,12 +52,13 @@
     private final HashSet<ComponentName> mEnabledServices = new HashSet<>();
     private final List<ServiceInfo> mServices = new ArrayList<>();
     private final List<Callback> mCallbacks = new ArrayList<>();
+    private final Predicate mValidator;
 
     private boolean mListening;
 
     private ServiceListing(Context context, String tag,
             String setting, String intentAction, String permission, String noun,
-            boolean addDeviceLockedFlags) {
+            boolean addDeviceLockedFlags, Predicate validator) {
         mContentResolver = context.getContentResolver();
         mContext = context;
         mTag = tag;
@@ -65,6 +67,7 @@
         mPermission = permission;
         mNoun = noun;
         mAddDeviceLockedFlags = addDeviceLockedFlags;
+        mValidator = validator;
     }
 
     public void addCallback(Callback callback) {
@@ -137,7 +140,6 @@
         final PackageManager pmWrapper = mContext.getPackageManager();
         List<ResolveInfo> installedServices = pmWrapper.queryIntentServicesAsUser(
                 new Intent(mIntentAction), flags, user);
-
         for (ResolveInfo resolveInfo : installedServices) {
             ServiceInfo info = resolveInfo.serviceInfo;
 
@@ -148,6 +150,9 @@
                         + mPermission);
                 continue;
             }
+            if (mValidator != null && !mValidator.test(info)) {
+                continue;
+            }
             mServices.add(info);
         }
         for (Callback callback : mCallbacks) {
@@ -194,6 +199,7 @@
         private String mPermission;
         private String mNoun;
         private boolean mAddDeviceLockedFlags = false;
+        private Predicate mValidator;
 
         public Builder(Context context) {
             mContext = context;
@@ -224,6 +230,11 @@
             return this;
         }
 
+        public Builder setValidator(Predicate<ServiceInfo> validator) {
+            mValidator = validator;
+            return this;
+        }
+
         /**
          * Set to true to add support for both MATCH_DIRECT_BOOT_AWARE and
          * MATCH_DIRECT_BOOT_UNAWARE flags when querying PackageManager. Required to get results
@@ -236,7 +247,7 @@
 
         public ServiceListing build() {
             return new ServiceListing(mContext, mTag, mSetting, mIntentAction, mPermission, mNoun,
-                    mAddDeviceLockedFlags);
+                    mAddDeviceLockedFlags, mValidator);
         }
     }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
index 688fc72..c4f09ce 100644
--- a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
+++ b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
@@ -31,13 +31,15 @@
 import android.provider.Settings;
 import android.service.dreams.DreamService;
 import android.service.dreams.IDreamManager;
+import android.util.ArraySet;
 import android.util.Log;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 import java.util.Set;
@@ -116,7 +118,7 @@
     private final boolean mDreamsActivatedOnSleepByDefault;
     private final boolean mDreamsActivatedOnDockByDefault;
     private final Set<ComponentName> mDisabledDreams;
-    private final Set<Integer> mSupportedComplications;
+    private Set<Integer> mSupportedComplications;
     private static DreamBackend sInstance;
 
     public static DreamBackend getInstance(Context context) {
@@ -281,7 +283,18 @@
 
     /** Gets all complications which have been enabled by the user. */
     public Set<Integer> getEnabledComplications() {
-        return getComplicationsEnabled() ? mSupportedComplications : Collections.emptySet();
+        final Set<Integer> enabledComplications =
+                getComplicationsEnabled()
+                        ? new ArraySet<>(mSupportedComplications) : new ArraySet<>();
+
+        if (!getHomeControlsEnabled()) {
+            enabledComplications.remove(COMPLICATION_TYPE_HOME_CONTROLS);
+        } else if (mSupportedComplications.contains(COMPLICATION_TYPE_HOME_CONTROLS)) {
+            // Add home control type to list of enabled complications, even if other complications
+            // have been disabled.
+            enabledComplications.add(COMPLICATION_TYPE_HOME_CONTROLS);
+        }
+        return enabledComplications;
     }
 
     /** Sets complication enabled state. */
@@ -290,6 +303,18 @@
                 Settings.Secure.SCREENSAVER_COMPLICATIONS_ENABLED, enabled ? 1 : 0);
     }
 
+    /** Sets whether home controls are enabled by the user on the dream */
+    public void setHomeControlsEnabled(boolean enabled) {
+        Settings.Secure.putInt(mContext.getContentResolver(),
+                Settings.Secure.SCREENSAVER_HOME_CONTROLS_ENABLED, enabled ? 1 : 0);
+    }
+
+    /** Gets whether home controls button is enabled on the dream */
+    private boolean getHomeControlsEnabled() {
+        return Settings.Secure.getInt(mContext.getContentResolver(),
+                Settings.Secure.SCREENSAVER_HOME_CONTROLS_ENABLED, 1) == 1;
+    }
+
     /**
      * Gets whether complications are enabled on this device
      */
@@ -304,6 +329,14 @@
         return mSupportedComplications;
     }
 
+    /**
+     * Sets the list of supported complications. Should only be used in tests.
+     */
+    @VisibleForTesting
+    public void setSupportedComplications(Set<Integer> complications) {
+        mSupportedComplications = complications;
+    }
+
     public boolean isEnabled() {
         return getBoolean(Settings.Secure.SCREENSAVER_ENABLED, mDreamsEnabledByDefault);
     }
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java
index 81006dd..fdefcde 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java
@@ -33,7 +33,10 @@
 import com.android.internal.R;
 import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager.SettableDeviceState;
 
+import com.google.common.truth.Expect;
+
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -45,6 +48,8 @@
 @RunWith(AndroidJUnit4.class)
 public class DeviceStateRotationLockSettingsManagerTest {
 
+    @Rule public Expect mExpect = Expect.create();
+
     @Mock private Context mMockContext;
     @Mock private Resources mMockResources;
 
@@ -65,12 +70,20 @@
         when(mMockContext.getApplicationContext()).thenReturn(mMockContext);
         when(mMockContext.getResources()).thenReturn(mMockResources);
         when(mMockContext.getContentResolver()).thenReturn(context.getContentResolver());
+        when(mMockResources.getStringArray(R.array.config_perDeviceStateRotationLockDefaults))
+                .thenReturn(new String[]{"0:1", "1:0:2", "2:2"});
+        when(mMockResources.getIntArray(R.array.config_foldedDeviceStates))
+                .thenReturn(new int[]{0});
+        when(mMockResources.getIntArray(R.array.config_halfFoldedDeviceStates))
+                .thenReturn(new int[]{1});
+        when(mMockResources.getIntArray(R.array.config_openDeviceStates))
+                .thenReturn(new int[]{2});
         mFakeSecureSettings.registerContentObserver(
                 Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
                 /* notifyForDescendents= */ false, //NOTYPO
                 mContentObserver,
                 UserHandle.USER_CURRENT);
-        mManager = new DeviceStateRotationLockSettingsManager(context, mFakeSecureSettings);
+        mManager = new DeviceStateRotationLockSettingsManager(mMockContext, mFakeSecureSettings);
     }
 
     @Test
@@ -104,7 +117,7 @@
     public void getSettableDeviceStates_returnsExpectedValuesInOriginalOrder() {
         when(mMockResources.getStringArray(
                 R.array.config_perDeviceStateRotationLockDefaults)).thenReturn(
-                new String[]{"2:2", "4:0", "1:1", "0:0"});
+                new String[]{"2:1", "1:0:1", "0:2"});
 
         List<SettableDeviceState> settableDeviceStates =
                 DeviceStateRotationLockSettingsManager.getInstance(
@@ -112,9 +125,44 @@
 
         assertThat(settableDeviceStates).containsExactly(
                 new SettableDeviceState(/* deviceState= */ 2, /* isSettable= */ true),
-                new SettableDeviceState(/* deviceState= */ 4, /* isSettable= */ false),
-                new SettableDeviceState(/* deviceState= */ 1, /* isSettable= */ true),
-                new SettableDeviceState(/* deviceState= */ 0, /* isSettable= */ false)
+                new SettableDeviceState(/* deviceState= */ 1, /* isSettable= */ false),
+                new SettableDeviceState(/* deviceState= */ 0, /* isSettable= */ true)
         ).inOrder();
     }
+
+    @Test
+    public void persistedInvalidIgnoredState_returnsDefaults() {
+        when(mMockResources.getStringArray(
+                R.array.config_perDeviceStateRotationLockDefaults)).thenReturn(
+                new String[]{"0:1", "1:0:2", "2:2"});
+        // Here 2 has IGNORED, and in the defaults 1 has IGNORED.
+        persistSettings("0:2:2:0:1:2");
+        DeviceStateRotationLockSettingsManager manager =
+                new DeviceStateRotationLockSettingsManager(mMockContext, mFakeSecureSettings);
+
+        mExpect.that(manager.getRotationLockSetting(0)).isEqualTo(1);
+        mExpect.that(manager.getRotationLockSetting(1)).isEqualTo(2);
+        mExpect.that(manager.getRotationLockSetting(2)).isEqualTo(2);
+    }
+
+    @Test
+    public void persistedValidValues_returnsPersistedValues() {
+        when(mMockResources.getStringArray(
+                R.array.config_perDeviceStateRotationLockDefaults)).thenReturn(
+                new String[]{"0:1", "1:0:2", "2:2"});
+        persistSettings("0:2:1:0:2:1");
+        DeviceStateRotationLockSettingsManager manager =
+                new DeviceStateRotationLockSettingsManager(mMockContext, mFakeSecureSettings);
+
+        mExpect.that(manager.getRotationLockSetting(0)).isEqualTo(2);
+        mExpect.that(manager.getRotationLockSetting(1)).isEqualTo(1);
+        mExpect.that(manager.getRotationLockSetting(2)).isEqualTo(1);
+    }
+
+    private void persistSettings(String value) {
+        mFakeSecureSettings.putStringForUser(
+                Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+                value,
+                UserHandle.USER_CURRENT);
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ServiceListingTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ServiceListingTest.java
index f7fd25b..7ff0988 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ServiceListingTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ServiceListingTest.java
@@ -18,20 +18,35 @@
 
 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.anyList;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
 import android.provider.Settings;
 
+import androidx.test.core.app.ApplicationProvider;
+
+import com.google.common.collect.ImmutableList;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 
+import java.util.List;
+
 @RunWith(RobolectricTestRunner.class)
 public class ServiceListingTest {
 
@@ -39,10 +54,16 @@
     private static final String TEST_INTENT = "com.example.intent";
 
     private ServiceListing mServiceListing;
+    private Context mContext;
+    private PackageManager mPm;
 
     @Before
     public void setUp() {
-        mServiceListing = new ServiceListing.Builder(RuntimeEnvironment.application)
+        mPm = mock(PackageManager.class);
+        mContext = spy(ApplicationProvider.getApplicationContext());
+        when(mContext.getPackageManager()).thenReturn(mPm);
+
+        mServiceListing = new ServiceListing.Builder(mContext)
                 .setTag("testTag")
                 .setSetting(TEST_SETTING)
                 .setNoun("testNoun")
@@ -52,6 +73,81 @@
     }
 
     @Test
+    public void testValidator() {
+        ServiceInfo s1 = new ServiceInfo();
+        s1.permission = "testPermission";
+        s1.packageName = "pkg";
+        ServiceInfo s2 = new ServiceInfo();
+        s2.permission = "testPermission";
+        s2.packageName = "pkg2";
+        ResolveInfo r1 = new ResolveInfo();
+        r1.serviceInfo = s1;
+        ResolveInfo r2 = new ResolveInfo();
+        r2.serviceInfo = s2;
+
+        when(mPm.queryIntentServicesAsUser(any(), anyInt(), anyInt())).thenReturn(
+                ImmutableList.of(r1, r2));
+
+        mServiceListing = new ServiceListing.Builder(mContext)
+                .setTag("testTag")
+                .setSetting(TEST_SETTING)
+                .setNoun("testNoun")
+                .setIntentAction(TEST_INTENT)
+                .setValidator(info -> {
+                    if (info.packageName.equals("pkg")) {
+                        return true;
+                    }
+                    return false;
+                })
+                .setPermission("testPermission")
+                .build();
+        ServiceListing.Callback callback = mock(ServiceListing.Callback.class);
+        mServiceListing.addCallback(callback);
+        mServiceListing.reload();
+
+        verify(mPm).queryIntentServicesAsUser(any(), anyInt(), anyInt());
+        ArgumentCaptor<List<ServiceInfo>> captor = ArgumentCaptor.forClass(List.class);
+        verify(callback, times(1)).onServicesReloaded(captor.capture());
+
+        assertThat(captor.getValue().size()).isEqualTo(1);
+        assertThat(captor.getValue().get(0)).isEqualTo(s1);
+    }
+
+    @Test
+    public void testNoValidator() {
+        ServiceInfo s1 = new ServiceInfo();
+        s1.permission = "testPermission";
+        s1.packageName = "pkg";
+        ServiceInfo s2 = new ServiceInfo();
+        s2.permission = "testPermission";
+        s2.packageName = "pkg2";
+        ResolveInfo r1 = new ResolveInfo();
+        r1.serviceInfo = s1;
+        ResolveInfo r2 = new ResolveInfo();
+        r2.serviceInfo = s2;
+
+        when(mPm.queryIntentServicesAsUser(any(), anyInt(), anyInt())).thenReturn(
+                ImmutableList.of(r1, r2));
+
+        mServiceListing = new ServiceListing.Builder(mContext)
+                .setTag("testTag")
+                .setSetting(TEST_SETTING)
+                .setNoun("testNoun")
+                .setIntentAction(TEST_INTENT)
+                .setPermission("testPermission")
+                .build();
+        ServiceListing.Callback callback = mock(ServiceListing.Callback.class);
+        mServiceListing.addCallback(callback);
+        mServiceListing.reload();
+
+        verify(mPm).queryIntentServicesAsUser(any(), anyInt(), anyInt());
+        ArgumentCaptor<List<ServiceInfo>> captor = ArgumentCaptor.forClass(List.class);
+        verify(callback, times(1)).onServicesReloaded(captor.capture());
+
+        assertThat(captor.getValue().size()).isEqualTo(2);
+    }
+
+    @Test
     public void testCallback() {
         ServiceListing.Callback callback = mock(ServiceListing.Callback.class);
         mServiceListing.addCallback(callback);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/dream/DreamBackendTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/dream/DreamBackendTest.java
index 52b9227..22ec12d 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/dream/DreamBackendTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/dream/DreamBackendTest.java
@@ -16,6 +16,10 @@
 package com.android.settingslib.dream;
 
 
+import static com.android.settingslib.dream.DreamBackend.COMPLICATION_TYPE_DATE;
+import static com.android.settingslib.dream.DreamBackend.COMPLICATION_TYPE_HOME_CONTROLS;
+import static com.android.settingslib.dream.DreamBackend.COMPLICATION_TYPE_TIME;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.mock;
@@ -36,13 +40,16 @@
 import org.robolectric.shadows.ShadowSettings;
 
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.stream.Collectors;
 
 @RunWith(RobolectricTestRunner.class)
 @Config(shadows = {ShadowSettings.ShadowSecure.class})
 public final class DreamBackendTest {
-    private static final int[] SUPPORTED_DREAM_COMPLICATIONS = {1, 2, 3};
+    private static final int[] SUPPORTED_DREAM_COMPLICATIONS =
+            {COMPLICATION_TYPE_HOME_CONTROLS, COMPLICATION_TYPE_DATE,
+                    COMPLICATION_TYPE_TIME};
     private static final List<Integer> SUPPORTED_DREAM_COMPLICATIONS_LIST = Arrays.stream(
             SUPPORTED_DREAM_COMPLICATIONS).boxed().collect(
             Collectors.toList());
@@ -93,8 +100,52 @@
     @Test
     public void testDisableComplications() {
         mBackend.setComplicationsEnabled(false);
-        assertThat(mBackend.getEnabledComplications()).isEmpty();
+        assertThat(mBackend.getEnabledComplications())
+                .containsExactly(COMPLICATION_TYPE_HOME_CONTROLS);
         assertThat(mBackend.getComplicationsEnabled()).isFalse();
     }
-}
 
+    @Test
+    public void testHomeControlsDisabled_ComplicationsEnabled() {
+        mBackend.setComplicationsEnabled(true);
+        mBackend.setHomeControlsEnabled(false);
+        // Home controls should not be enabled, only date and time.
+        final List<Integer> enabledComplications =
+                Arrays.asList(COMPLICATION_TYPE_DATE, COMPLICATION_TYPE_TIME);
+        assertThat(mBackend.getEnabledComplications())
+                .containsExactlyElementsIn(enabledComplications);
+    }
+
+    @Test
+    public void testHomeControlsDisabled_ComplicationsDisabled() {
+        mBackend.setComplicationsEnabled(false);
+        mBackend.setHomeControlsEnabled(false);
+        assertThat(mBackend.getEnabledComplications()).isEmpty();
+    }
+
+    @Test
+    public void testHomeControlsEnabled_ComplicationsDisabled() {
+        mBackend.setComplicationsEnabled(false);
+        mBackend.setHomeControlsEnabled(true);
+        // Home controls should not be enabled, only date and time.
+        final List<Integer> enabledComplications =
+                Collections.singletonList(COMPLICATION_TYPE_HOME_CONTROLS);
+        assertThat(mBackend.getEnabledComplications())
+                .containsExactlyElementsIn(enabledComplications);
+    }
+
+    @Test
+    public void testHomeControlsEnabled_ComplicationsEnabled() {
+        mBackend.setComplicationsEnabled(true);
+        mBackend.setHomeControlsEnabled(true);
+        // Home controls should not be enabled, only date and time.
+        final List<Integer> enabledComplications =
+                Arrays.asList(
+                        COMPLICATION_TYPE_HOME_CONTROLS,
+                        COMPLICATION_TYPE_DATE,
+                        COMPLICATION_TYPE_TIME
+                );
+        assertThat(mBackend.getEnabledComplications())
+                .containsExactlyElementsIn(enabledComplications);
+    }
+}
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
index 162bb2c..b8887ae 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
@@ -49,6 +49,7 @@
         Settings.Global.CHARGING_SOUNDS_ENABLED,
         Settings.Global.USB_MASS_STORAGE_ENABLED,
         Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED,
+        Settings.Global.NETWORK_AVOID_BAD_WIFI,
         Settings.Global.WIFI_WAKEUP_ENABLED,
         Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
         Settings.Global.USE_OPEN_WIFI_PACKAGE,
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index b5eaa4b..f6a66c9 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -139,6 +139,7 @@
         Settings.Secure.SCREENSAVER_COMPONENTS,
         Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
         Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
+        Settings.Secure.SCREENSAVER_HOME_CONTROLS_ENABLED,
         Settings.Secure.SHOW_FIRST_CRASH_DIALOG_DEV_OPTION,
         Settings.Secure.VOLUME_HUSH_GESTURE,
         Settings.Secure.MANUAL_RINGER_TOGGLE_COUNT,
@@ -221,6 +222,7 @@
         Settings.Secure.BLUETOOTH_LE_BROADCAST_PROGRAM_INFO,
         Settings.Secure.BLUETOOTH_LE_BROADCAST_CODE,
         Settings.Secure.BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME,
-        Settings.Secure.LOCK_SCREEN_WEATHER_ENABLED
+        Settings.Secure.LOCK_SCREEN_WEATHER_ENABLED,
+        Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED
     };
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index b152209..8784d87 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -17,6 +17,9 @@
 package android.provider.settings.validators;
 
 import static android.media.AudioFormat.SURROUND_SOUND_ENCODING;
+import static android.net.ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI_AVOID;
+import static android.net.ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI_IGNORE;
+import static android.net.ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI_PROMPT;
 import static android.provider.settings.validators.SettingsValidators.ANY_INTEGER_VALIDATOR;
 import static android.provider.settings.validators.SettingsValidators.ANY_STRING_VALIDATOR;
 import static android.provider.settings.validators.SettingsValidators.BOOLEAN_VALIDATOR;
@@ -95,6 +98,14 @@
         VALIDATORS.put(
                 Global.NETWORK_RECOMMENDATIONS_ENABLED,
                 new DiscreteValueValidator(new String[] {"-1", "0", "1"}));
+        VALIDATORS.put(
+                Global.NETWORK_AVOID_BAD_WIFI,
+                new DiscreteValueValidator(
+                        new String[] {
+                                String.valueOf(NETWORK_AVOID_BAD_WIFI_IGNORE),
+                                String.valueOf(NETWORK_AVOID_BAD_WIFI_PROMPT),
+                                String.valueOf(NETWORK_AVOID_BAD_WIFI_AVOID),
+                        }));
         VALIDATORS.put(Global.WIFI_WAKEUP_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, BOOLEAN_VALIDATOR);
         VALIDATORS.put(
@@ -339,4 +350,3 @@
         VALIDATORS.put(Global.Wearable.COOLDOWN_MODE_ON, BOOLEAN_VALIDATOR);
     }
 }
-
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 534e31a..44992f2 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -206,6 +206,7 @@
         VALIDATORS.put(Secure.SCREENSAVER_COMPONENTS, COMMA_SEPARATED_COMPONENT_LIST_VALIDATOR);
         VALIDATORS.put(Secure.SCREENSAVER_ACTIVATE_ON_DOCK, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.SCREENSAVER_HOME_CONTROLS_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.SHOW_FIRST_CRASH_DIALOG_DEV_OPTION, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.VOLUME_HUSH_GESTURE, NON_NEGATIVE_INTEGER_VALIDATOR);
         VALIDATORS.put(
@@ -355,5 +356,6 @@
         VALIDATORS.put(Secure.BLUETOOTH_LE_BROADCAST_CODE, ANY_STRING_VALIDATOR);
         VALIDATORS.put(Secure.BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME, ANY_STRING_VALIDATOR);
         VALIDATORS.put(Secure.LOCK_SCREEN_WEATHER_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED, BOOLEAN_VALIDATOR);
     }
 }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index d0055d7..9f59fc3 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -182,6 +182,8 @@
             "visible_pattern_enabled";
     private static final String KEY_LOCK_SETTINGS_POWER_BUTTON_INSTANTLY_LOCKS =
             "power_button_instantly_locks";
+    private static final String KEY_LOCK_SETTINGS_PIN_ENHANCED_PRIVACY =
+            "pin_enhanced_privacy";
 
     // Name of the temporary file we use during full backup/restore.  This is
     // stored in the full-backup tarfile as well, so should not be changed.
@@ -709,6 +711,10 @@
                 out.writeUTF(KEY_LOCK_SETTINGS_POWER_BUTTON_INSTANTLY_LOCKS);
                 out.writeUTF(powerButtonInstantlyLocks ? "1" : "0");
             }
+            if (lockPatternUtils.isPinEnhancedPrivacyEverChosen(userId)) {
+                out.writeUTF(KEY_LOCK_SETTINGS_PIN_ENHANCED_PRIVACY);
+                out.writeUTF(lockPatternUtils.isPinEnhancedPrivacyEnabled(userId) ? "1" : "0");
+            }
             // End marker
             out.writeUTF("");
             out.flush();
@@ -961,6 +967,9 @@
                     case KEY_LOCK_SETTINGS_POWER_BUTTON_INSTANTLY_LOCKS:
                         lockPatternUtils.setPowerButtonInstantlyLocks("1".equals(value), userId);
                         break;
+                    case KEY_LOCK_SETTINGS_PIN_ENHANCED_PRIVACY:
+                        lockPatternUtils.setPinEnhancedPrivacyEnabled("1".equals(value), userId);
+                        break;
                 }
             }
             in.close();
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index a78faaf..c90b95a 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1822,6 +1822,9 @@
                 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_FOLLOW_TYPING_ENABLED,
                 SecureSettingsProto.Accessibility
                         .ACCESSIBILITY_MAGNIFICATION_FOLLOW_TYPING_ENABLED);
+        dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED,
+                SecureSettingsProto.Accessibility.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED);
         p.end(accessibilityToken);
 
         final long adaptiveSleepToken = p.start(SecureSettingsProto.ADAPTIVE_SLEEP);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index fd0fa3a..3c2aefd 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -377,7 +377,6 @@
                     Settings.Global.NETPOLICY_QUOTA_FRAC_JOBS,
                     Settings.Global.NETPOLICY_QUOTA_FRAC_MULTIPATH,
                     Settings.Global.NETPOLICY_OVERRIDE_ENABLED,
-                    Settings.Global.NETWORK_AVOID_BAD_WIFI,
                     Settings.Global.NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES,
                     Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE,
                     Settings.Global.NETWORK_WATCHLIST_LAST_REPORT_TIME,
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 71a82bf..cacf133 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -878,7 +878,7 @@
                   android:showForAllUsers="true"
                   android:finishOnTaskLaunch="true"
                   android:launchMode="singleInstance"
-                  android:configChanges="screenSize|smallestScreenSize|screenLayout|keyboard|keyboardHidden"
+                  android:configChanges="screenSize|smallestScreenSize|screenLayout|keyboard|keyboardHidden|orientation"
                   android:visibleToInstantApps="true">
         </activity>
 
@@ -900,7 +900,7 @@
                   android:showWhenLocked="true"
                   android:showForAllUsers="true"
                   android:finishOnTaskLaunch="true"
-                  android:lockTaskMode="if_whitelisted"
+                  android:lockTaskMode="always"
                   android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
                   android:visibleToInstantApps="true">
         </activity>
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index 60bfdb2..6474e6a 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -43,6 +43,9 @@
         },
         {
           "exclude-annotation": "androidx.test.filters.FlakyTest"
+        },
+        {
+          "exclude-annotation": "android.platform.test.annotations.Postsubmit"
         }
       ]
     },
@@ -160,5 +163,21 @@
         }
       ]
     }
+  ],
+  "postsubmit": [
+    {
+      "name": "SystemUIGoogleScreenshotTests",
+      "options": [
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        },
+        {
+          "include-annotation": "android.platform.test.annotations.Postsubmit"
+        }
+      ]
+    }
   ]
 }
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
index 17a94b86..296c2ae 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -419,7 +419,7 @@
         internal val delegate: AnimationDelegate
 
         init {
-            delegate = AnimationDelegate(controller, callback, launchAnimator, listener)
+            delegate = AnimationDelegate(controller, callback, listener, launchAnimator)
         }
 
         @BinderThread
@@ -446,10 +446,10 @@
     constructor(
         private val controller: Controller,
         private val callback: Callback,
-        /** The animator to use to animate the window launch. */
-        private val launchAnimator: LaunchAnimator = DEFAULT_LAUNCH_ANIMATOR,
         /** Listener for animation lifecycle events. */
-        private val listener: Listener? = null
+        private val listener: Listener? = null,
+        /** The animator to use to animate the window launch. */
+        private val launchAnimator: LaunchAnimator = DEFAULT_LAUNCH_ANIMATOR
     ) : RemoteAnimationDelegate<IRemoteAnimationFinishedCallback> {
         private val launchContainer = controller.launchContainer
         private val context = launchContainer.context
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt
index 2903288..f0a8211 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt
@@ -19,14 +19,15 @@
 import android.graphics.fonts.Font
 import android.graphics.fonts.FontVariationAxis
 import android.util.MathUtils
+import android.util.MathUtils.abs
+import java.lang.Float.max
+import java.lang.Float.min
 
 private const val TAG_WGHT = "wght"
 private const val TAG_ITAL = "ital"
 
-private const val FONT_WEIGHT_MAX = 1000f
-private const val FONT_WEIGHT_MIN = 0f
-private const val FONT_WEIGHT_ANIMATION_STEP = 10f
 private const val FONT_WEIGHT_DEFAULT_VALUE = 400f
+private const val FONT_WEIGHT_ANIMATION_FRAME_COUNT = 100
 
 private const val FONT_ITALIC_MAX = 1f
 private const val FONT_ITALIC_MIN = 0f
@@ -118,14 +119,17 @@
             lerp(startAxes, endAxes) { tag, startValue, endValue ->
                 when (tag) {
                     // TODO: Good to parse 'fvar' table for retrieving default value.
-                    TAG_WGHT ->
-                        adjustWeight(
+                    TAG_WGHT -> {
+                        adaptiveAdjustWeight(
                             MathUtils.lerp(
                                 startValue ?: FONT_WEIGHT_DEFAULT_VALUE,
                                 endValue ?: FONT_WEIGHT_DEFAULT_VALUE,
                                 progress
-                            )
+                            ),
+                            startValue ?: FONT_WEIGHT_DEFAULT_VALUE,
+                            endValue ?: FONT_WEIGHT_DEFAULT_VALUE,
                         )
+                    }
                     TAG_ITAL ->
                         adjustItalic(
                             MathUtils.lerp(
@@ -205,10 +209,14 @@
         return result
     }
 
-    // For the performance reasons, we animate weight with FONT_WEIGHT_ANIMATION_STEP. This helps
+    // For the performance reasons, we animate weight with adaptive step. This helps
     // Cache hit ratio in the Skia glyph cache.
-    private fun adjustWeight(value: Float) =
-        coerceInWithStep(value, FONT_WEIGHT_MIN, FONT_WEIGHT_MAX, FONT_WEIGHT_ANIMATION_STEP)
+    // The reason we don't use fix step is because the range of weight axis is not normalized,
+    // some are from 50 to 100, others are from 0 to 1000, so we cannot give a constant proper step
+    private fun adaptiveAdjustWeight(value: Float, start: Float, end: Float): Float {
+        val step = max(abs(end - start) / FONT_WEIGHT_ANIMATION_FRAME_COUNT, 1F)
+        return coerceInWithStep(value, min(start, end), max(start, end), step)
+    }
 
     // For the performance reasons, we animate italic with FONT_ITALIC_ANIMATION_STEP. This helps
     // Cache hit ratio in the Skia glyph cache.
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/FontVariationUtils.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/FontVariationUtils.kt
new file mode 100644
index 0000000..78ae4af
--- /dev/null
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/FontVariationUtils.kt
@@ -0,0 +1,59 @@
+package com.android.systemui.animation
+
+private const val TAG_WGHT = "wght"
+private const val TAG_WDTH = "wdth"
+private const val TAG_OPSZ = "opsz"
+private const val TAG_ROND = "ROND"
+
+class FontVariationUtils {
+    private var mWeight = -1
+    private var mWidth = -1
+    private var mOpticalSize = -1
+    private var mRoundness = -1
+    private var isUpdated = false
+
+    /*
+     * generate fontVariationSettings string, used for key in typefaceCache in TextAnimator
+     * the order of axes should align to the order of parameters
+     * if every axis remains unchanged, return ""
+     */
+    fun updateFontVariation(
+        weight: Int = -1,
+        width: Int = -1,
+        opticalSize: Int = -1,
+        roundness: Int = -1
+    ): String {
+        isUpdated = false
+        if (weight >= 0 && mWeight != weight) {
+            isUpdated = true
+            mWeight = weight
+        }
+        if (width >= 0 && mWidth != width) {
+            isUpdated = true
+            mWidth = width
+        }
+        if (opticalSize >= 0 && mOpticalSize != opticalSize) {
+            isUpdated = true
+            mOpticalSize = opticalSize
+        }
+
+        if (roundness >= 0 && mRoundness != roundness) {
+            isUpdated = true
+            mRoundness = roundness
+        }
+        var resultString = ""
+        if (mWeight >= 0) {
+            resultString += "'$TAG_WGHT' $mWeight"
+        }
+        if (mWidth >= 0) {
+            resultString += (if (resultString.isBlank()) "" else ", ") + "'$TAG_WDTH' $mWidth"
+        }
+        if (mOpticalSize >= 0) {
+            resultString += (if (resultString.isBlank()) "" else ", ") + "'$TAG_OPSZ' $mOpticalSize"
+        }
+        if (mRoundness >= 0) {
+            resultString += (if (resultString.isBlank()) "" else ", ") + "'$TAG_ROND' $mRoundness"
+        }
+        return if (isUpdated) resultString else ""
+    }
+}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
index a08b598..9e9929e 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
@@ -23,11 +23,8 @@
 import android.graphics.Canvas
 import android.graphics.Typeface
 import android.graphics.fonts.Font
-import android.graphics.fonts.FontVariationAxis
 import android.text.Layout
-import android.util.SparseArray
 
-private const val TAG_WGHT = "wght"
 private const val DEFAULT_ANIMATION_DURATION: Long = 300
 
 typealias GlyphCallback = (TextAnimator.PositionedGlyph, Float) -> Unit
@@ -51,7 +48,7 @@
  *
  *         // Change the text size with animation.
  *         fun setTextSize(sizePx: Float, animate: Boolean) {
- *             animator.setTextStyle(-1 /* unchanged weight */, sizePx, animate)
+ *             animator.setTextStyle("" /* unchanged fvar... */, sizePx, animate)
  *         }
  *     }
  * ```
@@ -115,7 +112,9 @@
             protected set
     }
 
-    private val typefaceCache = SparseArray<Typeface?>()
+    private val fontVariationUtils = FontVariationUtils()
+
+    private val typefaceCache = HashMap<String, Typeface?>()
 
     fun updateLayout(layout: Layout) {
         textInterpolator.layout = layout
@@ -186,10 +185,11 @@
      * Bu passing -1 to duration, the default text animation, 1000ms, is used.
      * By passing false to animate, the text will be updated without animation.
      *
-     * @param weight an optional text weight.
+     * @param fvar an optional text fontVariationSettings.
      * @param textSize an optional font size.
      * @param colors an optional colors array that must be the same size as numLines passed to
      *               the TextInterpolator
+     * @param strokeWidth an optional paint stroke width
      * @param animate an optional boolean indicating true for showing style transition as animation,
      *                false for immediate style transition. True by default.
      * @param duration an optional animation duration in milliseconds. This is ignored if animate is
@@ -198,9 +198,10 @@
      *                     will be used. This is ignored if animate is false.
      */
     fun setTextStyle(
-        weight: Int = -1,
+        fvar: String? = "",
         textSize: Float = -1f,
         color: Int? = null,
+        strokeWidth: Float = -1f,
         animate: Boolean = true,
         duration: Long = -1L,
         interpolator: TimeInterpolator? = null,
@@ -215,45 +216,22 @@
         if (textSize >= 0) {
             textInterpolator.targetPaint.textSize = textSize
         }
-        if (weight >= 0) {
-            val fontVariationArray =
-                    FontVariationAxis.fromFontVariationSettings(
-                        textInterpolator.targetPaint.fontVariationSettings
-                    )
-            if (fontVariationArray.isNullOrEmpty()) {
-                textInterpolator.targetPaint.typeface =
-                    typefaceCache.getOrElse(weight) {
-                        textInterpolator.targetPaint.fontVariationSettings = "'$TAG_WGHT' $weight"
-                        textInterpolator.targetPaint.typeface
-                    }
-            } else {
-                val idx = fontVariationArray.indexOfFirst { it.tag == "$TAG_WGHT" }
-                if (idx == -1) {
-                    val updatedFontVariation =
-                        textInterpolator.targetPaint.fontVariationSettings + ",'$TAG_WGHT' $weight"
-                    textInterpolator.targetPaint.typeface =
-                        typefaceCache.getOrElse(weight) {
-                            textInterpolator.targetPaint.fontVariationSettings =
-                                    updatedFontVariation
-                            textInterpolator.targetPaint.typeface
-                        }
-                } else {
-                    fontVariationArray[idx] = FontVariationAxis(
-                            "$TAG_WGHT", weight.toFloat())
-                    val updatedFontVariation =
-                            FontVariationAxis.toFontVariationSettings(fontVariationArray)
-                    textInterpolator.targetPaint.typeface =
-                        typefaceCache.getOrElse(weight) {
-                            textInterpolator.targetPaint.fontVariationSettings =
-                                    updatedFontVariation
-                            textInterpolator.targetPaint.typeface
-                        }
+
+        if (!fvar.isNullOrBlank()) {
+            textInterpolator.targetPaint.typeface =
+                typefaceCache.getOrElse(fvar) {
+                    textInterpolator.targetPaint.fontVariationSettings = fvar
+                    typefaceCache.put(fvar, textInterpolator.targetPaint.typeface)
+                    textInterpolator.targetPaint.typeface
                 }
-            }
         }
+
         if (color != null) {
             textInterpolator.targetPaint.color = color
         }
+        if (strokeWidth >= 0F) {
+            textInterpolator.targetPaint.strokeWidth = strokeWidth
+        }
         textInterpolator.onTargetPaintModified()
 
         if (animate) {
@@ -286,13 +264,56 @@
             invalidateCallback()
         }
     }
+
+    /**
+     * Set text style with animation. Similar as
+     * fun setTextStyle(
+     *      fvar: String? = "",
+     *      textSize: Float = -1f,
+     *      color: Int? = null,
+     *      strokeWidth: Float = -1f,
+     *      animate: Boolean = true,
+     *      duration: Long = -1L,
+     *      interpolator: TimeInterpolator? = null,
+     *      delay: Long = 0,
+     *      onAnimationEnd: Runnable? = null
+     * )
+     *
+     * @param weight an optional style value for `wght` in fontVariationSettings.
+     * @param width an optional style value for `wdth` in fontVariationSettings.
+     * @param opticalSize an optional style value for `opsz` in fontVariationSettings.
+     * @param roundness an optional style value for `ROND` in fontVariationSettings.
+     */
+    fun setTextStyle(
+        weight: Int = -1,
+        width: Int = -1,
+        opticalSize: Int = -1,
+        roundness: Int = -1,
+        textSize: Float = -1f,
+        color: Int? = null,
+        strokeWidth: Float = -1f,
+        animate: Boolean = true,
+        duration: Long = -1L,
+        interpolator: TimeInterpolator? = null,
+        delay: Long = 0,
+        onAnimationEnd: Runnable? = null
+    ) {
+        val fvar = fontVariationUtils.updateFontVariation(
+            weight = weight,
+            width = width,
+            opticalSize = opticalSize,
+            roundness = roundness,)
+        setTextStyle(
+            fvar = fvar,
+            textSize = textSize,
+            color = color,
+            strokeWidth = strokeWidth,
+            animate = animate,
+            duration = duration,
+            interpolator = interpolator,
+            delay = delay,
+            onAnimationEnd = onAnimationEnd,
+        )
+    }
 }
 
-private fun <V> SparseArray<V>.getOrElse(key: Int, defaultValue: () -> V): V {
-    var v = get(key)
-    if (v == null) {
-        v = defaultValue()
-        put(key, v)
-    }
-    return v
-}
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 468a8b1..3eb7fd8 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
@@ -473,6 +473,7 @@
         // TODO(172943390): Add other interpolation or support custom interpolator.
         out.textSize = MathUtils.lerp(from.textSize, to.textSize, progress)
         out.color = ColorUtils.blendARGB(from.color, to.color, progress)
+        out.strokeWidth = MathUtils.lerp(from.strokeWidth, to.strokeWidth, progress)
     }
 
     // Shape the text and stores the result to out argument.
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/DemotingTestWithoutBugDetector.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/DemotingTestWithoutBugDetector.kt
index f64ea45..09762b0 100644
--- a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/DemotingTestWithoutBugDetector.kt
+++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/DemotingTestWithoutBugDetector.kt
@@ -25,9 +25,12 @@
 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 java.util.EnumSet
+import java.util.regex.Pattern
 import org.jetbrains.uast.UAnnotation
 import org.jetbrains.uast.UElement
 
+@Suppress("UnstableApiUsage") // For linter api
 class DemotingTestWithoutBugDetector : Detector(), SourceCodeScanner {
     override fun getApplicableUastTypes(): List<Class<out UElement>> {
         return listOf(UAnnotation::class.java)
@@ -36,22 +39,46 @@
     override fun createUastHandler(context: JavaContext): UElementHandler {
         return object : UElementHandler() {
             override fun visitAnnotation(node: UAnnotation) {
-                if (node.qualifiedName !in DEMOTING_ANNOTATION) {
-                    return
+                // Annotations having int bugId field
+                if (node.qualifiedName in DEMOTING_ANNOTATION_BUG_ID) {
+                    if (!containsBugId(node)) {
+                        val location = context.getLocation(node)
+                        val message = "Please attach a bug id to track demoted test"
+                        context.report(ISSUE, node, location, message)
+                    }
                 }
-                val bugId = node.findAttributeValue("bugId")!!.evaluate() as Int
-                if (bugId <= 0) {
-                    val location = context.getLocation(node)
-                    val message = "Please attach a bug id to track demoted test"
-                    context.report(ISSUE, node, location, message)
+                // @Ignore has a String field for specifying reasons
+                if (node.qualifiedName == DEMOTING_ANNOTATION_IGNORE) {
+                    if (!containsBugString(node)) {
+                        val location = context.getLocation(node)
+                        val message = "Please attach a bug (e.g. b/123) to track demoted test"
+                        context.report(ISSUE, node, location, message)
+                    }
                 }
             }
         }
     }
 
+    private fun containsBugId(node: UAnnotation): Boolean {
+        val bugId = node.findAttributeValue("bugId")?.evaluate() as Int?
+        return bugId != null && bugId > 0
+    }
+
+    private fun containsBugString(node: UAnnotation): Boolean {
+        val reason = node.findAttributeValue("value")?.evaluate() as String?
+        val bugPattern = Pattern.compile("b/\\d+")
+        return reason != null && bugPattern.matcher(reason).find()
+    }
+
     companion object {
-        val DEMOTING_ANNOTATION =
-            listOf("androidx.test.filters.FlakyTest", "android.platform.test.annotations.FlakyTest")
+        val DEMOTING_ANNOTATION_BUG_ID =
+            listOf(
+                "androidx.test.filters.FlakyTest",
+                "android.platform.test.annotations.FlakyTest",
+                "android.platform.test.rule.PlatinumRule.Platinum",
+            )
+
+        const val DEMOTING_ANNOTATION_IGNORE = "org.junit.Ignore"
 
         @JvmField
         val ISSUE: Issue =
@@ -70,7 +97,7 @@
                 implementation =
                     Implementation(
                         DemotingTestWithoutBugDetector::class.java,
-                        Scope.JAVA_FILE_SCOPE
+                        EnumSet.of(Scope.JAVA_FILE, Scope.TEST_SOURCES)
                     )
             )
     }
diff --git a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/DemotingTestWithoutBugDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/DemotingTestWithoutBugDetectorTest.kt
index 557c300..a1e6f92 100644
--- a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/DemotingTestWithoutBugDetectorTest.kt
+++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/DemotingTestWithoutBugDetectorTest.kt
@@ -20,8 +20,11 @@
 import com.android.tools.lint.checks.infrastructure.TestFiles
 import com.android.tools.lint.detector.api.Detector
 import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.Scope
+import java.util.EnumSet
 import org.junit.Test
 
+@Suppress("UnstableApiUsage")
 class DemotingTestWithoutBugDetectorTest : SystemUILintDetectorTest() {
 
     override fun getDetector(): Detector = DemotingTestWithoutBugDetector()
@@ -45,6 +48,7 @@
                     .indented(),
                 *stubs
             )
+            .customScope(testScope)
             .issues(DemotingTestWithoutBugDetector.ISSUE)
             .run()
             .expectClean()
@@ -65,6 +69,7 @@
                     .indented(),
                 *stubs
             )
+            .customScope(testScope)
             .issues(DemotingTestWithoutBugDetector.ISSUE)
             .run()
             .expectClean()
@@ -88,6 +93,7 @@
                     .indented(),
                 *stubs
             )
+            .customScope(testScope)
             .issues(DemotingTestWithoutBugDetector.ISSUE)
             .run()
             .expect(
@@ -115,6 +121,7 @@
                     .indented(),
                 *stubs
             )
+            .customScope(testScope)
             .issues(DemotingTestWithoutBugDetector.ISSUE)
             .run()
             .expect(
@@ -127,6 +134,145 @@
             )
     }
 
+    @Test
+    fun testExcludeDevices_withBugId() {
+        lint()
+            .files(
+                TestFiles.java(
+                        """
+                        package test.pkg;
+                        import android.platform.test.rule.PlatinumRule.Platinum;
+
+                        @Platinum(devices = "foo,bar", bugId = 123)
+                        public class TestClass {
+                            public void testCase() {}
+                        }
+                    """
+                    )
+                    .indented(),
+                *stubs
+            )
+            .customScope(testScope)
+            .issues(DemotingTestWithoutBugDetector.ISSUE)
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun testExcludeDevices_withoutBugId() {
+        lint()
+            .files(
+                TestFiles.java(
+                        """
+                        package test.pkg;
+                        import android.platform.test.rule.PlatinumRule.Platinum;
+
+                        @Platinum(devices = "foo,bar")
+                        public class TestClass {
+                            public void testCase() {}
+                        }
+                    """
+                    )
+                    .indented(),
+                *stubs
+            )
+            .customScope(testScope)
+            .issues(DemotingTestWithoutBugDetector.ISSUE)
+            .run()
+            .expect(
+                """
+                src/test/pkg/TestClass.java:4: Warning: Please attach a bug id to track demoted test [DemotingTestWithoutBug]
+                @Platinum(devices = "foo,bar")
+                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                0 errors, 1 warnings
+                """
+            )
+    }
+
+    @Test
+    fun testIgnore_withBug() {
+        lint()
+            .files(
+                TestFiles.java(
+                        """
+                        package test.pkg;
+                        import org.junit.Ignore;
+
+                        @Ignore("Blocked by b/123.")
+                        public class TestClass {
+                            public void testCase() {}
+                        }
+                    """
+                    )
+                    .indented(),
+                *stubs
+            )
+            .customScope(testScope)
+            .issues(DemotingTestWithoutBugDetector.ISSUE)
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun testIgnore_withoutBug() {
+        lint()
+            .files(
+                TestFiles.java(
+                        """
+                        package test.pkg;
+                        import org.junit.Ignore;
+
+                        @Ignore
+                        public class TestClass {
+                            public void testCase() {}
+                        }
+                    """
+                    )
+                    .indented(),
+                *stubs
+            )
+            .customScope(testScope)
+            .issues(DemotingTestWithoutBugDetector.ISSUE)
+            .run()
+            .expect(
+                """
+                src/test/pkg/TestClass.java:4: Warning: Please attach a bug (e.g. b/123) to track demoted test [DemotingTestWithoutBug]
+                @Ignore
+                ~~~~~~~
+                0 errors, 1 warnings
+                """
+            )
+
+        lint()
+            .files(
+                TestFiles.java(
+                        """
+                        package test.pkg;
+                        import org.junit.Ignore;
+
+                        @Ignore("Not ready")
+                        public class TestClass {
+                            public void testCase() {}
+                        }
+                    """
+                    )
+                    .indented(),
+                *stubs
+            )
+            .customScope(testScope)
+            .issues(DemotingTestWithoutBugDetector.ISSUE)
+            .run()
+            .expect(
+                """
+                src/test/pkg/TestClass.java:4: Warning: Please attach a bug (e.g. b/123) to track demoted test [DemotingTestWithoutBug]
+                @Ignore("Not ready")
+                ~~~~~~~~~~~~~~~~~~~~
+                0 errors, 1 warnings
+                """
+            )
+    }
+
+    private val testScope = EnumSet.of(Scope.JAVA_FILE, Scope.TEST_SOURCES)
     private val filtersFlakyTestStub: TestFile =
         java(
             """
@@ -147,5 +293,34 @@
         }
         """
         )
-    private val stubs = arrayOf(filtersFlakyTestStub, annotationsFlakyTestStub)
+    private val annotationsPlatinumStub: TestFile =
+        java(
+            """
+        package android.platform.test.rule;
+
+        public class PlatinumRule {
+            public @interface Platinum {
+                String devices();
+                int bugId() default -1;
+            }
+        }
+        """
+        )
+    private val annotationsIgnoreStub: TestFile =
+        java(
+            """
+        package org.junit;
+
+        public @interface Ignore {
+            String value() default "";
+        }
+        """
+        )
+    private val stubs =
+        arrayOf(
+            filtersFlakyTestStub,
+            annotationsFlakyTestStub,
+            annotationsPlatinumStub,
+            annotationsIgnoreStub
+        )
 }
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt
index 0d88075..f9e8aaf 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt
@@ -184,6 +184,9 @@
         /** Flag denoting whether the Monochromatic Theme is enabled. */
         const val FLAG_NAME_MONOCHROMATIC_THEME = "is_monochromatic_theme_enabled"
 
+        /** Flag denoting AI Wallpapers are enabled in wallpaper picker. */
+        const val FLAG_NAME_WALLPAPER_PICKER_UI_FOR_AIWP = "wallpaper_picker_ui_for_aiwp"
+
         object Columns {
             /** String. Unique ID for the flag. */
             const val NAME = "name"
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
index 1d28c63..c0b69c1 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
@@ -189,10 +189,12 @@
 
         /** Get the text for secondaryLabel. */
         public String getSecondaryLabel(String stateText) {
-            if (TextUtils.isEmpty(secondaryLabel)) {
+            // Use a local reference as the value might change from other threads
+            CharSequence localSecondaryLabel = secondaryLabel;
+            if (TextUtils.isEmpty(localSecondaryLabel)) {
                 return stateText;
             }
-            return secondaryLabel.toString();
+            return localSecondaryLabel.toString();
         }
 
         public boolean copyTo(State other) {
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java
index 70b5d73..b7088d5 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java
@@ -50,6 +50,13 @@
     boolean isPulsing();
 
     /**
+     * Is device dreaming. This method is more inclusive than
+     * {@link android.service.dreams.IDreamManager.isDreaming}, as it will return true during the
+     * dream's wake-up phase.
+     */
+    boolean isDreaming();
+
+    /**
      * Adds a state listener
      */
     void addCallback(StateListener listener);
diff --git a/packages/SystemUI/res-keyguard/values-eu/strings.xml b/packages/SystemUI/res-keyguard/values-eu/strings.xml
index d5dba42..bf1e716 100644
--- a/packages/SystemUI/res-keyguard/values-eu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-eu/strings.xml
@@ -30,7 +30,7 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Kargatzen"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Bizkor kargatzen"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mantso kargatzen"</string>
-    <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Kargatzea optimizatu da bateria ez kaltetzeko"</string>
+    <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Bateria ez kaltetzeko, kargatzeko modua optimizatu da"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Desblokeatzeko, sakatu Menua."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Sarea blokeatuta dago"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Ez dago SIM txartelik"</string>
diff --git a/packages/SystemUI/res-keyguard/values-hi/strings.xml b/packages/SystemUI/res-keyguard/values-hi/strings.xml
index fe72fe0..2bb4a03 100644
--- a/packages/SystemUI/res-keyguard/values-hi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hi/strings.xml
@@ -30,7 +30,7 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • चार्ज हो रहा है"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • तेज़ चार्ज हो रहा है"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • धीरे चार्ज हो रहा है"</string>
-    <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • बैटरी को नुकसान से बचाने के लिए, उसकी चार्जिंग को ऑप्टिमाइज़ किया गया"</string>
+    <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • बैटरी को नुकसान से बचाने के लिए, चार्जिंग को ऑप्टिमाइज़ किया गया"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"लॉक खोलने के लिए मेन्यू दबाएं."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"नेटवर्क लॉक किया हुआ है"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"कोई सिम कार्ड नहीं है"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ja/strings.xml b/packages/SystemUI/res-keyguard/values-ja/strings.xml
index 390bfcb..eb837b4 100644
--- a/packages/SystemUI/res-keyguard/values-ja/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ja/strings.xml
@@ -30,7 +30,7 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 充電中"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 急速充電中"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 低速充電中"</string>
-    <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 充電最適化済み(バッテリーを保護)"</string>
+    <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • バッテリーを保護するために、充電が最適化されています"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"メニューからロックを解除できます。"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"ネットワークがロックされました"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM カードなし"</string>
diff --git a/packages/SystemUI/res-keyguard/values-kk/strings.xml b/packages/SystemUI/res-keyguard/values-kk/strings.xml
index 845af85..8f3a984 100644
--- a/packages/SystemUI/res-keyguard/values-kk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kk/strings.xml
@@ -30,7 +30,7 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Зарядталуда"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Жылдам зарядталуда"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Баяу зарядталуда"</string>
-    <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Батареяны қорғау үшін, зарядтау оңтайландырылды"</string>
+    <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Батареяны қорғау үшін зарядтау оңтайландырылды"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Ашу үшін \"Мәзір\" пернесін басыңыз."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Желі құлыптаулы"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM картасы салынбаған"</string>
diff --git a/packages/SystemUI/res-keyguard/values-land/dimens.xml b/packages/SystemUI/res-keyguard/values-land/dimens.xml
index f1aa544..a4e7a5f 100644
--- a/packages/SystemUI/res-keyguard/values-land/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values-land/dimens.xml
@@ -27,6 +27,4 @@
     <integer name="scaled_password_text_size">26</integer>
 
     <dimen name="bouncer_user_switcher_y_trans">@dimen/status_bar_height</dimen>
-    <dimen name="bouncer_user_switcher_view_mode_user_switcher_bottom_margin">0dp</dimen>
-    <dimen name="bouncer_user_switcher_view_mode_view_flipper_bottom_margin">0dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
index 4633290..08cc6e2 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
@@ -30,7 +30,7 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 正在充电"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 正在快速充电"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 正在慢速充电"</string>
-    <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 为保护电池,充电过程已优化"</string>
+    <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 为保护电池,充电方式已优化"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"按“菜单”即可解锁。"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"网络已锁定"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"没有 SIM 卡"</string>
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index 992d143..edd6eff 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -123,9 +123,7 @@
     <dimen name="bouncer_user_switcher_item_padding_vertical">10dp</dimen>
     <dimen name="bouncer_user_switcher_item_padding_horizontal">12dp</dimen>
     <dimen name="bouncer_user_switcher_header_padding_end">44dp</dimen>
-    <dimen name="bouncer_user_switcher_y_trans">0dp</dimen>
-    <dimen name="bouncer_user_switcher_view_mode_user_switcher_bottom_margin">0dp</dimen>
-    <dimen name="bouncer_user_switcher_view_mode_view_flipper_bottom_margin">0dp</dimen>
+    <dimen name="bouncer_user_switcher_y_trans">80dp</dimen>
 
     <!-- 2 * the margin + size should equal the plus_margin -->
     <dimen name="user_switcher_icon_large_margin">16dp</dimen>
diff --git a/packages/SystemUI/res-product/values-af/strings.xml b/packages/SystemUI/res-product/values-af/strings.xml
index 09c9127..a1cefadb 100644
--- a/packages/SystemUI/res-product/values-af/strings.xml
+++ b/packages/SystemUI/res-product/values-af/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Jy het die foon <xliff:g id="NUMBER">%d</xliff:g> keer verkeerd probeer ontsluit. Die werkprofiel sal verwyder word, wat alle profieldata sal uitvee."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd geteken. Na nóg <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal jy gevra word om jou e-posrekening te gebruik om jou tablet te ontsluit.\n\n Probeer weer oor <xliff:g id="NUMBER_2">%3$d</xliff:g> sekondes."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd geteken. Na nóg <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal jy gevra word om jou e-posrekening te gebruik om jou foon te ontsluit.\n\n Probeer weer oor <xliff:g id="NUMBER_2">%3$d</xliff:g> sekondes."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Die vingerafdruksensor is op die aan/af-skakelaar. Dit is die plat knoppie langs die verhewe volumeknoppie aan die kant van die tablet."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Die vingerafdruksensor is op die aan/af-skakelaar. Dit is die plat knoppie langs die verhewe volumeknoppie aan die kant van die toestel."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Die vingerafdruksensor is op die aan/af-skakelaar. Dit is die plat knoppie langs die verhewe volumeknoppie aan die kant van die foon."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Ontsluit jou foon vir meer opsies"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Ontsluit jou tablet vir meer opsies"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Ontsluit jou toestel vir meer opsies"</string>
diff --git a/packages/SystemUI/res-product/values-am/strings.xml b/packages/SystemUI/res-product/values-am/strings.xml
index c08e194..fad5adb 100644
--- a/packages/SystemUI/res-product/values-am/strings.xml
+++ b/packages/SystemUI/res-product/values-am/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"ስልኩን <xliff:g id="NUMBER">%d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለመክፈት ሞክረዋል። የስራ መገለጫው ይወገዳል፣ ይህም ሁሉንም የመገለጫ ውሂብ ይሰርዛል።"</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"የመክፈቻ ስርዓተ ጥለቱን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ በትክክል አልሳሉትም። ከ<xliff:g id="NUMBER_1">%2$d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ የኢሜይል መለያ ተጠቅመው ጡባዊዎን እንዲከፍቱ ይጠየቃሉ።\n\n ከ<xliff:g id="NUMBER_2">%3$d</xliff:g> ከሰከንዶች በኋላ እንደገና ይሞክሩ።"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"የመክፈቻ ስርዓተ ጥለቱን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ በትክክል አልሳሉትም። ከ<xliff:g id="NUMBER_1">%2$d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ የኢሜይል መለያ ተጠቅመው ስልክዎን እንዲከፍቱ ይጠየቃሉ።\n\nእባክዎ ከ<xliff:g id="NUMBER_2">%3$d</xliff:g> ሰከንዶች በኋላ እንደገና ይሞክሩ።"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"የጣት አሻራ ዳሳሹ የማብሪያ/ማጥፊያ ቁልፉ ላይ ነው። በጡባዊው ጫፍ ላይ ከፍ ካለው የድምፅ አዝራር ቀጥሎ ያለው ጠፍጣፋ አዝራር ነው።"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"የጣት አሻራ ዳሳሹ የማብሪያ/ማጥፊያ ቁልፉ ላይ ነው። በመሣሪያው ጫፍ ላይ ከፍ ካለው የድምፅ አዝራር ቀጥሎ ያለው ጠፍጣፋ አዝራር ነው።"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"የጣት አሻራ ዳሳሹ የማብሪያ/ማጥፊያ ቁልፉ ላይ ነው። በስልኩ ጫፍ ላይ ከፍ ካለው የድምፅ አዝራር ቀጥሎ ያለው ጠፍጣፋ አዝራር ነው።"</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"ለተጨማሪ አማራጮች የእርስዎን ስልክ ይክፈቱ"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"ለተጨማሪ አማራጮች የእርስዎን ጡባዊ ይክፈቱ"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"ለተጨማሪ አማራጮች የእርስዎን መሣሪያ ይክፈቱ"</string>
diff --git a/packages/SystemUI/res-product/values-ar/strings.xml b/packages/SystemUI/res-product/values-ar/strings.xml
index 8922c27..a3e1bfd 100644
--- a/packages/SystemUI/res-product/values-ar/strings.xml
+++ b/packages/SystemUI/res-product/values-ar/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"أخطأت في محاولة فتح قفل الهاتف <xliff:g id="NUMBER">%d</xliff:g> مرة. ستتم إزالة الملف الشخصي للعمل، ومن ثم يتم حذف جميع بياناته."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"رسمت نقش فتح القفل بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%2$d</xliff:g> محاولة غير ناجحة أخرى، ستُطالَب بفتح قفل الجهاز اللوحي باستخدام معلومات حساب بريد إلكتروني.\n\n يُرجى إعادة المحاولة خلال <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانية."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"رسمت نقش فتح القفل بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%2$d</xliff:g> محاولة غير ناجحة أخرى، ستُطالَب بفتح قفل الهاتف باستخدام حساب بريد إلكتروني.\n\n يُرجى إعادة المحاولة خلال <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانية."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"توجد أداة استشعار بصمة الإصبع على زر التشغيل. زر التشغيل هو الزر المسطّح بجانب زرَّي التحكّم بمستوى الصوت البارزَين في الجزء الجانبي من الجهاز اللوحي."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"توجد أداة استشعار بصمة الإصبع على زر التشغيل. زر التشغيل هو الزر المسطّح بجانب زرَّي التحكّم بمستوى الصوت البارزَين في الجزء الجانبي من الجهاز."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"توجد أداة استشعار بصمة الإصبع على زر التشغيل. زر التشغيل هو الزر المسطّح بجانب زرَّي التحكّم بمستوى الصوت البارزَين في الجزء الجانبي من الهاتف."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"يمكنك فتح قفل هاتفك للوصول إلى مزيد من الخيارات."</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"يمكنك فتح قفل جهازك اللوحي للوصول إلى مزيد من الخيارات."</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"يمكنك فتح قفل جهازك للوصول إلى مزيد من الخيارات."</string>
diff --git a/packages/SystemUI/res-product/values-as/strings.xml b/packages/SystemUI/res-product/values-as/strings.xml
index c8aedb3..e16723b 100644
--- a/packages/SystemUI/res-product/values-as/strings.xml
+++ b/packages/SystemUI/res-product/values-as/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"আপুনি ফ’নটো আনলক কৰিবলৈ <xliff:g id="NUMBER">%d</xliff:g> বাৰ ভুলকৈ প্ৰয়াস কৰিছে। কৰ্মস্থানৰ প্ৰ’ফাইলটো আঁতৰোৱা হ’ব, যিয়ে প্ৰ’ফাইলটোৰ আটাইবোৰ ডেটা মচি পেলাব।"</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"আপুনি নিজৰ আনলক কৰা আৰ্হিটো <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুলকৈ আঁকিছে। আৰু <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰ ভুলকৈ প্ৰয়াস কৰাৰ পাছত আপোনাক নিজৰ টেবলেটটো এটা ইমেইল একাউণ্টৰ জৰিয়তে আনলক কৰিবলৈ কোৱা হ’ব।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ছেকেণ্ডৰ পাছত পুনৰ চেষ্টা কৰক।"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"আপুনি নিজৰ আনলক কৰা আৰ্হিটো <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুলকৈ আঁকিছে। আৰু <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰ ভুলকৈ প্ৰয়াস কৰাৰ পাছত আপোনাক নিজৰ ফ’নটো এটা ইমেইল একাউণ্টৰ জৰিয়তে আনলক কৰিবলৈ কোৱা হ’ব।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ছেকেণ্ডৰ পাছত পুনৰ চেষ্টা কৰক।"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"ফিংগাৰপ্ৰিণ্ট ছেন্সৰটো পাৱাৰ বুটামটোত আছে। এইটো হৈছে টেবলেটটোৰ প্ৰান্তত থকা উঠঙা ভলিউমৰ বুটামটোৰ কাষত থকা চেপেটা বুটামটো।"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"ফিংগাৰপ্ৰিণ্ট ছেন্সৰটো পাৱাৰ বুটামটোত আছে। এইটো হৈছে ডিভাইচটোৰ প্ৰান্তত থকা উঠঙা ভলিউমৰ বুটামটোৰ কাষত থকা চেপেটা বুটামটো।"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"ফিংগাৰপ্ৰিণ্ট ছেন্সৰটো পাৱাৰ বুটামটোত আছে। এইটো হৈছে ফ’নটোৰ প্ৰান্তত থকা উঠঙা ভলিউমৰ বুটামটোৰ কাষত থকা চেপেটা বুটামটো।"</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"অধিক বিকল্পৰ বাবে আপোনাৰ ফ’নটো আনলক কৰক"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"অধিক বিকল্পৰ বাবে আপোনাৰ টেবলেটটো আনলক কৰক"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"অধিক বিকল্পৰ বাবে আপোনাৰ ডিভাইচটো আনলক কৰক"</string>
diff --git a/packages/SystemUI/res-product/values-az/strings.xml b/packages/SystemUI/res-product/values-az/strings.xml
index fd514b3..cc8da78 100644
--- a/packages/SystemUI/res-product/values-az/strings.xml
+++ b/packages/SystemUI/res-product/values-az/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Telefonun kilidini açmaq üçün <xliff:g id="NUMBER">%d</xliff:g> dəfə yanlış cəhd etmisiniz. İş profili silinəcək və bütün data ləğv ediləcək."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Kilid açma modelini <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış çəkmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra planşet kilidini e-poçt hesabınızla açmaq tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniyə sonra cəhd edin."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Kilid açma modelini artıq <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış çəkmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra telefon kilidini e-poçt hesabınızla açmaq tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniyə sonra cəhd edin."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Barmaq izi sensoru enerji düyməsinin üzərindədir. Bu, planşetin kənarındakı qabarıq səs düyməsinin yanındakı yastı düymədir."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Barmaq izi sensoru enerji düyməsinin üzərindədir. Bu, cihazın kənarındakı qabarıq səs düyməsinin yanındakı yastı düymədir."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Barmaq izi sensoru enerji düyməsinin üzərindədir. Bu, telefonun kənarındakı qabarıq səs düyməsinin yanındakı yastı düymədir."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Daha çox seçim üçün telefonu kiliddən çıxarın"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Daha çox seçim üçün planşeti kiliddən çıxarın"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Daha çox seçim üçün cihazı kiliddən çıxarın"</string>
diff --git a/packages/SystemUI/res-product/values-b+sr+Latn/strings.xml b/packages/SystemUI/res-product/values-b+sr+Latn/strings.xml
index 287b3f6..c5007e8 100644
--- a/packages/SystemUI/res-product/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res-product/values-b+sr+Latn/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER">%d</xliff:g> puta. Uklonićemo poslovni profil, čime se brišu svi podaci sa profila."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Netačno ste nacrtali šablon za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, zatražićemo da otključate tablet pomoću imejl naloga.\n\n Probajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Netačno ste nacrtali šablon za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, zatražićemo da otključate telefon pomoću imejl naloga.\n\n Probajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Senzor za otisak prsta se nalazi na dugmetu za uključivanje. To je ravno dugme pored izdignutog dugmeta za jačinu zvuka na ivici tableta."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Senzor za otisak prsta se nalazi na dugmetu za uključivanje. To je ravno dugme pored izdignutog dugmeta za jačinu zvuka na ivici uređaja."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Senzor za otisak prsta se nalazi na dugmetu za uključivanje. To je ravno dugme pored izdignutog dugmeta za jačinu zvuka na ivici telefona."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Otključajte telefon za još opcija"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Otključajte tablet za još opcija"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Otključajte uređaj za još opcija"</string>
diff --git a/packages/SystemUI/res-product/values-be/strings.xml b/packages/SystemUI/res-product/values-be/strings.xml
index cf42bed..f021106 100644
--- a/packages/SystemUI/res-product/values-be/strings.xml
+++ b/packages/SystemUI/res-product/values-be/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Вы не змаглі разблакіраваць тэлефон столькі разоў: <xliff:g id="NUMBER">%d</xliff:g>. Працоўны профіль будзе выдалены, і гэта прывядзе да выдалення ўсіх даных у профілі."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Вы няправільна ўвялі ўзор разблакіроўкі столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) вам будзе прапанавана разблакіраваць планшэт, увайшоўшы ва ўліковы запіс электроннай пошты.\n\n Паўтарыце спробу праз <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Вы няправільна ўвялі ўзор разблакіроўкі столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) вам будзе прапанавана разблакіраваць тэлефон, увайшоўшы ва ўліковы запіс электроннай пошты.\n\n Паўтарыце спробу праз <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Сканер адбіткаў пальцаў знаходзіцца на кнопцы сілкавання. Гэта плоская кнопка побач з выпуклай кнопкай гучнасці на бакавой грані планшэта."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Сканер адбіткаў пальцаў знаходзіцца на кнопцы сілкавання. Гэта плоская кнопка побач з выпуклай кнопкай гучнасці на бакавой грані прылады."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Сканер адбіткаў пальцаў знаходзіцца на кнопцы сілкавання. Гэта плоская кнопка побач з выпуклай кнопкай гучнасці на бакавой грані тэлефона."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Каб адкрыць іншыя параметры, разблакіруйце тэлефон"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Каб адкрыць іншыя параметры, разблакіруйце планшэт"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Каб адкрыць іншыя параметры, разблакіруйце прыладу"</string>
diff --git a/packages/SystemUI/res-product/values-bg/strings.xml b/packages/SystemUI/res-product/values-bg/strings.xml
index 182ffa9..e57a56e 100644
--- a/packages/SystemUI/res-product/values-bg/strings.xml
+++ b/packages/SystemUI/res-product/values-bg/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Опитахте да отключите телефона и сбъркахте <xliff:g id="NUMBER">%d</xliff:g> пъти. Служебният потребителски профил ще бъде премахнат, при което ще се изтрият всички данни за него."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни опита ще бъдете помолени да отключите таблета си посредством имейл адрес.\n\n Опитайте отново след <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни опита ще бъдете помолени да отключите телефона посредством имейл адрес.\n\n Опитайте отново след <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Сензорът за отпечатъци се намира върху бутона за захранване. Този бутон е плосък и е разположен на ръба на таблета до повдигнатия бутон за силата на звука."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Сензорът за отпечатъци се намира върху бутона за захранване. Този бутон е плосък и е разположен на ръба на устройството до повдигнатия бутон за силата на звука."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Сензорът за отпечатъци се намира върху бутона за захранване. Този бутон е плосък и е разположен на ръба на телефона до повдигнатия бутон за силата на звука."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Отключете телефона си за още опции"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Отключете таблета си за още опции"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Отключете устройството си за още опции"</string>
diff --git a/packages/SystemUI/res-product/values-bn/strings.xml b/packages/SystemUI/res-product/values-bn/strings.xml
index d54de52..be1847a 100644
--- a/packages/SystemUI/res-product/values-bn/strings.xml
+++ b/packages/SystemUI/res-product/values-bn/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"আপনি <xliff:g id="NUMBER">%d</xliff:g> বার ভুল পদ্ধতিতে ফোন আনলক করার চেষ্টা করেছেন। অফিস প্রোফাইলটি সরিয়ে দেওয়া হবে, যার ফলে প্রোফাইলের সমস্ত ডেটা মুছে যাবে।"</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"আপনি <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুল পদ্ধতিতে প্যাটার্ন আনলক করার চেষ্টা করেছেন। আরও <xliff:g id="NUMBER_1">%2$d</xliff:g> বার এটি করলে আপনাকে প্যাটার্ন আনলক করতে একটি ইমেল অ্যাকাউন্ট ব্যবহার করতে বলা হবে।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> সেকেন্ড পরে আবার চেষ্টা করুন।"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"আপনি <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুল পদ্ধতিতে প্যাটার্ন আনলক করার চেষ্টা করেছেন। আরও <xliff:g id="NUMBER_1">%2$d</xliff:g> বার এটি করলে আপনাকে প্যাটার্ন আনলক করতে একটি ইমেল অ্যাকাউন্ট ব্যবহারের করতে বলা হবে।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> সেকেন্ড পরে আবার চেষ্টা করুন।"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"\'পাওয়ার\' বোতামের উপরে ফিঙ্গারপ্রিন্ট সেন্সর দেওয়া হয়েছে। ট্যাবলেটের প্রান্তে একটু বাইরে বেরিয়ে থাকা ভলিউমের বোতামের ঠিক পাশে এই ফ্ল্যাট বোতামটি আপনি খুঁজে পাবেন।"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"\'পাওয়ার\' বোতামের উপরে ফিঙ্গারপ্রিন্ট সেন্সর দেওয়া হয়েছে। ডিভাইসের সাইডে একটু বাইরে বেরিয়ে থাকা ভলিউমের বোতামের ঠিক পাশে এই ফ্ল্যাট বোতামটি আপনি খুঁজে পাবেন।"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"\'পাওয়ার\' বোতামের উপরে ফিঙ্গারপ্রিন্ট সেন্সর দেওয়া হয়েছে। ফোনের প্রান্তে একটু বাইরে বেরিয়ে থাকা ভলিউমের বোতামের ঠিক পাশে এই ফ্ল্যাট বোতামটি আপনি খুঁজে পাবেন।"</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"আরও বিকল্প দেখতে আপনার ফোন আনলক করুন"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"আরও বিকল্প দেখতে আপনার ট্যাবলেট আনলক করুন"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"আরও বিকল্প দেখতে আপনার ডিভাইস আনলক করুন"</string>
diff --git a/packages/SystemUI/res-product/values-bs/strings.xml b/packages/SystemUI/res-product/values-bs/strings.xml
index 9567125..2e91c01 100644
--- a/packages/SystemUI/res-product/values-bs/strings.xml
+++ b/packages/SystemUI/res-product/values-bs/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Pokušali ste neispravno otključati telefon <xliff:g id="NUMBER">%d</xliff:g> puta. Radni profil će se ukloniti i svi podaci s profila će se izbrisati."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Pogrešno ste nacrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, od vas će se tražiti da otključate tablet pomoću računa e-pošte. \n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Pogrešno ste nacrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, od vas će se tražiti da otključate telefon pomoću računa e-pošte. \n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Senzor za otisak prsta je na dugmetu za uključivanje. To je ravno dugme pored izdignutog dugmeta za jačinu zvuka na rubu tableta."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Senzor za otisak prsta je na dugmetu za uključivanje. To je ravno dugme pored izdignutog dugmeta za jačinu zvuka na rubu uređaja."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Senzor za otisak prsta je na dugmetu za uključivanje. To je ravno dugme pored izdignutog dugmeta za jačinu zvuka na rubu telefona."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Otključajte telefon za više opcija"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Otključajte tablet za više opcija"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Otključajte uređaj za više opcija"</string>
diff --git a/packages/SystemUI/res-product/values-ca/strings.xml b/packages/SystemUI/res-product/values-ca/strings.xml
index d318b4e..20665e9 100644
--- a/packages/SystemUI/res-product/values-ca/strings.xml
+++ b/packages/SystemUI/res-product/values-ca/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Has provat de desbloquejar el telèfon <xliff:g id="NUMBER">%d</xliff:g> vegades de manera incorrecta. El perfil de treball se suprimirà, juntament amb totes les dades que contingui."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, se\'t demanarà que desbloquegis la tauleta amb un compte de correu electrònic.\n\n Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%3$d</xliff:g> segons."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, se\'t demanarà que desbloquegis el telèfon amb un compte de correu electrònic.\n\n Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%3$d</xliff:g> segons."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"El sensor d\'empremtes digitals es troba al botó d\'engegada. És el botó pla situat al costat del botó de volum amb relleu al lateral de la tauleta."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"El sensor d\'empremtes digitals es troba al botó d\'engegada. És el botó pla situat al costat del botó de volum amb relleu al lateral del dispositiu."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"El sensor d\'empremtes digitals es troba al botó d\'engegada. És el botó pla situat al costat del botó de volum amb relleu al lateral del telèfon."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Desbloqueja el teu telèfon per veure més opcions"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Desbloqueja la teva tauleta per veure més opcions"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Desbloqueja el teu dispositiu per veure més opcions"</string>
diff --git a/packages/SystemUI/res-product/values-cs/strings.xml b/packages/SystemUI/res-product/values-cs/strings.xml
index e1ee268..10e3d0a 100644
--- a/packages/SystemUI/res-product/values-cs/strings.xml
+++ b/packages/SystemUI/res-product/values-cs/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Již <xliff:g id="NUMBER">%d</xliff:g>krát jste se pokusili odemknout telefon nesprávným způsobem. Pracovní profil bude odstraněn, čímž budou smazána všechna jeho data."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Již <xliff:g id="NUMBER_0">%1$d</xliff:g>krát jste nesprávně zadali své bezpečnostní gesto. Po <xliff:g id="NUMBER_1">%2$d</xliff:g>dalších neúspěšných pokusech budete požádáni o odemčení tabletu pomocí e-mailového účtu.\n\n Zkuste to znovu za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Již <xliff:g id="NUMBER_0">%1$d</xliff:g>krát jste nesprávně zadali své bezpečnostní gesto. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> dalších neúspěšných pokusech budete požádáni o odemčení telefonu pomocí e-mailového účtu.\n\n Zkuste to znovu za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Snímač otisků prstů je na vypínači. Je to ploché tlačítko vedle vystouplého tlačítka hlasitosti na hraně tabletu."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Snímač otisků prstů je na vypínači. Je to ploché tlačítko vedle vystouplého tlačítka hlasitosti na hraně zařízení."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Snímač otisků prstů je na vypínači. Je to ploché tlačítko vedle vystouplého tlačítka hlasitosti na hraně telefonu."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Chcete-li zobrazit další možnosti, odemkněte telefon"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Chcete-li zobrazit další možnosti, odemkněte tablet"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Chcete-li zobrazit další možnosti, odemkněte zařízení"</string>
diff --git a/packages/SystemUI/res-product/values-da/strings.xml b/packages/SystemUI/res-product/values-da/strings.xml
index 55bda69..baf4b75 100644
--- a/packages/SystemUI/res-product/values-da/strings.xml
+++ b/packages/SystemUI/res-product/values-da/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Du har forsøgt at låse telefonen op med den forkerte adgangskode <xliff:g id="NUMBER">%d</xliff:g> gange. Arbejdsprofilen fjernes, hvilket sletter alle profildata."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg bliver du bedt om at låse din tablet op ved hjælp af en mailkonto.\n\n Prøv igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg bliver du bedt om at låse din telefon op ved hjælp af en mailkonto.\n\n Prøv igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Fingeraftrykssensoren sidder på afbryderknappen. Det er den flade knap ved siden af den hævede lydstyrkeknap på siden af din tablet."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Fingeraftrykssensoren sidder på afbryderknappen. Det er den flade knap ved siden af den hævede lydstyrkeknap på siden af enheden."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Fingeraftrykssensoren sidder på afbryderknappen. Det er den flade knap ved siden af den hævede lydstyrkeknap på siden af telefonen."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Lås din telefon op for at se flere valgmuligheder"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Lås din tablet op for at se flere valgmuligheder"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Lås din enhed op for at se flere valgmuligheder"</string>
diff --git a/packages/SystemUI/res-product/values-de/strings.xml b/packages/SystemUI/res-product/values-de/strings.xml
index c82c739..d8c7e2e 100644
--- a/packages/SystemUI/res-product/values-de/strings.xml
+++ b/packages/SystemUI/res-product/values-de/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Du hast <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Smartphone zu entsperren. Das Arbeitsprofil wird nun entfernt und alle Profildaten werden gelöscht."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Du hast dein Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wirst du aufgefordert, dein Tablet mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuche es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden noch einmal."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Du hast dein Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wirst du aufgefordert, dein Smartphone mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuche es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden noch einmal."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Der Fingerabdrucksensor befindet sich auf der Ein-/Aus-Taste. Das ist die flache Taste neben der erhöhten Lautstärketaste am Rand des Tablets."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Der Fingerabdrucksensor befindet sich auf der Ein-/Aus-Taste. Das ist die flache Taste neben der erhöhten Lautstärketaste am Rand des Geräts."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Der Fingerabdrucksensor befindet sich auf der Ein-/Aus-Taste. Das ist die flache Taste neben der erhöhten Lautstärketaste am Rand des Smartphones."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Entsperre dein Smartphone für weitere Optionen"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Entsperre dein Tablet für weitere Optionen"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Entsperre dein Gerät für weitere Optionen"</string>
diff --git a/packages/SystemUI/res-product/values-el/strings.xml b/packages/SystemUI/res-product/values-el/strings.xml
index 3d38be4..51c45bc 100644
--- a/packages/SystemUI/res-product/values-el/strings.xml
+++ b/packages/SystemUI/res-product/values-el/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Δοκιμάσατε να ξεκλειδώσετε το τηλέφωνο <xliff:g id="NUMBER">%d</xliff:g> φορές χωρίς επιτυχία. Το προφίλ εργασίας θα καταργηθεί και θα διαγραφούν όλα τα δεδομένα προφίλ."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%2$d</xliff:g> ακόμα ανεπιτυχείς προσπάθειες, θα σας ζητηθεί να ξεκλειδώσετε το tablet με τη χρήση ενός λογαριασμού ηλεκτρονικού ταχυδρομείου.\n\n Δοκιμάστε να συνδεθείτε ξανά σε <xliff:g id="NUMBER_2">%3$d</xliff:g> δευτερόλεπτα."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%2$d</xliff:g> ακόμα ανεπιτυχείς προσπάθειες, θα σας ζητηθεί να ξεκλειδώσετε το τηλέφωνό σας με τη χρήση ενός λογαριασμού ηλεκτρονικού ταχυδρομείου.\n\n Δοκιμάστε ξανά σε <xliff:g id="NUMBER_2">%3$d</xliff:g> δευτερόλεπτα."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Ο αισθητήρας δακτυλικών αποτυπωμάτων βρίσκεται στο κουμπί λειτουργίας. Είναι το επίπεδο κουμπί δίπλα στο ανυψωμένο κουμπί έντασης ήχου στο άκρο του tablet."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Ο αισθητήρας δακτυλικών αποτυπωμάτων βρίσκεται στο κουμπί λειτουργίας. Είναι το επίπεδο κουμπί δίπλα στο ανυψωμένο κουμπί έντασης ήχου στο άκρο της συσκευής."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Ο αισθητήρας δακτυλικών αποτυπωμάτων βρίσκεται στο κουμπί λειτουργίας. Είναι το επίπεδο κουμπί δίπλα στο ανυψωμένο κουμπί έντασης ήχου στο άκρο του τηλεφώνου."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Ξεκλειδώστε το τηλέφωνό σας για περισσότερες επιλογές"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Ξεκλειδώστε το tablet για περισσότερες επιλογές"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Ξεκλειδώστε τη συσκευή σας για περισσότερες επιλογές"</string>
diff --git a/packages/SystemUI/res-product/values-en-rAU/strings.xml b/packages/SystemUI/res-product/values-en-rAU/strings.xml
index 04e63f5..1a489f7 100644
--- a/packages/SystemUI/res-product/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res-product/values-en-rAU/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the tablet."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the device."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the phone."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Unlock your phone for more options"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Unlock your tablet for more options"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Unlock your device for more options"</string>
diff --git a/packages/SystemUI/res-product/values-en-rCA/strings.xml b/packages/SystemUI/res-product/values-en-rCA/strings.xml
index 131c42a..47e62c0 100644
--- a/packages/SystemUI/res-product/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res-product/values-en-rCA/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"The fingerprint sensor is on the power button. It\'s the flat button next to the raised volume button on the edge of the tablet."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"The fingerprint sensor is on the power button. It\'s the flat button next to the raised volume button on the edge of the device."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"The fingerprint sensor is on the power button. It\'s the flat button next to the raised volume button on the edge of the phone."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Unlock your phone for more options"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Unlock your tablet for more options"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Unlock your device for more options"</string>
diff --git a/packages/SystemUI/res-product/values-en-rGB/strings.xml b/packages/SystemUI/res-product/values-en-rGB/strings.xml
index 04e63f5..1a489f7 100644
--- a/packages/SystemUI/res-product/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res-product/values-en-rGB/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the tablet."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the device."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the phone."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Unlock your phone for more options"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Unlock your tablet for more options"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Unlock your device for more options"</string>
diff --git a/packages/SystemUI/res-product/values-en-rIN/strings.xml b/packages/SystemUI/res-product/values-en-rIN/strings.xml
index 04e63f5..1a489f7 100644
--- a/packages/SystemUI/res-product/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res-product/values-en-rIN/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the tablet."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the device."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the phone."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Unlock your phone for more options"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Unlock your tablet for more options"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Unlock your device for more options"</string>
diff --git a/packages/SystemUI/res-product/values-en-rXC/strings.xml b/packages/SystemUI/res-product/values-en-rXC/strings.xml
index aa895e1..c42b920 100644
--- a/packages/SystemUI/res-product/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res-product/values-en-rXC/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‏‏‏‏‎‏‎‏‎‎‏‎‏‏‏‏‎‎‎‎‎‎‎‏‏‏‏‎‎‎‏‏‎‏‎‏‏‎‎‏‏‎‎‎‎‎‏‎‎‏‏‎‏‏‎‎You have incorrectly attempted to unlock the phone ‎‏‎‎‏‏‎<xliff:g id="NUMBER">%d</xliff:g>‎‏‎‎‏‏‏‎ times. The work profile will be removed, which will delete all profile data.‎‏‎‎‏‎"</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‏‏‎‏‎‎‎‎‎‎‏‏‏‎‎‏‏‎‎‏‏‎‎‎‏‎‎‎‏‏‎‏‎‏‏‏‎‎‎‏‏‎‎‎‏‎‏‎‏‏‏‏‏‎‎‎‎You have incorrectly drawn your unlock pattern ‎‏‎‎‏‏‎<xliff:g id="NUMBER_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ times. After ‎‏‎‎‏‏‎<xliff:g id="NUMBER_1">%2$d</xliff:g>‎‏‎‎‏‏‏‎ more unsuccessful attempts, you will be asked to unlock your tablet using an email account.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎ Try again in ‎‏‎‎‏‏‎<xliff:g id="NUMBER_2">%3$d</xliff:g>‎‏‎‎‏‏‏‎ seconds.‎‏‎‎‏‎"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‎‎‏‏‏‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‎‏‎‎‎‏‏‎‎‎‏‏‏‎‏‏‎‎‎‎‎‏‏‏‏‎‎‏‏‏‎‏‏‎‏‎You have incorrectly drawn your unlock pattern ‎‏‎‎‏‏‎<xliff:g id="NUMBER_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ times. After ‎‏‎‎‏‏‎<xliff:g id="NUMBER_1">%2$d</xliff:g>‎‏‎‎‏‏‏‎ more unsuccessful attempts, you will be asked to unlock your phone using an email account.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎ Try again in ‎‏‎‎‏‏‎<xliff:g id="NUMBER_2">%3$d</xliff:g>‎‏‎‎‏‏‏‎ seconds.‎‏‎‎‏‎"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‏‎‏‏‏‎‎‎‏‏‎‏‏‏‎‏‏‏‎‎‎‎‎‎‎‎‎‎‏‏‎‎‏‏‏‏‏‎‎‎‎‏‎‎‏‏‎‎‏‏‎‎‏‎‎‏‎The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the tablet.‎‏‎‎‏‎"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‏‎‏‎‎‏‏‏‏‎‎‎‏‏‏‎‏‏‎‎‎‏‎‏‎‎‏‏‎‏‏‎‎‎‎‏‏‎‎‎‏‏‎‏‎‎‎‏‏‏‎‎‎‏‎‏‎The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the device.‎‏‎‎‏‎"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‎‎‎‏‎‏‎‏‏‎‏‏‎‎‏‎‏‏‎‎‎‏‏‎‏‎‎‏‏‏‏‎‎‎‏‎‎‎‎‏‏‏‎The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the phone.‎‏‎‎‏‎"</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‎‏‏‎‏‎‏‏‏‏‎‏‏‎‏‏‏‏‎‎‏‏‏‎‎‎‎‎‏‏‎‏‏‏‏‏‎‏‏‎‏‏‎‎‏‏‏‎‎‎‎‏‏‎Unlock your phone for more options‎‏‎‎‏‎"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‎‎‏‏‎‏‏‎‏‏‎‎‏‎‏‏‏‏‎‎‏‏‏‏‎‎‏‏‏‏‎‏‏‏‏‎‎‏‏‎‎‏‎‏‎‎‎‎‏‏‏‎‎‏‎‏‎Unlock your tablet for more options‎‏‎‎‏‎"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‏‏‏‎‏‏‎‏‎‎‏‎‎‎‏‏‎‏‎‎‎‏‏‎‎‎‎‏‏‎‏‏‎‎‎‏‎‏‎‎‏‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎Unlock your device for more options‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res-product/values-es-rUS/strings.xml b/packages/SystemUI/res-product/values-es-rUS/strings.xml
index 7e0eec6..fff59b4 100644
--- a/packages/SystemUI/res-product/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res-product/values-es-rUS/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de manera incorrecta. Se quitará el perfil de trabajo, lo que borrará todos los datos asociados."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Dibujaste el patrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees la tablet mediante una cuenta de correo electrónico.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Dibujaste el patrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees el dispositivo mediante una cuenta de correo electrónico.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"El sensor de huellas dactilares está en el botón de encendido. Es el botón plano que está junto al botón de volumen en relieve, en el borde de la tablet."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"El sensor de huellas dactilares está en el botón de encendido. Es el botón plano que está junto al botón de volumen en relieve, en el borde del dispositivo."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"El sensor de huellas dactilares está en el botón de encendido. Es el botón plano que está junto al botón de volumen en relieve, en el borde del teléfono."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Desbloquea el teléfono para ver más opciones"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Desbloquea la tablet para ver más opciones"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Desbloquea el dispositivo para ver más opciones"</string>
diff --git a/packages/SystemUI/res-product/values-es/strings.xml b/packages/SystemUI/res-product/values-es/strings.xml
index 970c615..2ad0a9a 100644
--- a/packages/SystemUI/res-product/values-es/strings.xml
+++ b/packages/SystemUI/res-product/values-es/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Has intentado desbloquear el teléfono de forma incorrecta <xliff:g id="NUMBER">%d</xliff:g> veces. Se quitará este perfil de trabajo y se eliminarán todos sus datos."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Has dibujado un patrón de desbloqueo incorrecto <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Si se producen <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se te pedirá que desbloquees el tablet con una cuenta de correo electrónico.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Has dibujado un patrón de desbloqueo incorrecto <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Si se producen <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se te pedirá que desbloquees el teléfono con una cuenta de correo electrónico.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"El sensor de huellas digitales está en el botón de encendido. Es el botón plano situado junto al botón de volumen con relieve en el lateral de la tablet."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"El sensor de huellas digitales está en el botón de encendido. Es el botón plano situado junto al botón de volumen con relieve en el lateral del dispositivo."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"El sensor de huellas digitales está en el botón de encendido. Es el botón plano situado junto al botón de volumen con relieve en el lateral del teléfono."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Desbloquea el teléfono para ver más opciones"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Desbloquea el tablet para ver más opciones"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Desbloquea el dispositivo para ver más opciones"</string>
diff --git a/packages/SystemUI/res-product/values-et/strings.xml b/packages/SystemUI/res-product/values-et/strings.xml
index ae463f2..e6cc6e7 100644
--- a/packages/SystemUI/res-product/values-et/strings.xml
+++ b/packages/SystemUI/res-product/values-et/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Olete püüdnud <xliff:g id="NUMBER">%d</xliff:g> korda telefoni valesti avada. Tööprofiil eemaldatakse ja kõik profiiliandmed kustutatakse."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset palutakse teil tahvelarvuti avada meilikontoga.\n\n Proovige uuesti <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundi pärast."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset palutakse teil telefon avada meilikontoga.\n\n Proovige uuesti <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundi pärast."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Sõrmejäljeandur asub toitenupul. See on tahvelarvuti küljel helitugevuse kõrgendatud nupu kõrval olev lame nupp."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Sõrmejäljeandur asub toitenupul. See on seadme küljel helitugevuse kõrgendatud nupu kõrval olev lame nupp."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Sõrmejäljeandur asub toitenupul. See on telefoni küljel helitugevuse kõrgendatud nupu kõrval olev lame nupp."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Lisavalikute nägemiseks avage oma telefon"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Lisavalikute nägemiseks avage oma tahvelarvuti"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Lisavalikute nägemiseks avage oma seade"</string>
diff --git a/packages/SystemUI/res-product/values-eu/strings.xml b/packages/SystemUI/res-product/values-eu/strings.xml
index 7cf68f6..bf637f0 100644
--- a/packages/SystemUI/res-product/values-eu/strings.xml
+++ b/packages/SystemUI/res-product/values-eu/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"<xliff:g id="NUMBER">%d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Laneko profila kendu egingo da eta, ondorioz, profileko datu guztiak ezabatuko dira."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Desblokeatzeko eredua oker marraztu duzu <xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz oker marrazten baduzu, tableta posta-kontu baten bidez desblokeatzeko eskatuko dizugu.\n\n Saiatu berriro <xliff:g id="NUMBER_2">%3$d</xliff:g> segundo barru."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Desblokeatzeko eredua oker marraztu duzu <xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz oker marrazten baduzu, telefonoa posta-kontu baten bidez desblokeatzeko eskatuko dizugu.\n\n Saiatu berriro <xliff:g id="NUMBER_2">%3$d</xliff:g> segundo barru."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Hatz-marken sentsorea etengailuan dago. Tabletaren ertzeko bolumen-botoi goratuaren ondoan dagoen botoi laua da."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Hatz-marken sentsorea etengailuan dago. Gailuaren ertzeko bolumen-botoi goratuaren ondoan dagoen botoi laua da."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Hatz-marken sentsorea etengailuan dago. Telefonoaren ertzeko bolumen-botoi goratuaren ondoan dagoen botoi laua da."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Desblokeatu telefonoa aukera gehiago ikusteko"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Desblokeatu tableta aukera gehiago ikusteko"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Desblokeatu gailua aukera gehiago ikusteko"</string>
diff --git a/packages/SystemUI/res-product/values-fa/strings.xml b/packages/SystemUI/res-product/values-fa/strings.xml
index 5ff3011..3677dfe 100644
--- a/packages/SystemUI/res-product/values-fa/strings.xml
+++ b/packages/SystemUI/res-product/values-fa/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"<xliff:g id="NUMBER">%d</xliff:g> تلاش ناموفق برای باز کردن قفل تلفن داشته‌اید. نمایه کاری پاک می‌شود که با آن همه داده‌های نمایه حذف می‌شود."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"‏الگوی بازگشایی قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیده‌اید. بعداز <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته می‌‎شود که بااستفاده از یک حساب ایمیل قفل رایانه لوحی‌تان را باز کنید.\n\n لطفاً پس‌از <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"الگوی بازگشایی قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیده‌اید. پس‌از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته می‌شود که بااستفاده از یک حساب ایمیل قفل تلفن را باز کنید.\n\n لطفاً پس‌از <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"حسگر اثر انگشت روی دکمه روشن/خاموش قرار دارد. این همان دکمه مسطحی است که در کنار دکمه برآمده صدا در لبه رایانه لوحی قرار دارد."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"حسگر اثر انگشت روی دکمه روشن/خاموش قرار دارد. این همان دکمه مسطحی است که در کنار دکمه برآمده صدا در لبه دستگاه قرار دارد."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"حسگر اثر انگشت روی دکمه روشن/خاموش قرار دارد. این همان دکمه مسطحی است که در کنار دکمه برآمده صدا در لبه تلفن قرار دارد."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"برای گزینه‌های بیشتر، قفل تلفن را باز کنید"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"برای گزینه‌های بیشتر، قفل رایانه لوحی را باز کنید"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"برای گزینه‌های بیشتر، قفل دستگاه را باز کنید"</string>
diff --git a/packages/SystemUI/res-product/values-fi/strings.xml b/packages/SystemUI/res-product/values-fi/strings.xml
index 55a65ea..19473d6 100644
--- a/packages/SystemUI/res-product/values-fi/strings.xml
+++ b/packages/SystemUI/res-product/values-fi/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER">%d</xliff:g> kertaa. Työprofiili ja kaikki sen data poistetaan."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%2$d</xliff:g> kertaa, sinua pyydetään avaamaan tabletin lukitus sähköpostitilin avulla.\n\n Yritä uudelleen <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunnin kuluttua."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%2$d</xliff:g> kertaa, sinua pyydetään avaamaan puhelimesi lukitus sähköpostitilin avulla.\n\n Yritä uudelleen <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunnin kuluttua."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Sormenjälkitunnistin on virtapainikkeessa. Se on litteä painike koholla olevan äänenvoimakkuuspainikkeen vieressä tabletin sivussa."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Sormenjälkitunnistin on virtapainikkeessa. Se on litteä painike koholla olevan äänenvoimakkuuspainikkeen vieressä laitteen sivussa."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Sormenjälkitunnistin on virtapainikkeessa. Se on litteä painike koholla olevan äänenvoimakkuuspainikkeen vieressä puhelimen sivussa."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Avaa puhelimen lukitus, niin näet enemmän vaihtoehtoja"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Avaa tabletin lukitus, niin näet enemmän vaihtoehtoja"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Avaa laitteen lukitus, niin näet enemmän vaihtoehtoja"</string>
diff --git a/packages/SystemUI/res-product/values-fr-rCA/strings.xml b/packages/SystemUI/res-product/values-fr-rCA/strings.xml
index 1ffa042..001eafc 100644
--- a/packages/SystemUI/res-product/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res-product/values-fr-rCA/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Vous avez tenté de déverrouiller ce téléphone à <xliff:g id="NUMBER">%d</xliff:g> reprises. Le profil professionnel sera supprimé, ce qui entraîne la suppression de toutes ses données."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre tablette à l\'aide d\'un compte de courriel.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre téléphone à l\'aide d\'un compte de courriel.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Le capteur d\'empreintes digitales est situé sur l\'interrupteur. Il s\'agit du bouton plat situé à côté du bouton de volume surélevé, sur le bord de la tablette."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Le capteur d\'empreintes digitales est situé sur l\'interrupteur. Il s\'agit du bouton plat situé à côté du bouton de volume surélevé, sur le bord de l\'appareil."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Le capteur d\'empreintes digitales est situé sur l\'interrupteur. Il s\'agit du bouton plat situé à côté du bouton de volume surélevé, sur le bord du téléphone."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Déverrouillez votre téléphone pour afficher davantage d\'options"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Déverrouillez votre tablette pour afficher davantage d\'options"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Déverrouillez votre appareil pour afficher davantage d\'options"</string>
diff --git a/packages/SystemUI/res-product/values-fr/strings.xml b/packages/SystemUI/res-product/values-fr/strings.xml
index 75a0862..2145b26 100644
--- a/packages/SystemUI/res-product/values-fr/strings.xml
+++ b/packages/SystemUI/res-product/values-fr/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Vous avez tenté de déverrouiller le téléphone à <xliff:g id="NUMBER">%d</xliff:g> reprises. Le profil professionnel et toutes les données associées vont être supprimés."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre tablette à l\'aide d\'un compte de messagerie électronique.\n\nRéessayez dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre téléphone à l\'aide d\'un compte de messagerie électronique.\n\nRéessayez dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Le lecteur d\'empreinte digitale est sur le bouton Marche/Arrêt. C\'est le bouton plat à côté du bouton de volume en relief sur un bord de la tablette."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Le lecteur d\'empreinte digitale est sur le bouton Marche/Arrêt. C\'est le bouton plat à côté du bouton de volume en relief sur un bord de l\'appareil."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Le lecteur d\'empreinte digitale est sur le bouton Marche/Arrêt. C\'est le bouton plat à côté du bouton de volume en relief sur un bord du téléphone."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Déverrouillez votre téléphone pour obtenir plus d\'options"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Déverrouillez votre tablette pour obtenir plus d\'options"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Déverrouillez votre appareil pour obtenir plus d\'options"</string>
diff --git a/packages/SystemUI/res-product/values-gl/strings.xml b/packages/SystemUI/res-product/values-gl/strings.xml
index 25fbb25..98653bc 100644
--- a/packages/SystemUI/res-product/values-gl/strings.xml
+++ b/packages/SystemUI/res-product/values-gl/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Tentaches desbloquear o teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de forma incorrecta. Quitarase o perfil de traballo e, por conseguinte, todos os seus datos."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Debuxaches o padrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, terás que desbloquear a tableta a través dunha conta de correo electrónico.\n\n Téntao de novo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Debuxaches o padrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, terás que desbloquear o teléfono a través dunha conta de correo electrónico.\n\n Téntao de novo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"O sensor de impresión dixital está no botón de acendido. É o botón plano que se atopa a carón do botón de volume con relevo, no lateral da tableta."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"O sensor de impresión dixital está no botón de acendido. É o botón plano que se atopa a carón do botón de volume con relevo, no lateral do dispositivo."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"O sensor de impresión dixital está no botón de acendido. É o botón plano que se atopa a carón do botón de volume con relevo, no lateral do teléfono."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Desbloquea o teléfono para ver máis opcións"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Desbloquea a tableta para ver máis opcións"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Desbloquea o dispositivo para ver máis opcións"</string>
diff --git a/packages/SystemUI/res-product/values-gu/strings.xml b/packages/SystemUI/res-product/values-gu/strings.xml
index b889dcc..aaed22e 100644
--- a/packages/SystemUI/res-product/values-gu/strings.xml
+++ b/packages/SystemUI/res-product/values-gu/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"તમે ફોનને <xliff:g id="NUMBER">%d</xliff:g> વખત ખોટી રીતે અનલૉક કરવાનો પ્રયાસ કર્યો છે. આ કાર્યાલયની પ્રોફાઇલ કાઢી નાખવામાં આવશે, જે તમામ પ્રોફાઇલ ડેટાને ડિલીટ કરી દેશે."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"તમે તમારી અનલૉક પૅટર્ન <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે દોરી છે. વધુ <xliff:g id="NUMBER_1">%2$d</xliff:g> અસફળ પ્રયાસો પછી, તમને એક ઇમેઇલ એકાઉન્ટનો ઉપયોગ કરીને તમારા ટૅબ્લેટને અનલૉક કરવાનું કહેવામાં આવશે.\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> સેકન્ડમાં ફરી પ્રયાસ કરો."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"તમે તમારી અનલૉક પૅટર્ન <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે દોરી છે. વધુ <xliff:g id="NUMBER_1">%2$d</xliff:g> અસફળ પ્રયાસો પછી, તમને ઇમેઇલ એકાઉન્ટનો ઉપયોગ કરીને તમારા ફોનને અનલૉક કરવાનું કહેવામાં આવશે.\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> સેકન્ડમાં ફરીથી પ્રયાસ કરો."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"ફિંગરપ્રિન્ટ સેન્સર પાવર બટન પર છે. તે ટૅબ્લેટની કિનારીએ આવેલા ઉપસેલા વૉલ્યૂમ બટનની બાજુમાં આવેલું સપાટ બટન છે."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"ફિંગરપ્રિન્ટ સેન્સર પાવર બટન પર છે. તે ડિવાઇસની કિનારીએ આવેલા ઉપસેલા વૉલ્યૂમ બટનની બાજુમાં આવેલું સપાટ બટન છે."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"ફિંગરપ્રિન્ટ સેન્સર પાવર બટન પર છે. તે ફોનની કિનારીએ આવેલા ઉપસેલા વૉલ્યૂમ બટનની બાજુમાં આવેલું સપાટ બટન છે."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"વધુ વિકલ્પો માટે તમારા ફોનને અનલૉક કરો"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"વધુ વિકલ્પો માટે તમારા ટૅબ્લેટને અનલૉક કરો"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"વધુ વિકલ્પો માટે તમારા ડિવાઇસને અનલૉક કરો"</string>
diff --git a/packages/SystemUI/res-product/values-hi/strings.xml b/packages/SystemUI/res-product/values-hi/strings.xml
index f148fc5..fbff516c 100644
--- a/packages/SystemUI/res-product/values-hi/strings.xml
+++ b/packages/SystemUI/res-product/values-hi/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"आप फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत पासवर्ड डाल चुके हैं. इसकी वजह से वर्क प्रोफ़ाइल को हटा दिया जाएगा जिससे उपयोगकर्ता की प्रोफ़ाइल का सारा डेटा मिट जाएगा."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"आपने लॉक खोलने के पैटर्न को <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से बनाया है. इसलिए, <xliff:g id="NUMBER_1">%2$d</xliff:g> और गलत पैटर्न बनाने के बाद, टैबलेट को अनलॉक करने के लिए आपसे ईमेल खाते का इस्तेमाल करने को कहा जाएगा.\n\n अनलॉक करने के लिए <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंड में फिर से कोशिश करें."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"आपने लॉक खोलने के पैटर्न को <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से बनाया है. इसलिए, <xliff:g id="NUMBER_1">%2$d</xliff:g> और गलत पैटर्न बनाने के बाद, आपसे फ़ोन को अनलॉक करने के लिए ईमेल खाते का इस्तेमाल करने को कहा जाएगा.\n\n अनलॉक करने के लिए <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंड में फिर से कोशिश करें."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"फ़िंगरप्रिंट सेंसर, पावर बटन पर होता है. यह टैबलेट के किनारे पर मौजूद एक फ़्लैट बटन होता है, जो कि आपको आवाज़ कम या ज़्यादा करने वाले उभरे हुए बटन के बगल में मिलेगा."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"फ़िंगरप्रिंट सेंसर, पावर बटन पर होता है. यह डिवाइस के किनारे पर मौजूद एक फ़्लैट बटन होता है, जो कि आपको आवाज़ कम या ज़्यादा करने वाले उभरे हुए बटन के बगल में मिलेगा."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"फ़िंगरप्रिंट सेंसर, पावर बटन पर होता है. यह फ़ोन के किनारे पर मौजूद एक फ़्लैट बटन होता है, जो कि आपको आवाज़ कम या ज़्यादा करने वाले उभरे हुए बटन के बगल में मिलेगा."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"ज़्यादा विकल्प देखने के लिए, अपना फ़ोन अनलॉक करें"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"ज़्यादा विकल्प देखने के लिए, अपना टैबलेट अनलॉक करें"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"ज़्यादा विकल्प देखने के लिए, अपना डिवाइस अनलॉक करें"</string>
diff --git a/packages/SystemUI/res-product/values-hr/strings.xml b/packages/SystemUI/res-product/values-hr/strings.xml
index 73ffd62..51a4edc 100644
--- a/packages/SystemUI/res-product/values-hr/strings.xml
+++ b/packages/SystemUI/res-product/values-hr/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Neuspješno ste pokušali otključati telefon <xliff:g id="NUMBER">%d</xliff:g> put/a. Radni će se profil ukloniti, a time će se izbrisati i svi njegovi podaci."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Netočno ste iscrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja morat ćete otključati tablet pomoću računa e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Netočno ste iscrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja morat ćete otključati telefon pomoću računa e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Senzor otiska prsta nalazi se na tipki za uključivanje/isključivanje. To je ravni gumb pored izdignutog gumba za glasnoću na rubu tableta."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Senzor otiska prsta nalazi se na tipki za uključivanje/isključivanje. To je ravni gumb pored izdignutog gumba za glasnoću na rubu uređaja."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Senzor otiska prsta nalazi se na tipki za uključivanje/isključivanje. To je ravni gumb pored izdignutog gumba za glasnoću na rubu telefona."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Za više opcija otključajte telefon"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Za više opcija otključajte tablet"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Za više opcija otključajte uređaj"</string>
diff --git a/packages/SystemUI/res-product/values-hu/strings.xml b/packages/SystemUI/res-product/values-hu/strings.xml
index 19d79d3..2907cf5 100644
--- a/packages/SystemUI/res-product/values-hu/strings.xml
+++ b/packages/SystemUI/res-product/values-hu/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"<xliff:g id="NUMBER">%d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. A rendszer eltávolítja a munkaprofilt, és ezzel a profil összes adata törlődik."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%2$d</xliff:g> sikertelen kísérlet után e-mail-fiók használatával kell feloldania táblagépét.\n\nPróbálja újra <xliff:g id="NUMBER_2">%3$d</xliff:g> másodperc múlva."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%2$d</xliff:g> sikertelen kísérlet után e-mail-fiók használatával kell feloldania telefonját.\n\nPróbálja újra <xliff:g id="NUMBER_2">%3$d</xliff:g> másodperc múlva."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Az ujjlenyomat-érzékelő a bekapcsológombon található. Ez a kiemelkedő hangerőgomb melletti lapos gomb a táblagép szélén."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Az ujjlenyomat-érzékelő a bekapcsológombon található. Ez a kiemelkedő hangerőgomb melletti lapos gomb az eszköz szélén."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Az ujjlenyomat-érzékelő a bekapcsológombon található. Ez a kiemelkedő hangerőgomb melletti lapos gomb a telefon szélén."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"További lehetőségekért oldja fel a telefont"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"További lehetőségekért oldja fel a táblagépet"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"További lehetőségekért oldja fel az eszközt"</string>
diff --git a/packages/SystemUI/res-product/values-hy/strings.xml b/packages/SystemUI/res-product/values-hy/strings.xml
index 17f42a0..aade4a0 100644
--- a/packages/SystemUI/res-product/values-hy/strings.xml
+++ b/packages/SystemUI/res-product/values-hy/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Դուք կատարել եք հեռախոսն ապակողպելու <xliff:g id="NUMBER">%d</xliff:g> անհաջող փորձ: Աշխատանքային պրոֆիլը կհեռացվի, և պրոֆիլի բոլոր տվյալները կջնջվեն:"</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Դուք կատարել եք ապակողպման նախշը մուտքագրելու <xliff:g id="NUMBER_0">%1$d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%2$d</xliff:g> անհաջող փորձից հետո ձեզանից կպահանջվի ապակողպել պլանշետը էլփոստի հաշվի միջոցով։\n\n Խնդրում ենք կրկին փորձել <xliff:g id="NUMBER_2">%3$d</xliff:g> վայրկյանից:"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Դուք <xliff:g id="NUMBER_0">%1$d</xliff:g> անգամ սխալ եք հավաքել ձեր ապակողպման նմուշը: Եվս <xliff:g id="NUMBER_1">%2$d</xliff:g> անհաջող փորձից հետո ձեզ կառաջարկվի ապակողպել հեռախոսը` օգտագործելով էլփոստի հաշիվ:\n\n Կրկին փորձեք <xliff:g id="NUMBER_2">%3$d</xliff:g> վայրկյանից:"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Մատնահետքերի սկաները սնուցման կոճակի վրա է։ Այն հարթ կոճակ է ձայնի ուժգնության ուռուցիկ կոճակի կողքին՝ պլանշետի եզրային մասում։"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Մատնահետքերի սկաները սնուցման կոճակի վրա է։ Այն հարթ կոճակ է ձայնի ուժգնության ուռուցիկ կոճակի կողքին՝ սարքի եզրային մասում։"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Մատնահետքերի սկաները սնուցման կոճակի վրա է։ Այն հարթ կոճակ է ձայնի ուժգնության ուռուցիկ կոճակի կողքին՝ հեռախոսի եզրային մասում։"</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Ապակողպեք ձեր հեռախոսը՝ լրացուցիչ կարգավորումները տեսնելու համար"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Ապակողպեք ձեր պլանշետը՝ լրացուցիչ կարգավորումները տեսնելու համար"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Ապակողպեք ձեր սարքը՝ լրացուցիչ կարգավորումները տեսնելու համար"</string>
diff --git a/packages/SystemUI/res-product/values-in/strings.xml b/packages/SystemUI/res-product/values-in/strings.xml
index 15d8f39..0c7c2dd 100644
--- a/packages/SystemUI/res-product/values-in/strings.xml
+++ b/packages/SystemUI/res-product/values-in/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Anda telah <xliff:g id="NUMBER">%d</xliff:g> kali berupaya membuka kunci ponsel dengan tidak benar. Profil kerja akan dihapus, sehingga semua data profil akan dihapus."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya yang tidak berhasil, Anda akan diminta membuka kunci tablet menggunakan akun email.\n\n Coba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> detik."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya yang tidak berhasil, Anda akan diminta membuka kunci ponsel menggunakan akun email.\n\n Coba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> detik."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Sensor sidik jari ada di tombol daya. Tombol ini berupa tombol datar di samping tombol volume timbul di tepi tablet."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Sensor sidik jari ada di tombol daya. Tombol ini berupa tombol datar di samping tombol volume timbul di tepi perangkat."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Sensor sidik jari ada di tombol daya. Tombol ini berupa tombol datar di samping tombol volume timbul di tepi ponsel."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Buka kunci ponsel untuk melihat opsi lainnya"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Buka kunci tablet untuk melihat opsi lainnya"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Buka kunci perangkat untuk melihat opsi lainnya"</string>
diff --git a/packages/SystemUI/res-product/values-is/strings.xml b/packages/SystemUI/res-product/values-is/strings.xml
index b24871c..9120475 100644
--- a/packages/SystemUI/res-product/values-is/strings.xml
+++ b/packages/SystemUI/res-product/values-is/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Þú hefur gert <xliff:g id="NUMBER">%d</xliff:g> árangurslausar tilraunir til að opna símann. Vinnusniðið verður fjarlægt, með þeim afleiðingum að öllum gögnum þess verður eytt."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Þú hefur teiknað rangt opnunarmynstur <xliff:g id="NUMBER_0">%1$d</xliff:g> sinnum. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verðurðu beðin(n) um að opna spjaldtölvuna með tölvupóstreikningi.\n\n Reyndu aftur eftir <xliff:g id="NUMBER_2">%3$d</xliff:g> sekúndur."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Þú hefur teiknað rangt opnunarmynstur <xliff:g id="NUMBER_0">%1$d</xliff:g> sinnum. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verðurðu beðin(n) um að opna símann með tölvupóstreikningi.\n\n Reyndu aftur eftir <xliff:g id="NUMBER_2">%3$d</xliff:g> sekúndur."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Fingrafaralesarinn er á aflrofanum. Það er flati hnappurinn við hliðina á upphleypta hljóðstyrkshnappnum á hlið spjaldtölvunnar."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Fingrafaralesarinn er á aflrofanum. Það er flati hnappurinn við hliðina á upphleypta hljóðstyrkshnappnum á hlið tækisins."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Fingrafaralesarinn er á aflrofanum. Það er flati hnappurinn við hliðina á upphleypta hljóðstyrkshnappnum á hlið símans."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Taktu símann úr lás til að fá fleiri valkosti"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Taktu spjaldtölvuna úr lás til að fá fleiri valkosti"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Taktu tækið úr lás til að fá fleiri valkosti"</string>
diff --git a/packages/SystemUI/res-product/values-it/strings.xml b/packages/SystemUI/res-product/values-it/strings.xml
index 8e9875d..2496925 100644
--- a/packages/SystemUI/res-product/values-it/strings.xml
+++ b/packages/SystemUI/res-product/values-it/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Hai tentato di sbloccare il telefono senza riuscirci per <xliff:g id="NUMBER">%d</xliff:g> volte. Il profilo di lavoro verrà rimosso e verranno quindi eliminati tutti i dati associati."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"<xliff:g id="NUMBER_0">%1$d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il tablet con un account email.\n\n Riprova tra <xliff:g id="NUMBER_2">%3$d</xliff:g> secondi."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"<xliff:g id="NUMBER_0">%1$d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il telefono con un account email.\n\n Riprova tra <xliff:g id="NUMBER_2">%3$d</xliff:g> secondi."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Il sensore di impronte digitali si trova sul tasto di accensione. Si tratta del tasto piatto accanto al tasto del volume in rilievo sulla parte laterale del tablet."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Il sensore di impronte digitali si trova sul tasto di accensione. Si tratta del tasto piatto accanto al tasto del volume in rilievo sulla parte laterale del dispositivo."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Il sensore di impronte digitali si trova sul tasto di accensione. Si tratta del tasto piatto accanto al tasto del volume in rilievo sulla parte laterale del telefono."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Sblocca il telefono per visualizzare altre opzioni"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Sblocca il tablet per visualizzare altre opzioni"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Sblocca il dispositivo per visualizzare altre opzioni"</string>
diff --git a/packages/SystemUI/res-product/values-iw/strings.xml b/packages/SystemUI/res-product/values-iw/strings.xml
index b3aa028..ee131cb 100644
--- a/packages/SystemUI/res-product/values-iw/strings.xml
+++ b/packages/SystemUI/res-product/values-iw/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"ניסית לבטל את נעילת הטלפון <xliff:g id="NUMBER">%d</xliff:g> פעמים. פרופיל העבודה יוסר וכל נתוני הפרופיל יימחקו."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"שרטטת קו ביטול נעילה שגוי <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%2$d</xliff:g> ניסיונות כושלים נוספים, ,תישלח אליך בקשה לבטל את נעילת הטאבלט באמצעות חשבון אימייל‏.\n\n יש לנסות שוב בעוד <xliff:g id="NUMBER_2">%3$d</xliff:g> שניות."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"שרטטת קו ביטול נעילה שגוי <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%2$d</xliff:g> ניסיונות כושלים נוספים, תישלח אליך בקשה לבטל את נעילת הטלפון באמצעות חשבון אימייל‏.\n\n יש לנסות שוב בעוד <xliff:g id="NUMBER_2">%3$d</xliff:g> שניות."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"חיישן טביעות האצבע נמצא על לחצן ההפעלה. זה הלחצן השטוח ליד הלחצן הבולט של עוצמת הקול בשולי הטאבלט."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"חיישן טביעות האצבע נמצא על לחצן ההפעלה. זה הלחצן השטוח ליד הלחצן הבולט של עוצמת הקול בשולי המכשיר."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"חיישן טביעות האצבע נמצא על לחצן ההפעלה. זה הלחצן השטוח ליד הלחצן הבולט של עוצמת הקול בשולי הטלפון."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"לאפשרויות נוספות, יש לבטל את נעילת הטלפון"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"לאפשרויות נוספות, יש לבטל את נעילת הטאבלט"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"לאפשרויות נוספות, יש לבטל את נעילת המכשיר"</string>
diff --git a/packages/SystemUI/res-product/values-ja/strings.xml b/packages/SystemUI/res-product/values-ja/strings.xml
index c51a04c..2c8340f 100644
--- a/packages/SystemUI/res-product/values-ja/strings.xml
+++ b/packages/SystemUI/res-product/values-ja/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"スマートフォンのロック解除に <xliff:g id="NUMBER">%d</xliff:g> 回失敗しました。仕事用プロファイルは削除され、プロファイルのデータはすべて消去されます。"</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"ロック解除パターンの入力を <xliff:g id="NUMBER_0">%1$d</xliff:g> 回間違えました。あと <xliff:g id="NUMBER_1">%2$d</xliff:g> 回間違えると、タブレットのロック解除にメール アカウントが必要になります。\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後にもう一度お試しください。"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"ロック解除パターンの入力を <xliff:g id="NUMBER_0">%1$d</xliff:g> 回間違えました。あと <xliff:g id="NUMBER_1">%2$d</xliff:g> 回間違えると、スマートフォンのロック解除にメール アカウントが必要になります。\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後にもう一度お試しください。"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"指紋認証センサーは電源ボタンに内蔵されています。タブレット側面のボタンのうち、音量ボタンの横にあるフラットなボタンです。"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"指紋認証センサーは電源ボタンに内蔵されています。デバイス側面のボタンのうち、音量ボタンの横にあるフラットなボタンです。"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"指紋認証センサーは電源ボタンに内蔵されています。スマートフォン側面のボタンのうち、音量ボタンの横にあるフラットなボタンです。"</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"スマートフォンのロックを解除してその他のオプションを表示する"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"タブレットのロックを解除してその他のオプションを表示する"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"デバイスのロックを解除してその他のオプションを表示する"</string>
diff --git a/packages/SystemUI/res-product/values-ka/strings.xml b/packages/SystemUI/res-product/values-ka/strings.xml
index 3474a7f..bae2241 100644
--- a/packages/SystemUI/res-product/values-ka/strings.xml
+++ b/packages/SystemUI/res-product/values-ka/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"თქვენ არასწორად ცადეთ ტელეფონის განბლოკვა <xliff:g id="NUMBER">%d</xliff:g>-ჯერ. ამის გამო, სამსახურის პროფილი ამოიშლება, რაც პროფილის ყველა მონაცემის წაშლას გამოიწვევს."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"თქვენ არასწორად დახატეთ თქვენი განბლოკვის ნიმუში <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%2$d</xliff:g> წარუმატებელი მცდელობის შემდეგ მოგთხოვთ, ტაბლეტი თქვენი ელფოსტის ანგარიშის მეშვეობით განბლოკოთ.\n\n ცადეთ ხელახლა <xliff:g id="NUMBER_2">%3$d</xliff:g> წამში."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"თქვენ არასწორად დახატეთ თქვენი განბლოკვის ნიმუში <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%2$d</xliff:g> წარუმატებელი მცდელობის შემდეგ მოგთხოვთ, ტელეფონი თქვენი ელფოსტის ანგარიშის მეშვეობით განბლოკოთ.\n\n ცადეთ ხელახლა <xliff:g id="NUMBER_2">%3$d</xliff:g> წამში."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"თითის ანაბეჭდის სენსორი ჩართვის ღილაკზეა. ეს არის ბრტყელი ღილაკი ხმის აწევის ღილაკის გვერდით, ტაბლეტის კიდეში."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"თითის ანაბეჭდის სენსორი ჩართვის ღილაკზეა. ეს არის ბრტყელი ღილაკი ხმის აწევის ღილაკის გვერდით, მოწყობილობის კიდეში."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"თითის ანაბეჭდის სენსორი ჩართვის ღილაკზეა. ეს არის ბრტყელი ღილაკი ხმის აწევის ღილაკის გვერდით, ტელეფონის კიდეში."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"მეტი ვარიანტის სანახავად განბლოკეთ თქვენი ტელეფონი"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"მეტი ვარიანტის სანახავად განბლოკეთ თქვენი ტაბლეტი"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"მეტი ვარიანტის სანახავად განბლოკეთ თქვენი მოწყობილობა"</string>
diff --git a/packages/SystemUI/res-product/values-kk/strings.xml b/packages/SystemUI/res-product/values-kk/strings.xml
index 8cfda7e..83d55a7 100644
--- a/packages/SystemUI/res-product/values-kk/strings.xml
+++ b/packages/SystemUI/res-product/values-kk/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Телефон құлпын ашуға <xliff:g id="NUMBER">%d</xliff:g> рет сәтсіз әрекет жасалды. Жұмыс профилі өшіріліп, оның бүкіл деректері жойылады."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Құлыпты ашу өрнегі <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате енгізілді. <xliff:g id="NUMBER_1">%2$d</xliff:g> әрекет қалды. Одан кейін планшетті аккаунт арқылы ашу сұралады. \n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундтан кейін әрекетті қайталаңыз."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Құлыпты ашу өрнегі <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате енгізілді. <xliff:g id="NUMBER_1">%2$d</xliff:g> әрекет қалды. Одан кейін телефонды аккаунт арқылы ашу сұралады. \n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундтан кейін әрекетті қайталаңыз."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Саусақ ізін оқу сканері қуат түймесінде орналасқан. Ол – планшет шетіндегі шығыңқы дыбыс деңгейі түймесінің жанында орналасқан жалпақ түйме."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Саусақ ізін оқу сканері қуат түймесінде орналасқан. Ол – құрылғы шетіндегі шығыңқы дыбыс деңгейі түймесінің жанында орналасқан жалпақ түйме."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Саусақ ізін оқу сканері қуат түймесінде орналасқан. Ол – телефон шетіндегі шығыңқы дыбыс деңгейі түймесінің жанында орналасқан жалпақ түйме."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Басқа опцияларды көру үшін телефон құлпын ашыңыз."</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Басқа опцияларды көру үшін планшет құлпын ашыңыз."</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Басқа опцияларды көру үшін құрылғы құлпын ашыңыз."</string>
diff --git a/packages/SystemUI/res-product/values-km/strings.xml b/packages/SystemUI/res-product/values-km/strings.xml
index 035432d..52a2220 100644
--- a/packages/SystemUI/res-product/values-km/strings.xml
+++ b/packages/SystemUI/res-product/values-km/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"អ្នក​បាន​ព្យាយាម​ដោះសោ​ទូរសព្ទ​នេះ​មិន​ត្រឹមត្រូវ​ចំនួន <xliff:g id="NUMBER">%d</xliff:g> ដង​ហើយ។ កម្រង​ព័ត៌មាន​ការងារ​នេះ​នឹង​ត្រូវ​បាន​លុប ហើយ​វា​នឹង​លុប​ទិន្នន័យ​កម្រង​ព័ត៌មាន​ទាំងអស់។"</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"អ្នក​បាន​គូរ​លំនាំ​ដោះ​សោ​របស់​អ្នក​មិន​ត្រឹមត្រូវ​ចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដង​ហើយ។ បន្ទាប់ពីមានការ​ព្យាយាម​ដោះ​សោ​ចំនួន <xliff:g id="NUMBER_1">%2$d</xliff:g> ដងទៀត​មិន​ទទួល​បាន​ជោគជ័យ អ្នក​នឹង​ត្រូវ​បាន​ស្នើ​ឱ្យ​ដោះ​សោ​ថេប្លេត​របស់​អ្នក​ ដោយ​ប្រើ​គណនី​អ៊ីមែល។\n\n សូមព្យាយាម​ម្ដង​ទៀត​ក្នុង​រយៈ​ពេល <xliff:g id="NUMBER_2">%3$d</xliff:g> វិនាទី​ទៀត។"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"អ្នកបានគូរលំនាំ​ដោះសោ​របស់អ្នក​មិន​ត្រឹមត្រូវចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដងហើយ។ បន្ទាប់ពីមាន​ការព្យាយាម​ដោះសោចំនួន <xliff:g id="NUMBER_1">%2$d</xliff:g> ដងទៀតមិនទទួលបាន​ជោគជ័យ អ្នកនឹង​ត្រូវបាន​ស្នើឱ្យ​ដោះសោ​ទូរសព្ទ​របស់​អ្នកដោយ​ប្រើគណនី​អ៊ីមែល។\n\n សូមព្យាយាម​ម្ដងទៀតក្នុង​រយៈពេល <xliff:g id="NUMBER_2">%3$d</xliff:g> វិនាទីទៀត។"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"សេនស័រចាប់ស្នាមម្រាមដៃ​ស្ថិតនៅលើប៊ូតុង​ថាមពល។ វាជាប៊ូតុងរាបស្មើនៅជាប់នឹងប៊ូតុងកម្រិតសំឡេងដែលលៀនចេញមកនៅលើគែមថេប្លេត។"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"សេនស័រចាប់ស្នាមម្រាមដៃ​ស្ថិតនៅលើប៊ូតុង​ថាមពល។ វាជាប៊ូតុងរាបស្មើនៅជាប់នឹងប៊ូតុងកម្រិតសំឡេងដែលលៀនចេញមកនៅលើគែមឧបករណ៍។"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"សេនស័រចាប់ស្នាមម្រាមដៃ​ស្ថិតនៅលើប៊ូតុង​ថាមពល។ វាជាប៊ូតុងរាបស្មើនៅជាប់នឹងប៊ូតុងកម្រិតសំឡេងដែលលៀនចេញមកនៅលើគែមទូរសព្ទ។"</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"ដោះសោ​ទូរសព្ទរបស់អ្នក​សម្រាប់​ជម្រើសច្រើនទៀត"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"ដោះសោ​ថេប្លេតរបស់អ្នក​សម្រាប់​ជម្រើសច្រើនទៀត"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"ដោះសោ​ឧបករណ៍របស់អ្នក​សម្រាប់​ជម្រើសច្រើនទៀត"</string>
diff --git a/packages/SystemUI/res-product/values-kn/strings.xml b/packages/SystemUI/res-product/values-kn/strings.xml
index d795cef..1bdc159 100644
--- a/packages/SystemUI/res-product/values-kn/strings.xml
+++ b/packages/SystemUI/res-product/values-kn/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"ಫೋನ್ ಅನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್ ಅನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ, ಇದು ಪ್ರೊಫೈಲ್‌ನ ಎಲ್ಲಾ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"ನಿಮ್ಮ ಅನ್‍‍ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಡ್ರಾ ಮಾಡಿರುವಿರಿ. <xliff:g id="NUMBER_1">%2$d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ಬಳಿಕ, ನಿಮ್ಮ ಇಮೇಲ್ ಖಾತೆಯನ್ನು ಬಳಸಿ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್‌ಲಾಕ್ ಮಾಡಲು ನಿಮ್ಮನ್ನು ಕೇಳಲಾಗುತ್ತದೆ.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ಸೆಕೆಂಡ್‌ಗಳಲ್ಲಿ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"ನಿಮ್ಮ ಅನ್‍‍ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಡ್ರಾ ಮಾಡಿರುವಿರಿ. <xliff:g id="NUMBER_1">%2$d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ಬಳಿಕ, ಇಮೇಲ್ ಖಾತೆಯನ್ನು ಬಳಸಿ ನಿಮ್ಮ ಫೋನ್ ಅನ್‌ಲಾಕ್ ಮಾಡಲು ನಿಮ್ಮನ್ನು ಕೇಳಲಾಗುತ್ತದೆ.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ಸೆಕೆಂಡ್‌ಗಳಲ್ಲಿ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್ ಪವರ್ ಬಟನ್‌ನಲ್ಲಿದೆ. ಇದು ಟ್ಯಾಬ್ಲೆಟ್‌ನ ಅಂಚಿನಲ್ಲಿರುವ ಎತ್ತರಿಸಿದ ವಾಲ್ಯೂಮ್ ಬಟನ್‌ನ ಪಕ್ಕದಲ್ಲಿರುವ ಫ್ಲಾಟ್ ಬಟನ್ ಆಗಿದೆ."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್ ಪವರ್ ಬಟನ್‌ನಲ್ಲಿದೆ. ಇದು ಸಾಧನದ ಅಂಚಿನಲ್ಲಿರುವ ಎತ್ತರಿಸಿದ ವಾಲ್ಯೂಮ್ ಬಟನ್‌ನ ಪಕ್ಕದಲ್ಲಿರುವ ಫ್ಲಾಟ್ ಬಟನ್ ಆಗಿದೆ."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್ ಪವರ್ ಬಟನ್‌ನಲ್ಲಿದೆ. ಇದು ಫೋನ್‌ನ ಅಂಚಿನಲ್ಲಿರುವ ಎತ್ತರಿಸಿದ ವಾಲ್ಯೂಮ್ ಬಟನ್‌ನ ಪಕ್ಕದಲ್ಲಿರುವ ಫ್ಲಾಟ್ ಬಟನ್ ಆಗಿದೆ."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"ಹೆಚ್ಚಿನ ಆಯ್ಕೆಗಳಿಗಾಗಿ ನಿಮ್ಮ ಫೋನ್ ಅನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಿ"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"ಹೆಚ್ಚಿನ ಆಯ್ಕೆಗಳಿಗಾಗಿ ನಿಮ್ಮ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಿ"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"ಹೆಚ್ಚಿನ ಆಯ್ಕೆಗಳಿಗಾಗಿ ನಿಮ್ಮ ಸಾಧನವನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಿ"</string>
diff --git a/packages/SystemUI/res-product/values-ko/strings.xml b/packages/SystemUI/res-product/values-ko/strings.xml
index 651662f..bcf13dc 100644
--- a/packages/SystemUI/res-product/values-ko/strings.xml
+++ b/packages/SystemUI/res-product/values-ko/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"휴대전화 잠금 해제에 <xliff:g id="NUMBER">%d</xliff:g>번 실패했습니다. 직장 프로필과 모든 프로필 데이터가 삭제됩니다."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"잠금 해제 패턴을 <xliff:g id="NUMBER_0">%1$d</xliff:g>회 잘못 그렸습니다. <xliff:g id="NUMBER_1">%2$d</xliff:g>회 더 실패하면 이메일 계정을 사용하여 태블릿을 잠금 해제해야 합니다.\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g>초 후에 다시 시도해 주세요."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"잠금 해제 패턴을 <xliff:g id="NUMBER_0">%1$d</xliff:g>회 잘못 그렸습니다. <xliff:g id="NUMBER_1">%2$d</xliff:g>회 더 실패하면 이메일 계정을 사용하여 휴대전화를 잠금 해제해야 합니다.\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g>초 후에 다시 시도해 주세요."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"지문 센서는 전원 버튼에 있습니다. 태블릿 옆면에 있는 튀어나온 볼륨 버튼 옆의 평평한 버튼입니다."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"지문 센서는 전원 버튼에 있습니다. 기기 옆면에 있는 튀어나온 볼륨 버튼 옆의 평평한 버튼입니다."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"지문 센서는 전원 버튼에 있습니다. 휴대전화 옆면에 있는 튀어나온 볼륨 버튼 옆의 평평한 버튼입니다."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"더 많은 옵션을 확인하려면 휴대전화를 잠금 해제하세요."</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"더 많은 옵션을 확인하려면 태블릿을 잠금 해제하세요."</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"더 많은 옵션을 확인하려면 기기를 잠금 해제하세요."</string>
diff --git a/packages/SystemUI/res-product/values-ky/strings.xml b/packages/SystemUI/res-product/values-ky/strings.xml
index 7c54729..9286f2e 100644
--- a/packages/SystemUI/res-product/values-ky/strings.xml
+++ b/packages/SystemUI/res-product/values-ky/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Телефондун кулпусун <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Жумуш профили өчүрүлүп, андагы бардык нерселер өчүрүлөт."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Графикалык ачкычты <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> ийгиликсиз аракеттен кийин планшетиңизди бөгөттөн электрондук почтаңыз аркылуу чыгаруу талап кылынат.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секунддан кийин кайра аракеттениңиз."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Графикалык ачкычты <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> ийгиликсиз аракеттен кийин телефонуңузду бөгөттөн электрондук почтаңыз аркылуу чыгаруу талап кылынат.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секунддан кийин кайра аракеттениңиз."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Манжа изинин сенсору кубат баскычында жайгашкан. Бул планшеттин четиндеги үндү катуулатуу/акырындатуу баскычынын (көтөрүлгөн) жанындагы жалпак баскыч."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Манжа изинин сенсору кубат баскычында жайгашкан. Бул түзмөктүн четиндеги үндү катуулатуу/акырындатуу баскычынын (көтөрүлгөн) жанындагы жалпак баскыч."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Манжа изинин сенсору кубат баскычында жайгашкан. Бул телефондун четиндеги үндү катуулатуу/акырындатуу баскычынын (көтөрүлгөн) жанындагы жалпак баскыч."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Дагы башка параметрлерди көрүү үчүн телефонуңуздун кулпусун ачыңыз"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Дагы башка параметрлерди көрүү үчүн планшетиңиздин кулпусун ачыңыз"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Дагы башка параметрлерди көрүү үчүн түзмөгүңүздүн кулпусун ачыңыз"</string>
diff --git a/packages/SystemUI/res-product/values-lo/strings.xml b/packages/SystemUI/res-product/values-lo/strings.xml
index b6479d6..542383e 100644
--- a/packages/SystemUI/res-product/values-lo/strings.xml
+++ b/packages/SystemUI/res-product/values-lo/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"ທ່ານພະຍາຍາມປົດລັອກໂທລະສັບຜິດ <xliff:g id="NUMBER">%d</xliff:g> ເທື່ອແລ້ວ. ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຈະຖືກລຶບອອກ, ເຊິ່ງຈະລຶບຂໍ້ມູນໂປຣໄຟລ໌ທັງໝົດອອກນຳ."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"ທ່ານແຕ້ມຮູບແບບປົດລັອກຜິດ <xliff:g id="NUMBER_0">%1$d</xliff:g> ເທື່ອແລ້ວ. ຫຼັງຈາກແຕ້ມຜິດອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ເທື່ອ, ທ່ານຈະຖືກຖາມໃຫ້ປົດລັອກແທັບເລັດຂອງທ່ານດ້ວຍການເຂົ້າສູ່ລະບົບໂດຍໃຊ້ອີເມວຂອງທ່ານ.\n\n ກະລຸນາລອງໃໝ່ໃນອີກ <xliff:g id="NUMBER_2">%3$d</xliff:g> ວິນາທີ."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"ທ່ານແຕ້ມຮູບແບບປົດລັອກຜິດ <xliff:g id="NUMBER_0">%1$d</xliff:g> ເທື່ອແລ້ວ. ຫຼັງຈາກແຕ້ມຜິດອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ເທື່ອ, ທ່ານຈະຖືກຖາມໃຫ້ປົດໂທລະສັບຂອງທ່ານດ້ວຍການເຂົ້າສູ່ລະບົບໂດຍໃຊ້ບັນຊີອີເມວ.\n\n ກະລຸນາລອງໃໝ່ໃນອີກ <xliff:g id="NUMBER_2">%3$d</xliff:g> ວິນາທີ."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"ເຊັນເຊີລາຍນິ້ວມືແມ່ນຢູ່ປຸ່ມເປີດປິດ. ມັນເປັນປຸ່ມແປໆທີ່ຢູ່ຖັດຈາກປຸ່ມລະດັບສຽງຢູ່ຂອບຂອງແທັບເລັດ."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"ເຊັນເຊີລາຍນິ້ວມືແມ່ນຢູ່ປຸ່ມເປີດປິດ. ມັນເປັນປຸ່ມແປໆທີ່ຢູ່ຖັດຈາກປຸ່ມລະດັບສຽງຢູ່ຂອບຂອງອຸປະກອນ."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"ເຊັນເຊີລາຍນິ້ວມືແມ່ນຢູ່ປຸ່ມເປີດປິດ. ມັນເປັນປຸ່ມແປໆທີ່ຢູ່ຖັດຈາກປຸ່ມລະດັບສຽງຢູ່ຂອບຂອງໂທລະສັບ."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"ປົດລັອກໂທລະສັບຂອງທ່ານເພື່ອໃຊ້ຕົວເລືອກເພີ່ມເຕີມ"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"ປົດລັອກແທັບເລັດຂອງທ່ານເພື່ອໃຊ້ຕົວເລືອກເພີ່ມເຕີມ"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"ປົດລັອກອຸປະກອນຂອງທ່ານເພື່ອໃຊ້ຕົວເລືອກເພີ່ມເຕີມ"</string>
diff --git a/packages/SystemUI/res-product/values-lt/strings.xml b/packages/SystemUI/res-product/values-lt/strings.xml
index 560e36e..ef7550a 100644
--- a/packages/SystemUI/res-product/values-lt/strings.xml
+++ b/packages/SystemUI/res-product/values-lt/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"<xliff:g id="NUMBER">%d</xliff:g> kart. nesėkmingai bandėte atrakinti telefoną. Darbo profilis bus pašalintas ir visi profilio duomenys bus ištrinti."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. netinkamai nupiešėte atrakinimo piešinį. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. būsite paprašyti atrakinti planšetinį kompiuterį naudodami el. pašto paskyrą.\n\n Bandykite dar kartą po <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. netinkamai nupiešėte atrakinimo piešinį. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. būsite paprašyti atrakinti telefoną naudodami el. pašto paskyrą.\n\n Bandykite dar kartą po <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Piršto atspaudo jutiklis yra ant maitinimo mygtuko. Tai yra plokščias mygtukas šalia iškilusio garsumo mygtuko ant planšetinio kompiuterio krašto."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Piršto atspaudo jutiklis yra ant maitinimo mygtuko. Tai yra plokščias mygtukas šalia iškilusio garsumo mygtuko ant įrenginio krašto."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Piršto atspaudo jutiklis yra ant maitinimo mygtuko. Tai yra plokščias mygtukas šalia iškilusio garsumo mygtuko ant telefono krašto."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Atrakinkite telefoną, kad galėtumėte naudoti daugiau parinkčių"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Atrakinkite planšetinį kompiuterį, kad galėtumėte naudoti daugiau parinkčių"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Atrakinkite įrenginį, kad galėtumėte naudoti daugiau parinkčių"</string>
diff --git a/packages/SystemUI/res-product/values-lv/strings.xml b/packages/SystemUI/res-product/values-lv/strings.xml
index 3c64f62..b924cd5 100644
--- a/packages/SystemUI/res-product/values-lv/strings.xml
+++ b/packages/SystemUI/res-product/values-lv/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Jūs <xliff:g id="NUMBER">%d</xliff:g> reizi(-es) nesekmīgi mēģinājāt atbloķēt tālruni. Darba profils tiks noņemts, kā arī visi profila dati tiks dzēsti."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) nepareizi norādījāt atbloķēšanas kombināciju. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> neveiksmīga(-iem) mēģinājuma(-iem) planšetdators būs jāatbloķē, izmantojot e-pasta kontu.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundes(-ēm)."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) nepareizi norādījāt atbloķēšanas kombināciju. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīga(-iem) mēģinājuma(-iem) tālrunis būs jāatbloķē, izmantojot e-pasta kontu.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundes(-ēm)."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Pirksta nospieduma sensors atrodas uz barošanas pogas. Tā ir plakanā poga, kas atrodas blakus augstākai skaļuma pogai planšetdatora sānos."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Pirksta nospieduma sensors atrodas uz barošanas pogas. Tā ir plakanā poga, kas atrodas blakus augstākai skaļuma pogai ierīces sānos."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Pirksta nospieduma sensors atrodas uz barošanas pogas. Tā ir plakanā poga, kas atrodas blakus augstākai skaļuma pogai tālruņa sānos."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Atbloķējiet tālruni, lai skatītu citas opcijas."</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Atbloķējiet planšetdatoru, lai skatītu citas opcijas."</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Atbloķējiet ierīci, lai skatītu citas opcijas."</string>
diff --git a/packages/SystemUI/res-product/values-mk/strings.xml b/packages/SystemUI/res-product/values-mk/strings.xml
index d5895bf..d528600 100644
--- a/packages/SystemUI/res-product/values-mk/strings.xml
+++ b/packages/SystemUI/res-product/values-mk/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Погрешно се обидовте да го отклучите телефонот <xliff:g id="NUMBER">%d</xliff:g> пати. Работниот профил ќе се отстрани, со што ќе се избришат сите податоци на профилот."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Погрешно ја употребивте вашата шема на отклучување <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. По уште <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни обиди, ќе побараме да го отклучите таблетот со сметка на е-пошта.\n\n Обидете се повторно за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Погрешно ја употребивте вашата шема на отклучување <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. По уште <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни обиди, ќе побараме да го отклучите телефонот со сметка на е-пошта.\n\n Обидете се повторно за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Сензорот за отпечатоци се наоѓа на копчето за вклучување. Тоа е рамното копче веднаш до подигнатото копче за јачина на звук на работ од таблетот."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Сензорот за отпечатоци се наоѓа на копчето за вклучување. Тоа е рамното копче веднаш до подигнатото копче за јачина на звук на работ од уредот."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Сензорот за отпечатоци се наоѓа на копчето за вклучување. Тоа е рамното копче веднаш до подигнатото копче за јачина на звук на работ од телефонот."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Отклучето го вашиот телефон за повеќе опции"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Отклучето го вашиот таблет за повеќе опции"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Отклучето го вашиот уред за повеќе опции"</string>
diff --git a/packages/SystemUI/res-product/values-ml/strings.xml b/packages/SystemUI/res-product/values-ml/strings.xml
index 59f3eb5..dceb8e4 100644
--- a/packages/SystemUI/res-product/values-ml/strings.xml
+++ b/packages/SystemUI/res-product/values-ml/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"നിങ്ങൾ <xliff:g id="NUMBER">%d</xliff:g> തവണ തെറ്റായ രീതിയിൽ ഫോൺ അൺലോക്ക് ചെയ്യാൻ ശ്രമിച്ചു. ഔദ്യോഗിക പ്രൊഫൈൽ നീക്കം ചെയ്യപ്പെടുകയും, അതുവഴി എല്ലാ പ്രൊഫൈൽ ഡാറ്റയും ഇല്ലാതാകുകയും ചെയ്യും."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായ രീതിയിൽ അൺലോക്ക് പാറ്റേൺ വരച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി പരാജയപ്പെട്ടാൽ, ഒരു ഇമെയിൽ അക്കൗണ്ടുപയോഗിച്ച് ടാബ്‌ലെറ്റ് അൺലോക്ക് ചെയ്യാൻ നിങ്ങളോട് ആവശ്യപ്പെടും.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> സെക്കന്റ് കഴിഞ്ഞ് വീണ്ടും ശ്രമിക്കുക."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായ രീതിയിൽ അൺലോക്ക് പാറ്റേൺ വരച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി പരാജയപ്പെട്ടാൽ, ഒരു ഇമെയിൽ അക്കൗണ്ടുപയോഗിച്ച് ഫോൺ അൺലോക്ക് ചെയ്യാൻ നിങ്ങളോട് ആവശ്യപ്പെടും.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> സെക്കന്റ് കഴിഞ്ഞ് വീണ്ടും ശ്രമിക്കുക."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"പവർ ബട്ടണിലാണ് ഫിംഗർപ്രിന്റ് സെൻസർ ഉള്ളത്. ടാബ്‌ലെറ്റിന്റെ അറ്റത്ത് ഉയർന്ന് നിൽക്കുന്ന ശബ്ദ ബട്ടണിന്റെ അടുത്തുള്ള പരന്ന ബട്ടൺ ആണ് ഇത്."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"പവർ ബട്ടണിലാണ് ഫിംഗർപ്രിന്റ് സെൻസർ ഉള്ളത്. ഉപകരണത്തിന്റെ അറ്റത്ത് ഉയർന്ന് നിൽക്കുന്ന ശബ്ദ ബട്ടണിന്റെ അടുത്തുള്ള പരന്ന ബട്ടൺ ആണ് ഇത്."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"പവർ ബട്ടണിലാണ് ഫിംഗർപ്രിന്റ് സെൻസർ ഉള്ളത്. ഫോണിന്റെ അറ്റത്ത് ഉയർന്ന് നിൽക്കുന്ന ശബ്ദ ബട്ടണിന്റെ അടുത്തുള്ള പരന്ന ബട്ടൺ ആണ് ഇത്."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"കൂടുതൽ ഓപ്ഷനുകൾക്ക് നിങ്ങളുടെ ഫോൺ അൺലോക്ക് ചെയ്യുക"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"കൂടുതൽ ഓപ്ഷനുകൾക്ക് നിങ്ങളുടെ ടാബ്‌ലെറ്റ് അൺലോക്ക് ചെയ്യുക"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"കൂടുതൽ ഓപ്ഷനുകൾക്ക് നിങ്ങളുടെ ഉപകരണം അൺലോക്ക് ചെയ്യുക"</string>
diff --git a/packages/SystemUI/res-product/values-mn/strings.xml b/packages/SystemUI/res-product/values-mn/strings.xml
index 41eb52d..dba7998 100644
--- a/packages/SystemUI/res-product/values-mn/strings.xml
+++ b/packages/SystemUI/res-product/values-mn/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Та утасны түгжээг тайлах оролдлогыг <xliff:g id="NUMBER">%d</xliff:g> удаа буруу хийсэн байна. Ажлын профайлыг устгах бөгөөд ингэснээр профайлын бүх өгөгдлийг устгах болно."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Та тайлах хээгээ <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу зурсан байна. Дахин <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа буруу зурсны дараа та имэйл бүртгэл ашиглан таблетынхаа түгжээг тайлах шаардлагатай болно.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундийн дараа дахин оролдоно уу."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Та тайлах хээгээ <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу зурсан байна. Дахин <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа буруу зурсны дараа та имэйл бүртгэл ашиглан утасныхаа түгжээг тайлах шаардлагатай болно.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундийн дараа дахин оролдоно уу."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Хурууны хээ мэдрэгч асаах/унтраах товчин дээр байдаг. Энэ нь таблетын ирмэг дээрх дууны түвшний товгор товчлуурын хажууд байх хавтгай товчлуур юм."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Хурууны хээ мэдрэгч асаах/унтраах товчин дээр байдаг. Энэ нь төхөөрөмжийн ирмэг дээрх дууны түвшний товгор товчлуурын хажууд байх хавтгай товчлуур юм."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Хурууны хээ мэдрэгч асаах/унтраах товчин дээр байдаг. Энэ нь утасны ирмэг дээрх дууны түвшний товгор товчлуурын хажууд байх хавтгай товчлуур юм."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Бусад сонголтыг харахын тулд утасныхаа түгжээг тайлна уу"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Бусад сонголтыг харахын тулд таблетынхаа түгжээг тайлна уу"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Бусад сонголтыг харахын тулд төхөөрөмжийнхөө түгжээг тайлна уу"</string>
diff --git a/packages/SystemUI/res-product/values-mr/strings.xml b/packages/SystemUI/res-product/values-mr/strings.xml
index ec277cc..3e8ddef 100644
--- a/packages/SystemUI/res-product/values-mr/strings.xml
+++ b/packages/SystemUI/res-product/values-mr/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"तुम्ही फोन अनलॉक करण्याचा <xliff:g id="NUMBER">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. कार्य प्रोफाइल काढली जाईल, त्यामुळे सर्व प्रोफाइल डेटा हटवला जाईल."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"तुम्ही तुमचा अनलॉक पॅटर्न <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने काढला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, तुम्हाला ईमेल खाते वापरून तुमचा टॅबलेट अनलॉक करण्यास सांगितले जाईल.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"तुम्ही तुमचा अनलॉक पॅटर्न <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने काढला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, तुम्हाला ईमेल खाते वापरून तुमचा फोन अनलॉक करण्यास सांगितले जाईल.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"फिंगरप्रिंट सेन्सर हे पॉवर बटणावर आहे. टॅबलेटच्या कडेला वर आलेल्या व्हॉल्यूम बटणाच्या बाजूला असलेले सपाट बटण म्हणजे पॉवर बटण."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"फिंगरप्रिंट सेन्सर हे पॉवर बटणावर आहे. डिव्हाइसच्या कडेला वरती आलेल्या व्हॉल्यूम बटणाच्या बाजूला असलेले सपाट बटण म्हणजे पॉवर बटण."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"फिंगरप्रिंट सेन्सर हे पॉवर बटणावर आहे. फोनच्या कडेला वर आलेल्या व्हॉल्यूम बटणाच्या बाजूला असलेले सपाट बटण म्हणजे पॉवर बटण."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"आणखी पर्यायांसाठी तुमचा फोन अनलॉक करा"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"आणखी पर्यायांसाठी तुमचा टॅबलेट अनलॉक करा"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"आणखी पर्यायांसाठी तुमचे डिव्हाइस अनलॉक करा"</string>
diff --git a/packages/SystemUI/res-product/values-ms/strings.xml b/packages/SystemUI/res-product/values-ms/strings.xml
index 7b247a0..31a4b4f 100644
--- a/packages/SystemUI/res-product/values-ms/strings.xml
+++ b/packages/SystemUI/res-product/values-ms/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Profil kerja ini akan dialih keluar sekali gus memadamkan semua data profil."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Anda telah tersilap lukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, anda akan diminta membuka kunci tablet anda menggunakan akaun e-mel.\n\n Cuba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> saat."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Anda telah tersilap lukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, anda akan diminta membuka kunci telefon anda menggunakan akaun e-mel.\n\n Cuba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> saat."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Penderia cap jari berada pada butang kuasa. Penderia cap jari ialah butang leper yang terletak bersebelahan butang kelantangan timbul pada bahagian tepi tablet."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Penderia cap jari berada pada butang kuasa. Penderia cap jari ialah butang leper yang terletak bersebelahan butang kelantangan timbul pada bahagian tepi peranti."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Penderia cap jari berada pada butang kuasa. Penderia cap jari ialah butang leper yang terletak bersebelahan butang kelantangan timbul pada bahagian tepi telefon."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Buka kunci telefon anda untuk mendapatkan lagi pilihan"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Buka kunci tablet anda untuk mendapatkan lagi pilihan"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Buka kunci peranti anda untuk mendapatkan lagi pilihan"</string>
diff --git a/packages/SystemUI/res-product/values-my/strings.xml b/packages/SystemUI/res-product/values-my/strings.xml
index d15df82..cfc5568 100644
--- a/packages/SystemUI/res-product/values-my/strings.xml
+++ b/packages/SystemUI/res-product/values-my/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"ဖုန်းကို <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် မှားယွင်းစွာ လော့ခ်ဖွင့်ရန် ကြိုးစားခဲ့ပါသည်။ အလုပ်ပရိုဖိုင်ကို ဖယ်ရှားလိုက်မည်ဖြစ်ပြီး ပရိုဖိုင်ဒေတာ အားလုံးကိုလည်း ဖျက်လိုက်ပါမည်။"</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"သင်သည် သင်၏ လော့ခ်ဖွင့်ခြင်းပုံစံကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ် မှားယွင်းစွာ ဆွဲခဲ့ပါသည်။ <xliff:g id="NUMBER_1">%2$d</xliff:g> ကြိမ် ထပ်မံမှားယွင်းပြီးသည့်နောက်တွင် သင့်အီးမေးလ်အကောင့်အား အသုံးပြု၍ တက်ဘလက်ကို လော့ခ်ဖွင့်ရန် တောင်းဆိုသွားပါမည်။\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> စက္ကန့်အကြာတွင် ထပ်စမ်းကြည့်ပါ။"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"သင်သည် သင်၏ လော့ခ်ဖွင့်ခြင်းပုံစံကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ် မှားယွင်းစွာ ဆွဲခဲ့ပါသည်။ <xliff:g id="NUMBER_1">%2$d</xliff:g> ကြိမ် ထပ်မံမှားယွင်းပြီးသည့်နောက်တွင် သင့်အီးမေးလ်အကောင့်အား အသုံးပြု၍ ဖုန်းကို လော့ခ်ဖွင့်ရန် တောင်းဆိုသွားပါမည်။\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> စက္ကန့်အကြာတွင် ထပ်စမ်းကြည့်ပါ။"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"လက်ဗွေ အာရုံခံကိရိယာသည် ဖွင့်ပိတ်ခလုတ်ပေါ်တွင် ရှိသည်။ တက်ဘလက်၏ဘေးဘက်ရှိ အသံထိန်းခလုတ်ဖုသီးနှင့် ကပ်လျက်မှ ခလုတ်ပြားဖြစ်သည်။"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"လက်ဗွေ အာရုံခံကိရိယာသည် ဖွင့်ပိတ်ခလုတ်ပေါ်တွင် ရှိသည်။ စက်၏ဘေးဘက်ရှိ အသံထိန်းခလုတ်ဖုသီးနှင့် ကပ်လျက်မှ ခလုတ်ပြားဖြစ်သည်။"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"လက်ဗွေ အာရုံခံကိရိယာသည် ဖွင့်ပိတ်ခလုတ်ပေါ်တွင် ရှိသည်။ ဖုန်း၏ဘေးဘက်ရှိ အသံထိန်းခလုတ်ဖုသီးနှင့် ကပ်လျက်မှ ခလုတ်ပြားဖြစ်သည်။"</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"နောက်ထပ် ထိန်းချုပ်မှုများအတွက် သင့်ဖုန်းကို လော့ခ်ဖွင့်ပါ"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"နောက်ထပ် ထိန်းချုပ်မှုများအတွက် သင့်တက်ဘလက်ကို လော့ခ်ဖွင့်ပါ"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"နောက်ထပ် ထိန်းချုပ်မှုများအတွက် သင့်စက်ကို လော့ခ်ဖွင့်ပါ"</string>
diff --git a/packages/SystemUI/res-product/values-nb/strings.xml b/packages/SystemUI/res-product/values-nb/strings.xml
index 816e9c1..5b76c8e 100644
--- a/packages/SystemUI/res-product/values-nb/strings.xml
+++ b/packages/SystemUI/res-product/values-nb/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER">%d</xliff:g> ganger. Jobbprofilen blir fjernet, og alle profildataene blir slettet."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Du har tegnet opplåsingsmønsteret feil <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%2$d</xliff:g> nye mislykkede forsøk blir du bedt om å låse opp nettbrettet via en e-postkonto.\n\n Prøv på nytt om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Du har tegnet opplåsingsmønsteret feil <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%2$d</xliff:g> nye mislykkede forsøk blir du bedt om å låse opp telefonen via en e-postkonto.\n\n Prøv på nytt om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Fingeravtrykkssensoren er på av/på-knappen. Det er den flate knappen ved siden av den hevede volumknappen på siden av nettbrettet."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Fingeravtrykkssensoren er på av/på-knappen. Det er den flate knappen ved siden av den hevede volumknappen på siden av enheten."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Fingeravtrykkssensoren er på av/på-knappen. Det er den flate knappen ved siden av den hevede volumknappen på siden av telefonen."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Lås opp telefonen din for å få flere alternativer"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Lås opp nettbrettet ditt for å få flere alternativer"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Lås opp enheten din for å få flere alternativer"</string>
diff --git a/packages/SystemUI/res-product/values-ne/strings.xml b/packages/SystemUI/res-product/values-ne/strings.xml
index eef80b2..2d7b03f 100644
--- a/packages/SystemUI/res-product/values-ne/strings.xml
+++ b/packages/SystemUI/res-product/values-ne/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"तपाईंले <xliff:g id="NUMBER">%d</xliff:g> पटक गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नुभएको छ। कार्य प्रोफाइललाई यसका सबै डेटा मेटिने गरी हटाइने छ।"</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक आफ्नो अनलक गर्ने ढाँचा गलत रूपमा कोर्नुभयो। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> पटक असफल प्रयास गरेपछि, तपाईंलाई एउटा इमेल खाता प्रयोग गरेर आफ्नो ट्याब्लेट अनलक गर्न आग्रह गरिने छ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकेन्डमा फेरि प्रयास गर्नुहोस्।"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक आफ्नो अनलक गर्ने ढाँचा गलत रूपमा कोर्नुभयो। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> पटक असफल प्रयास गरेपछि, तपाईंलाई एउटा इमेल खाता प्रयोग गरेर आफ्नो फोन अनलक गर्न आग्रह गरिने छ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकेन्डमा फेरि प्रयास गर्नुहोस्।"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"फिंगरप्रिन्ट सेन्सर पावर बटनमा हुन्छ। यो ट्याब्लेटको किनारामा रहेको थोरै उचालिएको भोल्युम बटनको छेउमा रहेको चेप्टो बटन नै पावर बटन हो।"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"फिंगरप्रिन्ट सेन्सर पावर बटनमा हुन्छ। यो डिभाइसको किनारामा रहेको थोरै उचालिएको भोल्युम बटनको छेउमा रहेको चेप्टो बटन नै पावर बटन हो।"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"फिंगरप्रिन्ट सेन्सर पावर बटनमा हुन्छ। यो फोनको किनारामा रहेको थोरै उचालिएको भोल्युम बटनको छेउमा रहेको चेप्टो बटन नै पावर बटन हो।"</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"थप विकल्पहरू हेर्न आफ्नो फोन अनलक गर्नुहोस्"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"थप विकल्पहरू हेर्न आफ्नो ट्याब्लेट अनलक गर्नुहोस्"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"थप विकल्पहरू हेर्न आफ्नो डिभाइस अनलक गर्नुहोस्"</string>
diff --git a/packages/SystemUI/res-product/values-nl/strings.xml b/packages/SystemUI/res-product/values-nl/strings.xml
index 95e32ef..829f1a6 100644
--- a/packages/SystemUI/res-product/values-nl/strings.xml
+++ b/packages/SystemUI/res-product/values-nl/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Je hebt <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Het werkprofiel wordt verwijderd, waardoor alle profielgegevens worden verwijderd."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Je hebt je ontgrendelingspatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt je gevraagd je tablet te ontgrendelen via een e-mailaccount.\n\n Probeer het over <xliff:g id="NUMBER_2">%3$d</xliff:g> seconden opnieuw."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Je hebt je ontgrendelingspatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt je gevraagd je telefoon te ontgrendelen via een e-mailaccount.\n\n Probeer het over <xliff:g id="NUMBER_2">%3$d</xliff:g> seconden opnieuw."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Je vindt de vingerafdruksensor onder de aan/uit-knop. Het is de platte knop naast de verhoogde volumeknop aan de zijkant van de tablet."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Je vindt de vingerafdruksensor onder de aan/uit-knop. Het is de platte knop naast de verhoogde volumeknop aan de zijkant van het apparaat."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Je vindt de vingerafdruksensor onder de aan/uit-knop. Het is de platte knop naast de verhoogde volumeknop aan de zijkant van de telefoon."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Ontgrendel je telefoon voor meer opties"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Ontgrendel je tablet voor meer opties"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Ontgrendel je apparaat voor meer opties"</string>
diff --git a/packages/SystemUI/res-product/values-or/strings.xml b/packages/SystemUI/res-product/values-or/strings.xml
index e0d9366..7aa09a64 100644
--- a/packages/SystemUI/res-product/values-or/strings.xml
+++ b/packages/SystemUI/res-product/values-or/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"ଆପଣ ଫୋନ୍‌କୁ ଅନ୍‌ଲକ୍ କରିବାକୁ<xliff:g id="NUMBER">%d</xliff:g>ଥର ଭୁଲ ପ୍ରୟାସ କରିଛନ୍ତି। କାର୍ଯ୍ୟ ପ୍ରୋଫାଇଲ୍ ବାହାର କରିଦିଆଯିବ, ଯାହା ଫଳରେ ସମସ୍ତ ପ୍ରୋଫାଇଲ୍ ଡାଟା ଡିଲିଟ୍ ହେବ।"</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"ଆପଣ ଆପଣଙ୍କ ଅନ୍‌ଲକ୍ ପାଟର୍ନକୁ <xliff:g id="NUMBER_0">%1$d</xliff:g>ଥର ଭୁଲ ଭାବେ ଡ୍ର କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g>ଟି ଭୁଲ ପ୍ରୟାସ ପରେ ଆପଣଙ୍କୁ ଏକ ଇମେଲ୍ ଆକାଉଣ୍ଟ ବ୍ୟବହାର କରି ଆପଣଙ୍କ ଟାବ୍‌ଲୋଟ୍‌କୁ ଅନ୍‌ଲକ୍ କରିବା ପାଇଁ କୁହାଯିବ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ସେକେଣ୍ଡ ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"ଆପଣ ଆପଣଙ୍କ ଅନ୍‌ଲକ୍ ପାଟର୍ନକୁ <xliff:g id="NUMBER_0">%1$d</xliff:g>ଥର ଭୁଲ ଭାବେ ଡ୍ର କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g>ଟି ଭୁଲ ପ୍ରୟାସ ପରେ ଆପଣଙ୍କୁ ଏକ ଇମେଲ୍ ଆକାଉଣ୍ଟ ବ୍ୟବହାର କରି ଆପଣଙ୍କ ଫୋନ୍‌କୁ ଅନ୍‌ଲକ୍‌ କରିବା ପାଇଁ କୁହାଯିବ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ସେକେଣ୍ଡ ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"ଟିପଚିହ୍ନ ସେନ୍ସର ପାୱାର ବଟନରେ ଅଛି। ଏହା ଟାବଲେଟର ଧାରରେ ବଢ଼ାଯାଇଥିବା ଭଲ୍ୟୁମ ବଟନ ପାଖରେ ଥିବା ଫ୍ଲାଟ ବଟନ ଅଟେ।"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"ଟିପଚିହ୍ନ ସେନ୍ସର ପାୱାର ବଟନରେ ଅଛି। ଏହା ଡିଭାଇସର ଧାରରେ ବଢ଼ାଯାଇଥିବା ଭଲ୍ୟୁମ ବଟନ ପାଖରେ ଥିବା ଫ୍ଲାଟ ବଟନ ଅଟେ।"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"ଟିପଚିହ୍ନ ସେନ୍ସର ପାୱାର ବଟନରେ ଅଛି। ଏହା ଫୋନର ଧାରରେ ବଢ଼ାଯାଇଥିବା ଭଲ୍ୟୁମ ବଟନ ପାଖରେ ଥିବା ଫ୍ଲାଟ ବଟନ ଅଟେ।"</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"ଅଧିକ ବିକଳ୍ପ ପାଇଁ ଆପଣଙ୍କ ଫୋନ୍ ଅନଲକ୍ କରନ୍ତୁ"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"ଅଧିକ ବିକଳ୍ପ ପାଇଁ ଆପଣଙ୍କ ଟାବଲେଟ୍ ଅନଲକ୍ କରନ୍ତୁ"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"ଅଧିକ ବିକଳ୍ପ ପାଇଁ ଆପଣଙ୍କ ଡିଭାଇସ୍ ଅନଲକ୍ କରନ୍ତୁ"</string>
diff --git a/packages/SystemUI/res-product/values-pa/strings.xml b/packages/SystemUI/res-product/values-pa/strings.xml
index d65998b..71409b6e 100644
--- a/packages/SystemUI/res-product/values-pa/strings.xml
+++ b/packages/SystemUI/res-product/values-pa/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"ਤੁਸੀਂ <xliff:g id="NUMBER">%d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਫ਼ੋਨ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ। ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਹਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਸਾਰਾ ਪ੍ਰੋਫਾਈਲ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਆਪਣਾ ਅਣਲਾਕ ਪੈਟਰਨ ਗਲਤ ਢੰਗ ਨਾਲ ਉਲੀਕਿਆ ਹੈ। <xliff:g id="NUMBER_1">%2$d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਤੁਹਾਨੂੰ ਇੱਕ ਈਮੇਲ ਖਾਤਾ ਵਰਤਦੇ ਹੋਏ ਆਪਣੇ ਟੈਬਲੈੱਟ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਲਈ ਕਿਹਾ ਜਾਵੇਗਾ।\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਆਪਣਾ ਅਣਲਾਕ ਪੈਟਰਨ ਗਲਤ ਢੰਗ ਨਾਲ ਡ੍ਰਾ ਕੀਤਾ ਹੈ। <xliff:g id="NUMBER_1">%2$d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਤੁਹਾਨੂੰ ਇੱਕ ਈਮੇਲ ਖਾਤਾ ਵਰਤਦੇ ਹੋਏ ਆਪਣਾ ਫ਼ੋਨ ਅਣਲਾਕ ਕਰਨ ਲਈ ਕਿਹਾ ਜਾਏਗਾ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ ਪਾਵਰ ਬਟਨ \'ਤੇ ਹੈ। ਇਹ ਟੈਬਲੈੱਟ ਦੇ ਕਿਨਾਰੇ \'ਤੇ ਅਜਿਹਾ ਸਮਤਲ ਬਟਨ ਹੁੰਦਾ ਹੈ ਜੋ ਉੱਭਰੇ ਹੋਏ ਅਵਾਜ਼ ਬਟਨ ਦੇ ਅੱਗੇ ਹੁੰਦਾ ਹੈ।"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ ਪਾਵਰ ਬਟਨ \'ਤੇ ਹੈ। ਇਹ ਡੀਵਾਈਸ ਦੇ ਕਿਨਾਰੇ \'ਤੇ ਅਜਿਹਾ ਸਮਤਲ ਬਟਨ ਹੁੰਦਾ ਹੈ ਜੋ ਉੱਭਰੇ ਹੋਏ ਅਵਾਜ਼ ਬਟਨ ਦੇ ਅੱਗੇ ਹੁੰਦਾ ਹੈ।"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ ਪਾਵਰ ਬਟਨ \'ਤੇ ਹੈ। ਇਹ ਫ਼ੋਨ ਦੇ ਕਿਨਾਰੇ \'ਤੇ ਅਜਿਹਾ ਸਮਤਲ ਬਟਨ ਹੁੰਦਾ ਹੈ ਜੋ ਉੱਭਰੇ ਹੋਏ ਅਵਾਜ਼ ਬਟਨ ਦੇ ਅੱਗੇ ਹੁੰਦਾ ਹੈ।"</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"ਹੋਰ ਵਿਕਲਪਾਂ ਲਈ ਆਪਣਾ ਫ਼ੋਨ ਅਣਲਾਕ ਕਰੋ"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"ਹੋਰ ਵਿਕਲਪਾਂ ਲਈ ਆਪਣਾ ਟੈਬਲੈੱਟ ਅਣਲਾਕ ਕਰੋ"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"ਹੋਰ ਵਿਕਲਪਾਂ ਲਈ ਆਪਣਾ ਡੀਵਾਈਸ ਅਣਲਾਕ ਕਰੋ"</string>
diff --git a/packages/SystemUI/res-product/values-pl/strings.xml b/packages/SystemUI/res-product/values-pl/strings.xml
index f6360eb..3f5bc77 100644
--- a/packages/SystemUI/res-product/values-pl/strings.xml
+++ b/packages/SystemUI/res-product/values-pl/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Po raz <xliff:g id="NUMBER">%d</xliff:g> próbowano nieprawidłowo odblokować telefon. Profil służbowy zostanie usunięty, co spowoduje skasowanie wszystkich jego danych."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> nieprawidłowo narysowano wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach konieczne będzie odblokowanie tabletu przy użyciu konta e-mail.\n\n Spróbuj ponownie za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> nieprawidłowo narysowano wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach konieczne będzie odblokowanie telefonu przy użyciu konta e-mail.\n\n Spróbuj ponownie za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Czytnik linii papilarnych znajduje się na przycisku zasilania. To płaski przycisk przy uniesionym przycisku głośności na krawędzi tabletu."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Czytnik linii papilarnych znajduje się na przycisku zasilania. To płaski przycisk przy uniesionym przycisku głośności na krawędzi urządzenia."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Czytnik linii papilarnych znajduje się na przycisku zasilania. To płaski przycisk przy uniesionym przycisku głośności na krawędzi telefonu."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Odblokuj telefon, by wyświetlić więcej opcji"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Odblokuj tablet, by wyświetlić więcej opcji"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Odblokuj urządzenie, by wyświetlić więcej opcji"</string>
diff --git a/packages/SystemUI/res-product/values-pt-rBR/strings.xml b/packages/SystemUI/res-product/values-pt-rBR/strings.xml
index fff7606..55e64ff 100644
--- a/packages/SystemUI/res-product/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res-product/values-pt-rBR/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Você desenhou seu padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use uma conta de e-mail para desbloquear o tablet.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Você desenhou seu padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use uma conta de e-mail para desbloquear o smartphone.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"O sensor de impressão digital fica no botão liga/desliga. Ele é plano e está ao lado do botão de volume na borda do tablet."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"O sensor de impressão digital fica no botão liga/desliga. Ele é plano e está ao lado do botão de volume na borda do dispositivo."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"O sensor de impressão digital fica no botão liga/desliga. Ele é plano e está ao lado do botão de volume na borda do smartphone."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Desbloqueie seu smartphone para ver mais opções"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Desbloqueie seu tablet para ver mais opções"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Desbloqueie seu dispositivo para ver mais opções"</string>
diff --git a/packages/SystemUI/res-product/values-pt-rPT/strings.xml b/packages/SystemUI/res-product/values-pt-rPT/strings.xml
index 678bd26..d82d340 100644
--- a/packages/SystemUI/res-product/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res-product/values-pt-rPT/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Tentou desbloquear incorretamente o telemóvel <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que eliminará todos os dados do mesmo."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Desenhou o padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, ser-lhe-á pedido para desbloquear o tablet através de uma conta de email.\n\n Tente novamente dentro de <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Desenhou o padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, ser-lhe-á pedido para desbloquear o telemóvel através de uma conta de email.\n\n Tente novamente dentro de <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"O sensor de impressões digitais encontra-se no botão ligar/desligar. É o botão sem relevo junto ao botão de volume com relevo na extremidade do tablet."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"O sensor de impressões digitais encontra-se no botão ligar/desligar. É o botão sem relevo junto ao botão de volume com relevo na extremidade do dispositivo."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"O sensor de impressões digitais encontra-se no botão ligar/desligar. É o botão sem relevo junto ao botão de volume com relevo na extremidade do telemóvel."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Desbloqueie o telemóvel para obter mais opções."</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Desbloqueie o tablet para obter mais opções."</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Desbloqueie o dispositivo para obter mais opções."</string>
diff --git a/packages/SystemUI/res-product/values-pt/strings.xml b/packages/SystemUI/res-product/values-pt/strings.xml
index fff7606..55e64ff 100644
--- a/packages/SystemUI/res-product/values-pt/strings.xml
+++ b/packages/SystemUI/res-product/values-pt/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Você desenhou seu padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use uma conta de e-mail para desbloquear o tablet.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Você desenhou seu padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use uma conta de e-mail para desbloquear o smartphone.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"O sensor de impressão digital fica no botão liga/desliga. Ele é plano e está ao lado do botão de volume na borda do tablet."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"O sensor de impressão digital fica no botão liga/desliga. Ele é plano e está ao lado do botão de volume na borda do dispositivo."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"O sensor de impressão digital fica no botão liga/desliga. Ele é plano e está ao lado do botão de volume na borda do smartphone."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Desbloqueie seu smartphone para ver mais opções"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Desbloqueie seu tablet para ver mais opções"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Desbloqueie seu dispositivo para ver mais opções"</string>
diff --git a/packages/SystemUI/res-product/values-ro/strings.xml b/packages/SystemUI/res-product/values-ro/strings.xml
index 471f01e..40f402b 100644
--- a/packages/SystemUI/res-product/values-ro/strings.xml
+++ b/packages/SystemUI/res-product/values-ro/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Ai făcut <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Profilul de serviciu va fi eliminat, iar toate datele profilului vor fi șterse."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Ai desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, ți se va solicita să deblochezi tableta cu ajutorul unui cont de e-mail.\n\n Încearcă din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> secunde."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Ai desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, ți se va solicita să deblochezi telefonul cu ajutorul unui cont de e-mail.\n\n Încearcă din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> secunde."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Senzorul de amprentă se află pe butonul de pornire. Este butonul plat de lângă butonul de volum în relief de pe marginea tabletei."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Senzorul de amprentă se află pe butonul de pornire. Este butonul plat de lângă butonul de volum în relief de pe marginea dispozitivului."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Senzorul de amprentă se află pe butonul de pornire. Este butonul plat de lângă butonul de volum în relief de pe marginea telefonului."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Deblochează telefonul pentru mai multe opțiuni"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Deblochează tableta pentru mai multe opțiuni"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Deblochează dispozitivul pentru mai multe opțiuni"</string>
diff --git a/packages/SystemUI/res-product/values-ru/strings.xml b/packages/SystemUI/res-product/values-ru/strings.xml
index 0d0dd1c..0b4f559b 100644
--- a/packages/SystemUI/res-product/values-ru/strings.xml
+++ b/packages/SystemUI/res-product/values-ru/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Вы несколько раз (<xliff:g id="NUMBER">%d</xliff:g>) не смогли разблокировать телефон. Рабочий профиль и все его данные будут удалены."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Вы несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>) ввели неверный графический ключ. Осталось попыток: <xliff:g id="NUMBER_1">%2$d</xliff:g>. В случае неудачи вам будет предложено разблокировать планшет с помощью аккаунта электронной почты.\n\nПовторите попытку через <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Вы несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>) ввели неверный графический ключ. Осталось попыток: <xliff:g id="NUMBER_1">%2$d</xliff:g>. В случае неудачи вам будет предложено разблокировать телефон с помощью аккаунта электронной почты.\n\nПовторите попытку через <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Сканер отпечатков пальцев находится на кнопке питания. Она плоская и расположена рядом с приподнятой кнопкой регулировки громкости на боковой стороне планшета."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Сканер отпечатков пальцев находится на кнопке питания. Она плоская и расположена рядом с приподнятой кнопкой регулировки громкости на боковой стороне устройства."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Сканер отпечатков пальцев находится на кнопке питания. Она плоская и расположена рядом с приподнятой кнопкой регулировки громкости на боковой стороне телефона."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Чтобы посмотреть дополнительные параметры, разблокируйте телефон."</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Чтобы посмотреть дополнительные параметры, разблокируйте планшет."</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Чтобы посмотреть дополнительные параметры, разблокируйте устройство."</string>
diff --git a/packages/SystemUI/res-product/values-si/strings.xml b/packages/SystemUI/res-product/values-si/strings.xml
index 0d7b67d..fd29f44 100644
--- a/packages/SystemUI/res-product/values-si/strings.xml
+++ b/packages/SystemUI/res-product/values-si/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"ඔබ දුරකථනය අගුළු හැරීමට <xliff:g id="NUMBER">%d</xliff:g> වරක් වැරදියට උත්සාහ කර ඇත. කාර්යාල පැතිකඩ ඉවත් කරනු ඇති අතර, එය සියලු පැතිකඩ දත්ත මකනු ඇත."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"ඔබ අගුළු ඇරිමේ රටාව <xliff:g id="NUMBER_0">%1$d</xliff:g> වතාවක් වැරදියට ඇඳ ඇත. තවත් අසාර්ථක උත්සාහ <xliff:g id="NUMBER_1">%2$d</xliff:g> කින් පසුව, ඊ-තැපැල් ගිණුම භාවිතා කරමින් ඔබගේ ටැබ්ලටයේ අගුළු ඇරීමට ඔබට පවසනු ඇත.\n\n නැවත තත්පර <xliff:g id="NUMBER_2">%3$d</xliff:g> කින් උත්සාහ කරන්න."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"ඔබ වැරදියට <xliff:g id="NUMBER_0">%1$d</xliff:g> වතාවක් ඔබගේ අගුළු හැරීමේ රටාව ඇඳ ඇත. අසාර්ථක උත්සහ කිරීම් <xliff:g id="NUMBER_1">%2$d</xliff:g> න් පසුව, ඔබගේ ඊ-තැපැල් ලිපිනය භාවිතයෙන් ඔබගේ දුරකථනය අගුළු හැරීමට ඔබගෙන් අසයි.\n\n තත්පර <xliff:g id="NUMBER_2">%3$d</xliff:g> න් පසුව නැවත උත්සහ කරන්න."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"ඇඟිලි සලකුණු සංවේදකය බල බොත්තම මත ඇත. එය ටැබ්ලටයෙහි කෙළවර ඇති ඉහළ හඬ පරිමා බොත්තම අසල ඇති පැතලි බොත්තමයි."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"ඇඟිලි සලකුණු සංවේදකය බල බොත්තම මත ඇත. එය උපාංගයෙහි කෙළවර ඇති ඉහළ හඬ පරිමා බොත්තම අසල ඇති පැතලි බොත්තමයි."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"ඇඟිලි සලකුණු සංවේදකය බල බොත්තම මත ඇත. එය දුරකථනයෙහි කෙළවර ඇති ඉහළ හඬ පරිමා බොත්තම අසල ඇති පැතලි බොත්තමයි."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"තව විකල්ප සඳහා ඔබේ දුරකථනය අගුලු හරින්න"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"තව විකල්ප සඳහා ඔබේ ටැබ්ලට් පරිගණකය අගුලු හරින්න"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"තව විකල්ප සඳහා ඔබේ උපාංගය අගුලු හරින්න"</string>
diff --git a/packages/SystemUI/res-product/values-sk/strings.xml b/packages/SystemUI/res-product/values-sk/strings.xml
index 3caddbe..e65777b 100644
--- a/packages/SystemUI/res-product/values-sk/strings.xml
+++ b/packages/SystemUI/res-product/values-sk/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Telefón ste sa pokúsili <xliff:g id="NUMBER">%d</xliff:g>‑krát nesprávne odomknúť. Pracovný profil bude odstránený spolu so všetkými údajmi."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"<xliff:g id="NUMBER_0">%1$d</xliff:g>‑krát ste nesprávne nakreslili svoj bezpečnostný vzor. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> ďalších neúspešných pokusoch sa zobrazí výzva na odomknutie tabletu pomocou e‑mailového účtu.\n\n Skúste to znova o <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Už ste <xliff:g id="NUMBER_0">%1$d</xliff:g>‑krát nesprávne nakreslili svoj bezpečnostný vzor. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> ďalších neúspešných pokusoch sa zobrazí výzva na odomknutie telefónu pomocou e‑mailového účtu.\n\n Skúste to znova o <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Senzor odtlačkov prstov je na vypínači. Je to ploché tlačidlo vedľa vypuklého tlačidla hlasitosti na okraji tabletu."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Senzor odtlačkov prstov je na vypínači. Je to ploché tlačidlo vedľa vypuklého tlačidla hlasitosti na okraji zariadenia."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Senzor odtlačkov prstov je na vypínači. Je to ploché tlačidlo vedľa vypuklého tlačidla hlasitosti na okraji telefónu."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Ak chcete zobraziť ďalšie možnosti, odomknite telefón"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Ak chcete zobraziť ďalšie možnosti, odomknite tablet"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Ak chcete zobraziť ďalšie možnosti, odomknite zariadenie"</string>
diff --git a/packages/SystemUI/res-product/values-sl/strings.xml b/packages/SystemUI/res-product/values-sl/strings.xml
index 96ac31b..b3859c9 100644
--- a/packages/SystemUI/res-product/values-sl/strings.xml
+++ b/packages/SystemUI/res-product/values-sl/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Telefon ste neuspešno poskusili odkleniti <xliff:g id="NUMBER">%d</xliff:g>-krat. Delovni profil bo odstranjen in vsi podatki profila bodo izbrisani."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat napačno vnesli. Če ga neuspešno poskusite vnesti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, boste pozvani, da tablični računalnik odklenete z e-poštnim računom.\n\nPoskusite znova čez <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat napačno vnesli. Če ga neuspešno poskusite vnesti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, boste pozvani, da telefon odklenete z e-poštnim računom.\n\nPoskusite znova čez <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Tipalo prstnih odtisov je na gumbu za vklop. To je ploski gumb ob izbočenem gumbu za glasnost na robu tabličnega računalnika."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Tipalo prstnih odtisov je na gumbu za vklop. To je ploski gumb ob izbočenem gumbu za glasnost na robu naprave."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Tipalo prstnih odtisov je na gumbu za vklop. To je ploski gumb ob izbočenem gumbu za glasnost na robu telefona."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Za več možnosti odklenite telefon"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Za več možnosti odklenite tablični računalnik"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Za več možnosti odklenite napravo"</string>
diff --git a/packages/SystemUI/res-product/values-sq/strings.xml b/packages/SystemUI/res-product/values-sq/strings.xml
index f552b29..c7f9085 100644
--- a/packages/SystemUI/res-product/values-sq/strings.xml
+++ b/packages/SystemUI/res-product/values-sq/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Ke tentuar <xliff:g id="NUMBER">%d</xliff:g> herë pa sukses për ta shkyçur telefonin. Profili i punës do të hiqet, gjë që do të fshijë të gjitha të dhënat e profilit."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Ke vizatuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses motivin tënd të shkyçjes. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativave të tjera të pasuksesshme, do të të duhet ta shkyçësh tabletin duke përdorur një llogari email-i.\n\n Provo sërish për <xliff:g id="NUMBER_2">%3$d</xliff:g> sekonda."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Ke vizatuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses motivin tënd. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativave të tjera të pasuksesshme, do të të duhet ta shkyçësh telefonin duke përdorur një llogari email-i.\n\n Provo sërish për <xliff:g id="NUMBER_2">%3$d</xliff:g> sekonda."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Sensori i gjurmës së gishtit është në butonin e energjisë. Ai është butoni i rrafshët pranë butonit të ngritur të volumit në anë të tabletit."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Sensori i gjurmës së gishtit është në butonin e energjisë. Ai është butoni i rrafshët pranë butonit të ngritur të volumit në anë të pajisjes."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Sensori i gjurmës së gishtit është në butonin e energjisë. Ai është butoni i rrafshët pranë butonit të ngritur të volumit në anë të telefonit."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Shkyçe telefonin për më shumë opsione"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Shkyçe tabletin për më shumë opsione"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Shkyçe pajisjen për më shumë opsione"</string>
diff --git a/packages/SystemUI/res-product/values-sr/strings.xml b/packages/SystemUI/res-product/values-sr/strings.xml
index f1e6eec..435c2fb 100644
--- a/packages/SystemUI/res-product/values-sr/strings.xml
+++ b/packages/SystemUI/res-product/values-sr/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER">%d</xliff:g> пута. Уклонићемо пословни профил, чиме се бришу сви подаци са профила."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Нетачно сте нацртали шаблон за откључавање <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, затражићемо да откључате таблет помоћу имејл налога.\n\n Пробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Нетачно сте нацртали шаблон за откључавање <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, затражићемо да откључате телефон помоћу имејл налога.\n\n Пробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Сензор за отисак прста се налази на дугмету за укључивање. То је равно дугме поред издигнутог дугмета за јачину звука на ивици таблета."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Сензор за отисак прста се налази на дугмету за укључивање. То је равно дугме поред издигнутог дугмета за јачину звука на ивици уређаја."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Сензор за отисак прста се налази на дугмету за укључивање. То је равно дугме поред издигнутог дугмета за јачину звука на ивици телефона."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Откључајте телефон за још опција"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Откључајте таблет за још опција"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Откључајте уређај за још опција"</string>
diff --git a/packages/SystemUI/res-product/values-sv/strings.xml b/packages/SystemUI/res-product/values-sv/strings.xml
index 397580f6..a7db280 100644
--- a/packages/SystemUI/res-product/values-sv/strings.xml
+++ b/packages/SystemUI/res-product/values-sv/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Du har försökt låsa upp telefonen på ett felaktigt sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Jobbprofilen tas bort och all profildata raderas."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%2$d</xliff:g> försök måste du låsa upp surfplattan med hjälp av ett e-postkonto.\n\n Försök igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%2$d</xliff:g> försök måste du låsa upp telefonen med hjälp av ett e-postkonto.\n\n Försök igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Fingeravtryckssensorn sitter på av/på-knappen. Det är den platta knappen bredvid den upphöjda volymknappen på surfplattans kant."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Fingeravtryckssensorn sitter på av/på-knappen. Det är den platta knappen bredvid den upphöjda volymknappen på enhetens kant."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Fingeravtryckssensorn sitter på av/på-knappen. Det är den platta knappen bredvid den upphöjda volymknappen på telefonens kant."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Lås upp telefonen för fler alternativ"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Lås upp surfplattan för fler alternativ"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Lås upp enheten för fler alternativ"</string>
diff --git a/packages/SystemUI/res-product/values-sw/strings.xml b/packages/SystemUI/res-product/values-sw/strings.xml
index 863838f..57b0d75 100644
--- a/packages/SystemUI/res-product/values-sw/strings.xml
+++ b/packages/SystemUI/res-product/values-sw/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Umejaribu kufungua simu mara <xliff:g id="NUMBER">%d</xliff:g> bila mafanikio. Wasifu wa kazini utaondolewa, hatua itakayofuta data yote ya wasifu."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Umeweka mchoro usio sahihi wa kufungua skrini mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%2$d</xliff:g> zaidi bila mafanikio, utaombwa ufungue kompyuta yako kibao kwa kutumia akaunti ya barua pepe.\n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%3$d</xliff:g>."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Umeweka mchoro usio sahihi wa kufungua skrini mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Ukikosea mara nyingine <xliff:g id="NUMBER_1">%2$d</xliff:g>, utaombwa ufungue simu yako kwa kutumia akaunti ya barua pepe.\n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%3$d</xliff:g>."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Kitambuzi cha alama ya kidole kinapatikana kwenye kitufe cha kuwasha/kuzima. Ni kitufe bapa pembeni pa kitufe cha sauti kilichoinuka kwenye ukingo wa kompyuta kibao."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Kitambuzi cha alama ya kidole kinapatikana kwenye kitufe cha kuwasha/kuzima. Ni kitufe bapa pembeni pa kitufe cha sauti kilichoinuka kwenye ukingo wa kifaa."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Kitambuzi cha alama ya kidole kinapatikana kwenye kitufe cha kuwasha/kuzima. Ni kitufe bapa pembeni pa kitufe cha sauti kilichoinuka kwenye ukingo wa simu."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Fungua simu yako ili upate chaguo zaidi"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Fungua kompyuta yako kibao ili upate chaguo zaidi"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Fungua kifaa chako ili upate chaguo zaidi"</string>
diff --git a/packages/SystemUI/res-product/values-ta/strings.xml b/packages/SystemUI/res-product/values-ta/strings.xml
index 0582460..d692060 100644
--- a/packages/SystemUI/res-product/values-ta/strings.xml
+++ b/packages/SystemUI/res-product/values-ta/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"மொபைலை அன்லாக் செய்ய, <xliff:g id="NUMBER">%d</xliff:g> முறை தவறாக முயன்றுவிட்டதனால் பணிக் கணக்கு அகற்றப்படும். இதனால் அதிலுள்ள அனைத்துச் சுயவிவரத் தரவும் நீக்கப்படும்."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"அன்லாக் பேட்டர்னை, <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக வரைந்துவிட்டீர்கள். இன்னும் <xliff:g id="NUMBER_1">%2$d</xliff:g> முறை தவறாக வரைந்தால், மின்னஞ்சல் கணக்கைப் பயன்படுத்தி டேப்லெட்டை அன்லாக் செய்யும்படி கேட்கப்படுவீர்கள்.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> வினாடிகளில் மீண்டும் முயலவும்."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"அன்லாக் பேட்டர்னை, <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக வரைந்துவிட்டீர்கள். இன்னும் <xliff:g id="NUMBER_1">%2$d</xliff:g> முறை தவறாக வரைந்தால், மின்னஞ்சல் கணக்கைப் பயன்படுத்தி மொபைலை அன்லாக் செய்யும்படி கேட்கப்படுவீர்கள்.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> வினாடிகளில் மீண்டும் முயலவும்."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"\'கைரேகை சென்சார்\' பவர் பட்டனில் உள்ளது. இது டேப்லெட்டின் விளிம்பில் சற்று மேலெழும்பிய ஒலியளவு பட்டனுக்கு அடுத்துள்ள தட்டையான பட்டனாகும்."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"\'கைரேகை சென்சார்\' பவர் பட்டனில் உள்ளது. இது சாதனத்தின் விளிம்பில் சற்று மேலெழும்பிய ஒலியளவு பட்டனுக்கு அடுத்துள்ள தட்டையான பட்டனாகும்."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"\'கைரேகை சென்சார்\' பவர் பட்டனில் உள்ளது. இது மொபைலின் விளிம்பில் சற்று மேலெழும்பிய ஒலியளவு பட்டனுக்கு அடுத்துள்ள தட்டையான பட்டனாகும்."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"மேலும் விருப்பங்களுக்கு மொபைலை அன்லாக் செய்யவும்"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"மேலும் விருப்பங்களுக்கு டேப்லெட்டை அன்லாக் செய்யவும்"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"மேலும் விருப்பங்களுக்குச் சாதனத்தை அன்லாக் செய்யவும்"</string>
diff --git a/packages/SystemUI/res-product/values-te/strings.xml b/packages/SystemUI/res-product/values-te/strings.xml
index 088cf88..2bab57a 100644
--- a/packages/SystemUI/res-product/values-te/strings.xml
+++ b/packages/SystemUI/res-product/values-te/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"మీరు ఫోన్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు తప్పు ప్రయత్నాలు చేశారు. కార్యాలయ ప్రొఫైల్ తీసివేయబడుతుంది, దీని వలన ప్రొఫైల్ డేటా మొత్తం తొలగించబడుతుంది."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"మీరు మీ అన్‌లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> ప్రయత్నాలలో విఫలమైతే, మీరు ఈమెయిల్‌ ఖాతాను ఉపయోగించి మీ టాబ్లెట్‌ను అన్‌లాక్ చేయాల్సి వస్తుంది.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"మీరు మీ అన్‌లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> ప్రయత్నాలలో విఫలమైతే, మీరు ఈమెయిల్‌ ఖాతాను ఉపయోగించి మీ ఫోన్‌ను అన్‌లాక్ చేయాల్సి వస్తుంది.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"వేలిముద్ర సెన్సార్ పవర్ బటన్‌పై ఉంది. ఇది, ఈ టాబ్లెట్ అంచున ఉబ్బెత్తుగా ఉన్న వాల్యూమ్ బటన్ పక్కన ఉన్న ఫ్లాట్ బటన్."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"వేలిముద్ర సెన్సార్ పవర్ బటన్‌పై ఉంది. ఇది, ఈ పరికరం అంచున ఉబ్బెత్తుగా ఉన్న వాల్యూమ్ బటన్ పక్కన ఉన్న ఫ్లాట్ బటన్."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"వేలిముద్ర సెన్సార్ పవర్ బటన్‌పై ఉంది. ఇది, ఈ ఫోన్ అంచున ఉబ్బెత్తుగా ఉన్న వాల్యూమ్ బటన్ పక్కన ఉన్న ఫ్లాట్ బటన్."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"మరిన్ని ఆప్షన్‌ల కోసం మీ ఫోన్‌ను అన్‌లాక్ చేయండి"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"మరిన్ని ఆప్షన్‌ల కోసం మీ టాబ్లెట్‌ను అన్‌లాక్ చేయండి"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"మరిన్ని ఆప్షన్‌ల కోసం మీ పరికరాన్ని అన్‌లాక్ చేయండి"</string>
diff --git a/packages/SystemUI/res-product/values-th/strings.xml b/packages/SystemUI/res-product/values-th/strings.xml
index f367f9a..8a053cd 100644
--- a/packages/SystemUI/res-product/values-th/strings.xml
+++ b/packages/SystemUI/res-product/values-th/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"คุณปลดล็อกโทรศัพท์ไม่ถูกต้อง <xliff:g id="NUMBER">%d</xliff:g> ครั้งแล้ว ระบบจะนำโปรไฟล์งานออก ซึ่งจะเป็นการลบข้อมูลทั้งหมดในโปรไฟล์"</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้งแล้ว หากทำไม่สำเร็จอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> ครั้ง ระบบจะขอให้คุณปลดล็อกแท็บเล็ตโดยใช้บัญชีอีเมล\n\n โปรดลองอีกครั้งใน <xliff:g id="NUMBER_2">%3$d</xliff:g> วินาที"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้งแล้ว หากทำไม่สำเร็จอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> ครั้ง ระบบจะขอให้คุณปลดล็อกโทรศัพท์โดยใช้บัญชีอีเมล\n\n โปรดลองอีกครั้งในอีก <xliff:g id="NUMBER_2">%3$d</xliff:g> วินาที"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"เซ็นเซอร์ลายนิ้วมืออยู่ที่ปุ่มเปิด/ปิด ซึ่งเป็นปุ่มแบนข้างปุ่มนูนที่ใช้ปรับระดับเสียงตรงบริเวณขอบของแท็บเล็ต"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"เซ็นเซอร์ลายนิ้วมืออยู่ที่ปุ่มเปิด/ปิด ซึ่งเป็นปุ่มแบนข้างปุ่มนูนที่ใช้ปรับระดับเสียงตรงบริเวณขอบของอุปกรณ์"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"เซ็นเซอร์ลายนิ้วมืออยู่ที่ปุ่มเปิด/ปิด ซึ่งเป็นปุ่มแบนข้างปุ่มนูนที่ใช้ปรับระดับเสียงตรงบริเวณขอบของโทรศัพท์"</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"ปลดล็อกโทรศัพท์เพื่อดูตัวเลือกเพิ่มเติม"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"ปลดล็อกแท็บเล็ตเพื่อดูตัวเลือกเพิ่มเติม"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"ปลดล็อกอุปกรณ์เพื่อดูตัวเลือกเพิ่มเติม"</string>
diff --git a/packages/SystemUI/res-product/values-tl/strings.xml b/packages/SystemUI/res-product/values-tl/strings.xml
index cfc6df4..353afd0 100644
--- a/packages/SystemUI/res-product/values-tl/strings.xml
+++ b/packages/SystemUI/res-product/values-tl/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"<xliff:g id="NUMBER">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang telepono gamit ang maling password. Aalisin ang profile sa trabaho, na magiging dahilan para ma-delete ang lahat ng data sa profile."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"<xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses kang nagkamali sa pagguhit ng iyong pattern sa pag-unlock. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, hihilingin sa iyong i-unlock ang tablet mo gamit ang isang email account.\n\n Subukan ulit sa loob ng <xliff:g id="NUMBER_2">%3$d</xliff:g> (na) segundo."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"<xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses kang nagkamali sa pagguhit ng iyong pattern sa pag-unlock. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, hihilingin sa iyong i-unlock ang telepono mo gamit ang isang email account.\n\n Subukan ulit sa loob ng <xliff:g id="NUMBER_2">%3$d</xliff:g> (na) segundo."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Nasa power button ang sensor para sa fingerprint. Ito ang flat na button sa tabi ng nakaangat na button ng volume sa gilid ng tablet."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Nasa power button ang sensor para sa fingerprint. Ito ang flat na button sa tabi ng nakaangat na button ng volume sa gilid ng device."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Nasa power button ang sensor para sa fingerprint. Ito ang flat na button sa tabi ng nakaangat na button ng volume sa gilid ng telepono."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"I-unlock ang iyong telepono para sa higit pang opsyon"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"I-unlock ang iyong tablet para sa higit pang opsyon"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"I-unlock ang iyong device para sa higit pang opsyon"</string>
diff --git a/packages/SystemUI/res-product/values-tr/strings.xml b/packages/SystemUI/res-product/values-tr/strings.xml
index fedd3c8..bd4ddad 100644
--- a/packages/SystemUI/res-product/values-tr/strings.xml
+++ b/packages/SystemUI/res-product/values-tr/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Telefonun kilidini <xliff:g id="NUMBER">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. İş profili kaldırılacak ve tüm profil verileri silinecektir."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%1$d</xliff:g> kez hatalı çizdiniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız deneme daha yaparsanız tabletinizin kilidini bir e-posta hesabı kullanarak açmanız istenir.\n<xliff:g id="NUMBER_2">%3$d</xliff:g>\n saniye içinde tekrar deneyin."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%1$d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız deneme daha yaparsanız telefonunuzu bir e-posta hesabı kullanarak açmanız istenir.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniye içinde tekrar deneyin."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Parmak izi sensörü güç düğmesinin üzerindedir. Bu sensör, tabletin kenarındaki standart ses düğmesinin yanında bulunan düz düğmedir."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Parmak izi sensörü güç düğmesinin üzerindedir. Bu sensör, cihazın kenarındaki standart ses düğmesinin yanında bulunan düz düğmedir."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Parmak izi sensörü güç düğmesinin üzerindedir. Bu sensör, telefonun kenarındaki standart ses düğmesinin yanında bulunan düz düğmedir."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Diğer seçenekler için telefonunuzun kilidini açın"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Diğer seçenekler için tabletinizin kilidini açın"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Diğer seçenekler için cihazınızın kilidini açın"</string>
diff --git a/packages/SystemUI/res-product/values-uk/strings.xml b/packages/SystemUI/res-product/values-uk/strings.xml
index 4f5fc9c..1e14b73 100644
--- a/packages/SystemUI/res-product/values-uk/strings.xml
+++ b/packages/SystemUI/res-product/values-uk/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Кількість невдалих спроб розблокувати телефон: <xliff:g id="NUMBER">%d</xliff:g>. Буде видалено робочий профіль і всі його дані."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Залишилося спроб: <xliff:g id="NUMBER_1">%2$d</xliff:g>. У разі невдачі з\'явиться запит розблокувати планшет за допомогою облікового запису електронної пошти.\n\n Повторіть спробу за <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Залишилося спроб: <xliff:g id="NUMBER_1">%2$d</xliff:g>. У разі невдачі з\'явиться запит розблокувати телефон за допомогою облікового запису електронної пошти.\n\n Повторіть спробу за <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Сканер відбитків пальців розташовано на кнопці живлення. Це плоска кнопка поруч із випуклою кнопкою гучності на бічній крайці планшета."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Сканер відбитків пальців розташовано на кнопці живлення. Це плоска кнопка поруч із випуклою кнопкою гучності на бічній крайці пристрою."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Сканер відбитків пальців розташовано на кнопці живлення. Це плоска кнопка поруч із випуклою кнопкою гучності на бічній крайці телефона."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Розблокуйте телефон, щоб переглянути інші параметри"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Розблокуйте планшет, щоб переглянути інші параметри"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Розблокуйте пристрій, щоб переглянути інші параметри"</string>
diff --git a/packages/SystemUI/res-product/values-ur/strings.xml b/packages/SystemUI/res-product/values-ur/strings.xml
index ee55538..1fc9338 100644
--- a/packages/SystemUI/res-product/values-ur/strings.xml
+++ b/packages/SystemUI/res-product/values-ur/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"آپ نے فون کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ دفتری پروفائل ہٹا دی جائے گی، جس سے پروفائل کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"آپ نے اپنا غیر مقفل کرنے کا پیٹرن <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے ڈرا کیا ہے۔ <xliff:g id="NUMBER_1">%2$d</xliff:g> مزید ناکام کوششوں کے بعد، آپ سے ایک ای میل اکاؤنٹ استعمال کر کے اپنا ٹیبلیٹ غیر مقفل کرنے کو کہا جائے گا۔\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"آپ نے اپنا غیر مقفل کرنے کا پیٹرن <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے ڈرا کیا ہے۔ <xliff:g id="NUMBER_1">%2$d</xliff:g> مزید ناکام کوششوں کے بعد، آپ سے ایک ای میل اکاؤنٹ استعمال کر کے اپنا فون غیر مقفل کرنے کو کہا جائے گا۔\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"فنگر پرنٹ سینسر پاور بٹن پر موجود ہے۔ یہ ٹیبلیٹ کے کنارے پر ابھرے ہوئے والیوم بٹن کے آگے والا ہموار بٹن ہے۔"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"فنگر پرنٹ سینسر پاور بٹن پر موجود ہے۔ یہ آلے کے کنارے پر ابھرے ہوئے والیوم بٹن کے آگے والا ہموار بٹن ہے۔"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"فنگر پرنٹ سینسر پاور بٹن پر موجود ہے۔ یہ فون کے کنارے پر ابھرے ہوئے والیوم بٹن کے آگے والا ہموار بٹن ہے۔"</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"مزید اختیارات کے لیے اپنا فون غیر مقفل کریں"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"مزید اختیارات کے لیے اپنا ٹیبلیٹ غیر مقفل کریں"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"مزید اختیارات کے لیے اپنا آلہ غیر مقفل کریں"</string>
diff --git a/packages/SystemUI/res-product/values-uz/strings.xml b/packages/SystemUI/res-product/values-uz/strings.xml
index 58309ff..4ab996a 100644
--- a/packages/SystemUI/res-product/values-uz/strings.xml
+++ b/packages/SystemUI/res-product/values-uz/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER">%d</xliff:g> marta xato urinish qildingiz. Endi ish profili oʻchirib tashlanadi va undagi barcha maʼlumotlar ham oʻchib ketadi."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Grafik kalit <xliff:g id="NUMBER_0">%1$d</xliff:g> marta xato chizildi. <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinishdan keyin sizdan emailingizdan foydalanib, planshet qulfini ochishingiz soʻraladi.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> soniyadan keyin yana urinib koʻring."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Grafik kalit <xliff:g id="NUMBER_0">%1$d</xliff:g> marta xato chizildi. <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinishdan keyin sizdan emailngizdan foydalanib, telefon qulfini ochishingiz soʻraladi.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> soniyadan keyin qayta urinib koʻring."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Barmoq izi sensori quvvat tugmasida joylashgan. U tekis tugma planshetning yon chekkasida tovush balandligi tugmasining yonida joylashgan."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Barmoq izi sensori quvvat tugmasida joylashgan. U tekis tugma qurilmaning yon chekkasida tovush balandligi tugmasining yonida joylashgan."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Barmoq izi sensori quvvat tugmasida joylashgan. U tekis tugma telefonning yon chekkasida tovush balandligi tugmasining yonida joylashgan."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Boshqa parametrlar uchun telefoningiz qulfini oching"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Boshqa parametrlar uchun planshetingiz qulfini oching"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Boshqa parametrlar uchun qurilmangiz qulfini oching"</string>
diff --git a/packages/SystemUI/res-product/values-vi/strings.xml b/packages/SystemUI/res-product/values-vi/strings.xml
index e4ecfc1..bd2af86 100644
--- a/packages/SystemUI/res-product/values-vi/strings.xml
+++ b/packages/SystemUI/res-product/values-vi/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Bạn đã mở khóa điện thoại sai <xliff:g id="NUMBER">%d</xliff:g> lần. Hồ sơ công việc sẽ bị xóa, tức là tất cả dữ liệu hồ sơ sẽ bị xóa."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Bạn đã vẽ không chính xác hình mở khóa <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa máy tính bảng bằng tài khoản email.\n\n Hãy thử lại sau <xliff:g id="NUMBER_2">%3$d</xliff:g> giây."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Bạn đã vẽ không chính xác hình mở khóa <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa điện thoại bằng tài khoản email.\n\n Hãy thử lại sau <xliff:g id="NUMBER_2">%3$d</xliff:g> giây."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Cảm biến vân tay nằm trên nút nguồn. Đó là nút phẳng cạnh nút âm lượng nhô lên trên cạnh của máy tính bảng."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Cảm biến vân tay nằm trên nút nguồn. Đó là nút phẳng cạnh nút âm lượng nhô lên trên cạnh của thiết bị."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Cảm biến vân tay nằm trên nút nguồn. Đó là nút phẳng cạnh nút âm lượng nhô lên trên cạnh của điện thoại."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Mở khóa điện thoại của bạn để xem thêm tùy chọn"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Mở khóa máy tính bảng của bạn để xem thêm tùy chọn"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Mở khóa thiết bị của bạn để xem thêm tùy chọn"</string>
diff --git a/packages/SystemUI/res-product/values-zh-rCN/strings.xml b/packages/SystemUI/res-product/values-zh-rCN/strings.xml
index 2813efd..c30da8c 100644
--- a/packages/SystemUI/res-product/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res-product/values-zh-rCN/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"您尝试解锁手机后失败的次数已达 <xliff:g id="NUMBER">%d</xliff:g> 次。系统将移除此工作资料,而这将删除所有的工作资料数据。"</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"您已 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次画错解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐号解锁平板电脑。\n\n请在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒后重试。"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"您已 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次画错解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐号解锁手机。\n\n请在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒后重试。"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"指纹传感器在电源按钮上。电源按钮是一个扁平按钮,位于平板电脑边缘凸起的音量按钮旁边。"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"指纹传感器在电源按钮上。电源按钮是一个扁平按钮,位于设备边缘凸起的音量按钮旁边。"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"指纹传感器在电源按钮上。电源按钮是一个扁平按钮,位于手机边缘凸起的音量按钮旁边。"</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"解锁手机即可查看更多选项"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"解锁平板电脑即可查看更多选项"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"解锁设备即可查看更多选项"</string>
diff --git a/packages/SystemUI/res-product/values-zh-rHK/strings.xml b/packages/SystemUI/res-product/values-zh-rHK/strings.xml
index ba07d92..3904e3c 100644
--- a/packages/SystemUI/res-product/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res-product/values-zh-rHK/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"您嘗試解鎖手機已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。系統將移除此工作設定檔,而所有設定檔資料亦會一併刪除。"</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果之後再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統會要求您透過電郵帳戶解鎖平板電腦。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果之後再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統會要求您透過電郵帳戶解鎖手機。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"指紋感應器位於開關按鈕上,開關按鈕形狀扁平,位於平板電腦邊緣凸起的音量按鈕旁。"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"指紋感應器位於開關按鈕上,開關按鈕形狀扁平,位於裝置邊緣凸起的音量按鈕旁。"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"指紋感應器位於開關按鈕上,開關按鈕形狀扁平,位於手機邊緣凸起的音量按鈕旁。"</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"解鎖手機以存取更多選項"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"解鎖平板電腦以存取更多選項"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"解鎖裝置以存取更多選項"</string>
diff --git a/packages/SystemUI/res-product/values-zh-rTW/strings.xml b/packages/SystemUI/res-product/values-zh-rTW/strings.xml
index 736824c..520de89 100644
--- a/packages/SystemUI/res-product/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res-product/values-zh-rTW/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"你嘗試解鎖手機已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。你的工作資料夾將遭到移除,所有設定檔資料也會一併遭到刪除。"</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"你的解鎖圖案已畫錯 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次機會。如果失敗次數超過限制,系統會要求你透過電子郵件帳戶將平板電腦解鎖。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"你的解鎖圖案已畫錯 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次機會。如果失敗次數超過限制,系統會要求你透過電子郵件帳戶將手機解鎖。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"指紋感應器在電源鍵上。電源鍵的形狀是扁平的,位在平板電腦側邊凸起的音量按鈕旁。"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"指紋感應器在電源鍵上。電源鍵的形狀是扁平的,位在裝置側邊凸起的音量按鈕旁。"</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"指紋感應器在電源鍵上。電源鍵的形狀是扁平的,位在手機側邊凸起的音量按鈕旁。"</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"解鎖手機可查看更多選項"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"解鎖平板電腦可查看更多選項"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"解鎖裝置可查看更多選項"</string>
diff --git a/packages/SystemUI/res-product/values-zu/strings.xml b/packages/SystemUI/res-product/values-zu/strings.xml
index dae4b22..2c60e54 100644
--- a/packages/SystemUI/res-product/values-zu/strings.xml
+++ b/packages/SystemUI/res-product/values-zu/strings.xml
@@ -40,6 +40,9 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Uzame ngokungalungile ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER">%d</xliff:g>. Iphrofayela yomsebenzi izosuswa, okuzosusa yonke idatha yephrofayela."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Udwebe ngokungalungile iphethini yakho yokuvula ngezikhathi ezingu-<xliff:g id="NUMBER_0">%1$d</xliff:g>. Ngemuva kwemizamo engaphumelelanga kaningi engu-<xliff:g id="NUMBER_1">%2$d</xliff:g>, uzocelwa ukuthi uvule ithebulethi yakho usebenzisa i-akhawunti ye-imeyili.\n\nZama futhi kumasekhondi angu-<xliff:g id="NUMBER_2">%3$d</xliff:g>."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Ukulayisha ungenisa iphathini yakho yokuvula ngendlela engalungile izikhathi ezi-<xliff:g id="NUMBER_0">%1$d</xliff:g> Emva kweminye imizamo engu-<xliff:g id="NUMBER_1">%2$d</xliff:g>, uzocelwa ukuvula ifoni yakho usebenzisa ukungena ngemvume ku-Google\n\n Zame futhi emumva kwengu- <xliff:g id="NUMBER_2">%3$d</xliff:g> imizuzwana."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Inzwa yesigxivizo somunwe esenkinobhweni yamandla. Inkinobho eyisicaba eduze kwenkinobho yevolumu ephakanyisiwe emaphethelweni wethebulethi."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Inzwa yesigxivizo somunwe esenkinobhweni yamandla. Inkinobho eyisicaba eduze kwenkinobho yevolumu ephakanyisiwe emaphethelweni edivayisi."</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Inzwa yesigxivizo somunwe esenkinobhweni yamandla. Inkinobho eyisicaba eduze kwenkinobho yevolumu ephakanyisiwe emaphethelweni efoni."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Vula ifoni yakho ukuthola okunye okungakhethwa"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Vula ithebulethi yakho ukuthola okunye okungakhethwa"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Vula idivayisi yakho ukuthola okunye okungakhethwa"</string>
diff --git a/packages/SystemUI/res-product/values/strings.xml b/packages/SystemUI/res-product/values/strings.xml
index 87b206c..dc6880b 100644
--- a/packages/SystemUI/res-product/values/strings.xml
+++ b/packages/SystemUI/res-product/values/strings.xml
@@ -123,11 +123,11 @@
     </string>
 
     <!-- Content description of the fingerprint icon when the system-provided fingerprint dialog is showing, to locate the sensor (tablet) for accessibility (not shown on the screen). [CHAR LIMIT=NONE]-->
-    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the tablet.\n\nPressing the power button turns off the screen.</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the tablet.</string>
     <!-- Content description of the fingerprint icon when the system-provided fingerprint dialog is showing, to locate the sensor (device) for accessibility (not shown on the screen). [CHAR LIMIT=NONE]-->
-    <string name="security_settings_sfps_enroll_find_sensor_message" product="device">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the device.\n\nPressing the power button turns off the screen.</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="device">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the device.</string>
     <!-- Content description of the fingerprint icon when the system-provided fingerprint dialog is showing, to locate the sensor (default) for accessibility (not shown on the screen). [CHAR LIMIT=NONE]-->
-    <string name="security_settings_sfps_enroll_find_sensor_message" product="default">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the phone.\n\nPressing the power button turns off the screen.</string>
+    <string name="security_settings_sfps_enroll_find_sensor_message" product="default">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the phone.</string>
 
     <!-- Text shown when viewing global actions while phone is locked and additional controls are hidden [CHAR LIMIT=NONE] -->
     <string name="global_action_lock_message" product="default">Unlock your phone for more options</string>
diff --git a/packages/SystemUI/res/drawable/media_ttt_chip_background.xml b/packages/SystemUI/res/drawable/chipbar_background.xml
similarity index 92%
rename from packages/SystemUI/res/drawable/media_ttt_chip_background.xml
rename to packages/SystemUI/res/drawable/chipbar_background.xml
index 3abf4d7..5722177 100644
--- a/packages/SystemUI/res/drawable/media_ttt_chip_background.xml
+++ b/packages/SystemUI/res/drawable/chipbar_background.xml
@@ -17,6 +17,6 @@
 <shape
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
-    <solid android:color="?androidprv:attr/colorSurface" />
+    <solid android:color="?androidprv:attr/colorAccentSecondary" />
     <corners android:radius="32dp" />
 </shape>
diff --git a/packages/SystemUI/res/drawable/media_ttt_undo_background.xml b/packages/SystemUI/res/drawable/chipbar_end_button_background.xml
similarity index 93%
rename from packages/SystemUI/res/drawable/media_ttt_undo_background.xml
rename to packages/SystemUI/res/drawable/chipbar_end_button_background.xml
index 3e2e4f0..80c7207 100644
--- a/packages/SystemUI/res/drawable/media_ttt_undo_background.xml
+++ b/packages/SystemUI/res/drawable/chipbar_end_button_background.xml
@@ -20,7 +20,7 @@
     android:color="?android:textColorPrimary">
     <item android:id="@android:id/background">
         <shape>
-            <solid android:color="?androidprv:attr/colorAccentPrimary"/>
+            <solid android:color="@android:color/system_accent1_200"/>
             <corners android:radius="24dp" />
         </shape>
     </item>
diff --git a/packages/SystemUI/res/drawable/dream_overlay_bottom_affordance_bg.xml b/packages/SystemUI/res/drawable/dream_overlay_bottom_affordance_bg.xml
new file mode 100644
index 0000000..3b67ddd
--- /dev/null
+++ b/packages/SystemUI/res/drawable/dream_overlay_bottom_affordance_bg.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* Copyright 2023, The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+-->
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    android:shape="rectangle">
+  <solid android:color="?androidprv:attr/colorSurface"/>
+  <size
+      android:width="@dimen/dream_overlay_bottom_affordance_height"
+      android:height="@dimen/dream_overlay_bottom_affordance_width"/>
+  <corners android:radius="@dimen/dream_overlay_bottom_affordance_radius" />
+</shape>
diff --git a/packages/SystemUI/res/drawable/ic_keyboard_backlight.xml b/packages/SystemUI/res/drawable/ic_keyboard_backlight.xml
new file mode 100644
index 0000000..d123caf
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_keyboard_backlight.xml
@@ -0,0 +1,12 @@
+<vector android:height="11dp" android:viewportHeight="12"
+    android:viewportWidth="22" android:width="20.166666dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <group>
+        <clip-path android:pathData="M0,0.5h22v11h-22z"/>
+        <path android:fillColor="#231F20" android:pathData="M6.397,9.908H0V11.5H6.397V9.908Z"/>
+        <path android:fillColor="#231F20" android:pathData="M14.199,9.908H7.801V11.5H14.199V9.908Z"/>
+        <path android:fillColor="#231F20" android:pathData="M11.858,0.5H10.142V6.434H11.858V0.5Z"/>
+        <path android:fillColor="#231F20" android:pathData="M8.348,7.129L3.885,2.975L3.823,2.932L2.668,4.003L2.621,4.046L7.084,8.2L7.146,8.243L8.301,7.172L8.348,7.129Z"/>
+        <path android:fillColor="#231F20" android:pathData="M18.224,2.975L18.177,2.932L13.653,7.129L14.807,8.2L14.854,8.243L19.379,4.046L18.224,2.975Z"/>
+        <path android:fillColor="#231F20" android:pathData="M22,9.908H15.603V11.5H22V9.908Z"/>
+    </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_back.xml b/packages/SystemUI/res/drawable/ic_sysbar_back.xml
index ee40262..6c34655 100644
--- a/packages/SystemUI/res/drawable/ic_sysbar_back.xml
+++ b/packages/SystemUI/res/drawable/ic_sysbar_back.xml
@@ -15,13 +15,13 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="28dp"
-    android:height="28dp"
+    android:width="20dp"
+    android:height="20dp"
     android:autoMirrored="true"
-    android:viewportWidth="28"
-    android:viewportHeight="28">
+    android:viewportWidth="20"
+    android:viewportHeight="20">
 
     <path
         android:fillColor="?attr/singleToneColor"
-        android:pathData="M6.49,14.86c-0.66-0.39-0.66-1.34,0-1.73l6.02-3.53l5.89-3.46C19.11,5.73,20,6.26,20,7.1V14v6.9 c0,0.84-0.89,1.37-1.6,0.95l-5.89-3.46L6.49,14.86z" />
+        android:pathData="M15.5417 1.66669C15.1833 1.66669 14.8417 1.76669 14.5333 1.94169L3.21667 8.74169C2.775 9.00002 2.5 9.48335 2.5 10C2.5 10.5167 2.775 11 3.21667 11.2584L14.5333 18.05C14.8417 18.2334 15.1833 18.325 15.5417 18.325C16.625 18.325 17.5 17.45 17.5 16.3667V3.62502C17.5 2.54169 16.625 1.66669 15.5417 1.66669Z" />
 </vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_home.xml b/packages/SystemUI/res/drawable/ic_sysbar_home.xml
index da23937..8b2a58a 100644
--- a/packages/SystemUI/res/drawable/ic_sysbar_home.xml
+++ b/packages/SystemUI/res/drawable/ic_sysbar_home.xml
@@ -15,12 +15,12 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="28dp"
-    android:height="28dp"
-    android:viewportWidth="28"
-    android:viewportHeight="28">
+    android:width="20dp"
+    android:height="20dp"
+    android:viewportWidth="20"
+    android:viewportHeight="20">
 
     <path
         android:fillColor="?attr/singleToneColor"
-        android:pathData="M 14 7 C 17.8659932488 7 21 10.1340067512 21 14 C 21 17.8659932488 17.8659932488 21 14 21 C 10.1340067512 21 7 17.8659932488 7 14 C 7 10.1340067512 10.1340067512 7 14 7 Z" />
+        android:pathData="M10.0001 18.3334C5.40008 18.3334 1.66675 14.6 1.66675 10C1.66675 5.40002 5.40008 1.66669 10.0001 1.66669C14.6001 1.66669 18.3334 5.40002 18.3334 10C18.3334 14.6 14.6001 18.3334 10.0001 18.3334Z" />
 </vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_recent.xml b/packages/SystemUI/res/drawable/ic_sysbar_recent.xml
index 6b038d1..6ff3ec3 100644
--- a/packages/SystemUI/res/drawable/ic_sysbar_recent.xml
+++ b/packages/SystemUI/res/drawable/ic_sysbar_recent.xml
@@ -15,12 +15,12 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="28dp"
-    android:height="28dp"
-    android:viewportWidth="28"
-    android:viewportHeight="28">
+    android:width="20dp"
+    android:height="20dp"
+    android:viewportWidth="20"
+    android:viewportHeight="20">
 
     <path
         android:fillColor="?attr/singleToneColor"
-        android:pathData="M19.9,21.5H8.1c-0.88,0-1.6-0.72-1.6-1.6V8.1c0-0.88,0.72-1.6,1.6-1.6h11.8c0.88,0,1.6,0.72,1.6,1.6v11.8 C21.5,20.78,20.78,21.5,19.9,21.5z" />
+        android:pathData="M4.47634 2.5H15.5241C16.6164 2.5 17.5002 3.38382 17.5002 4.4761V15.5239C17.5002 16.6162 16.6164 17.5 15.5241 17.5H4.47634C3.38407 17.5 2.50024 16.6162 2.50024 15.5239V4.4761C2.50024 3.38382 3.38407 2.5 4.47634 2.5Z" />
 </vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/qs_media_rec_scrim.xml b/packages/SystemUI/res/drawable/qs_media_rec_scrim.xml
new file mode 100644
index 0000000..de0a620
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_media_rec_scrim.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <!-- gradient from 25% in the center to 100% at edges -->
+    <gradient
+        android:type="radial"
+        android:gradientRadius="40%p"
+        android:startColor="#AE000000"
+        android:endColor="#00000000" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/activity_rear_display_education.xml b/packages/SystemUI/res/layout/activity_rear_display_education.xml
index 094807e..c295cfe 100644
--- a/packages/SystemUI/res/layout/activity_rear_display_education.xml
+++ b/packages/SystemUI/res/layout/activity_rear_display_education.xml
@@ -30,6 +30,7 @@
 
             <com.airbnb.lottie.LottieAnimationView
                 android:id="@+id/rear_display_folded_animation"
+                android:importantForAccessibility="no"
                 android:layout_width="@dimen/rear_display_animation_width"
                 android:layout_height="@dimen/rear_display_animation_height"
                 android:layout_gravity="center"
diff --git a/packages/SystemUI/res/layout/activity_rear_display_education_opened.xml b/packages/SystemUI/res/layout/activity_rear_display_education_opened.xml
index e970bc5..c12bfcc 100644
--- a/packages/SystemUI/res/layout/activity_rear_display_education_opened.xml
+++ b/packages/SystemUI/res/layout/activity_rear_display_education_opened.xml
@@ -31,6 +31,7 @@
 
         <com.airbnb.lottie.LottieAnimationView
             android:id="@+id/rear_display_folded_animation"
+            android:importantForAccessibility="no"
             android:layout_width="@dimen/rear_display_animation_width"
             android:layout_height="@dimen/rear_display_animation_height"
             android:layout_gravity="center"
diff --git a/packages/SystemUI/res/layout/chipbar.xml b/packages/SystemUI/res/layout/chipbar.xml
index 0ff944c..762dcdc 100644
--- a/packages/SystemUI/res/layout/chipbar.xml
+++ b/packages/SystemUI/res/layout/chipbar.xml
@@ -29,8 +29,8 @@
         android:orientation="horizontal"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:padding="@dimen/media_ttt_chip_outer_padding"
-        android:background="@drawable/media_ttt_chip_background"
+        android:padding="@dimen/chipbar_outer_padding"
+        android:background="@drawable/chipbar_background"
         android:layout_marginTop="20dp"
         android:layout_marginStart="@dimen/notification_side_paddings"
         android:layout_marginEnd="@dimen/notification_side_paddings"
@@ -43,8 +43,8 @@
 
         <com.android.internal.widget.CachingIconView
             android:id="@+id/start_icon"
-            android:layout_width="@dimen/media_ttt_app_icon_size"
-            android:layout_height="@dimen/media_ttt_app_icon_size"
+            android:layout_width="@dimen/chipbar_start_icon_size"
+            android:layout_height="@dimen/chipbar_start_icon_size"
             android:layout_marginEnd="12dp"
             android:alpha="0.0"
             />
@@ -54,47 +54,46 @@
             android:layout_width="0dp"
             android:layout_height="wrap_content"
             android:layout_weight="1"
-            android:textSize="@dimen/media_ttt_text_size"
-            android:textColor="?android:attr/textColorPrimary"
+            android:textSize="@dimen/chipbar_text_size"
+            android:textColor="@color/chipbar_text_and_icon_color"
             android:alpha="0.0"
             />
 
         <!-- At most one of [loading, failure_icon, undo] will be visible at a time. -->
         <ImageView
             android:id="@+id/loading"
-            android:layout_width="@dimen/media_ttt_status_icon_size"
-            android:layout_height="@dimen/media_ttt_status_icon_size"
-            android:layout_marginStart="@dimen/media_ttt_last_item_start_margin"
+            android:layout_width="@dimen/chipbar_end_icon_size"
+            android:layout_height="@dimen/chipbar_end_icon_size"
+            android:layout_marginStart="@dimen/chipbar_end_item_start_margin"
             android:src="@drawable/ic_progress_activity"
-            android:tint="?androidprv:attr/colorAccentPrimaryVariant"
+            android:tint="@android:color/system_accent2_700"
             android:alpha="0.0"
             />
 
         <ImageView
             android:id="@+id/error"
-            android:layout_width="@dimen/media_ttt_status_icon_size"
-            android:layout_height="@dimen/media_ttt_status_icon_size"
-            android:layout_marginStart="@dimen/media_ttt_last_item_start_margin"
+            android:layout_width="@dimen/chipbar_end_icon_size"
+            android:layout_height="@dimen/chipbar_end_icon_size"
+            android:layout_marginStart="@dimen/chipbar_end_item_start_margin"
             android:src="@drawable/ic_warning"
-            android:tint="@color/GM2_red_500"
+            android:tint="@color/GM2_red_600"
             android:alpha="0.0"
             />
 
-        <!-- TODO(b/245610654): Re-name all the media-specific dimens to chipbar dimens instead. -->
         <TextView
             android:id="@+id/end_button"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:textColor="?androidprv:attr/textColorOnAccent"
-            android:layout_marginStart="@dimen/media_ttt_last_item_start_margin"
-            android:textSize="@dimen/media_ttt_text_size"
-            android:paddingStart="@dimen/media_ttt_chip_outer_padding"
-            android:paddingEnd="@dimen/media_ttt_chip_outer_padding"
-            android:paddingTop="@dimen/media_ttt_undo_button_vertical_padding"
-            android:paddingBottom="@dimen/media_ttt_undo_button_vertical_padding"
-            android:layout_marginTop="@dimen/media_ttt_undo_button_vertical_negative_margin"
-            android:layout_marginBottom="@dimen/media_ttt_undo_button_vertical_negative_margin"
-            android:background="@drawable/media_ttt_undo_background"
+            android:layout_marginStart="@dimen/chipbar_end_item_start_margin"
+            android:textSize="@dimen/chipbar_text_size"
+            android:paddingStart="@dimen/chipbar_outer_padding"
+            android:paddingEnd="@dimen/chipbar_outer_padding"
+            android:paddingTop="@dimen/chipbar_end_button_vertical_padding"
+            android:paddingBottom="@dimen/chipbar_end_button_vertical_padding"
+            android:layout_marginTop="@dimen/chipbar_end_button_vertical_negative_margin"
+            android:layout_marginBottom="@dimen/chipbar_end_button_vertical_negative_margin"
+            android:background="@drawable/chipbar_end_button_background"
             android:alpha="0.0"
             />
 
diff --git a/packages/SystemUI/res/layout/dream_overlay_container.xml b/packages/SystemUI/res/layout/dream_overlay_container.xml
index 8e83b4a..ae0a937 100644
--- a/packages/SystemUI/res/layout/dream_overlay_container.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_container.xml
@@ -25,11 +25,12 @@
         android:id="@+id/dream_overlay_content"
         android:layout_width="match_parent"
         android:layout_height="0dp"
-        android:layout_marginTop="@dimen/dream_overlay_container_margin_top"
-        android:layout_marginEnd="@dimen/dream_overlay_container_margin_end"
-        android:layout_marginBottom="@dimen/dream_overlay_container_margin_bottom"
-        android:layout_marginStart="@dimen/dream_overlay_container_margin_start"
-
+        android:paddingTop="@dimen/dream_overlay_container_padding_top"
+        android:paddingEnd="@dimen/dream_overlay_container_padding_end"
+        android:paddingBottom="@dimen/dream_overlay_container_padding_bottom"
+        android:paddingStart="@dimen/dream_overlay_container_padding_start"
+        android:clipToPadding="false"
+        android:clipChildren="false"
         app:layout_constraintTop_toBottomOf="@id/dream_overlay_status_bar"
         app:layout_constraintBottom_toBottomOf="parent"
         />
diff --git a/packages/SystemUI/res/layout/dream_overlay_home_controls_chip.xml b/packages/SystemUI/res/layout/dream_overlay_home_controls_chip.xml
index fb78b49..0cd0623 100644
--- a/packages/SystemUI/res/layout/dream_overlay_home_controls_chip.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_home_controls_chip.xml
@@ -14,21 +14,15 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
 -->
-<FrameLayout
+<com.android.systemui.animation.view.LaunchableImageView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_height="wrap_content"
-    android:layout_width="wrap_content"
-    android:paddingVertical="@dimen/dream_overlay_complication_home_controls_padding">
-
-    <com.android.systemui.animation.view.LaunchableImageView
-        android:id="@+id/home_controls_chip"
-        android:layout_height="@dimen/keyguard_affordance_fixed_height"
-        android:layout_width="@dimen/keyguard_affordance_fixed_width"
-        android:layout_gravity="bottom|start"
-        android:scaleType="center"
-        android:tint="?android:attr/textColorPrimary"
-        android:src="@drawable/controls_icon"
-        android:background="@drawable/keyguard_bottom_affordance_bg"
-        android:contentDescription="@string/quick_controls_title" />
-
-</FrameLayout>
+    android:id="@+id/home_controls_chip"
+    android:layout_height="@dimen/dream_overlay_bottom_affordance_height"
+    android:layout_width="@dimen/dream_overlay_bottom_affordance_width"
+    android:layout_gravity="bottom|start"
+    android:padding="@dimen/dream_overlay_bottom_affordance_padding"
+    android:background="@drawable/dream_overlay_bottom_affordance_bg"
+    android:scaleType="fitCenter"
+    android:tint="?android:attr/textColorPrimary"
+    android:src="@drawable/controls_icon"
+    android:contentDescription="@string/quick_controls_title" />
diff --git a/packages/SystemUI/res/layout/dream_overlay_media_entry_chip.xml b/packages/SystemUI/res/layout/dream_overlay_media_entry_chip.xml
index 50f3ffc..b75c638 100644
--- a/packages/SystemUI/res/layout/dream_overlay_media_entry_chip.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_media_entry_chip.xml
@@ -17,13 +17,12 @@
 <ImageView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/media_entry_chip"
-    android:layout_height="@dimen/keyguard_affordance_fixed_height"
-    android:layout_width="@dimen/keyguard_affordance_fixed_width"
+    android:layout_height="@dimen/dream_overlay_bottom_affordance_height"
+    android:layout_width="@dimen/dream_overlay_bottom_affordance_width"
     android:layout_gravity="bottom|start"
-    android:scaleType="center"
+    android:scaleType="fitCenter"
+    android:padding="@dimen/dream_overlay_bottom_affordance_padding"
     android:tint="?android:attr/textColorPrimary"
     android:src="@drawable/ic_music_note"
-    android:background="@drawable/keyguard_bottom_affordance_bg"
-    android:layout_marginStart="@dimen/keyguard_affordance_horizontal_offset"
-    android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
+    android:background="@drawable/dream_overlay_bottom_affordance_bg"
     android:contentDescription="@string/controls_media_title" />
diff --git a/packages/SystemUI/res/layout/media_recommendation_view.xml b/packages/SystemUI/res/layout/media_recommendation_view.xml
index c54c4e4..e63aa21 100644
--- a/packages/SystemUI/res/layout/media_recommendation_view.xml
+++ b/packages/SystemUI/res/layout/media_recommendation_view.xml
@@ -22,16 +22,19 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:translationZ="0dp"
-        android:scaleType="centerCrop"
+        android:scaleType="matrix"
         android:adjustViewBounds="true"
         android:clipToOutline="true"
+        android:layerType="hardware"
         android:background="@drawable/bg_smartspace_media_item"/>
 
     <!-- App icon -->
     <com.android.internal.widget.CachingIconView
         android:id="@+id/media_rec_app_icon"
-        android:layout_width="@dimen/qs_media_rec_icon_top_margin"
-        android:layout_height="@dimen/qs_media_rec_icon_top_margin"
+        android:layout_width="@dimen/qs_media_rec_album_icon_size"
+        android:layout_height="@dimen/qs_media_rec_album_icon_size"
+        android:minWidth="@dimen/qs_media_rec_album_icon_size"
+        android:minHeight="@dimen/qs_media_rec_album_icon_size"
         android:layout_marginStart="@dimen/qs_media_info_spacing"
         android:layout_marginTop="@dimen/qs_media_info_spacing"/>
 
diff --git a/packages/SystemUI/res/layout/media_smartspace_recommendations.xml b/packages/SystemUI/res/layout/media_smartspace_recommendations.xml
index aa655e6..9304ff7 100644
--- a/packages/SystemUI/res/layout/media_smartspace_recommendations.xml
+++ b/packages/SystemUI/res/layout/media_smartspace_recommendations.xml
@@ -40,6 +40,8 @@
         android:id="@+id/recommendation_card_icon"
         android:layout_width="@dimen/qs_media_app_icon_size"
         android:layout_height="@dimen/qs_media_app_icon_size"
+        android:minWidth="@dimen/qs_media_app_icon_size"
+        android:minHeight="@dimen/qs_media_app_icon_size"
         android:layout_marginStart="@dimen/qs_media_padding"
         android:layout_marginTop="@dimen/qs_media_rec_icon_top_margin"
         app:layout_constraintStart_toStartOf="parent"
@@ -53,6 +55,8 @@
             android:id="@+id/media_cover1"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
+            android:minWidth="@dimen/qs_media_rec_album_size"
+            android:minHeight="@dimen/qs_media_rec_album_size"
             app:layout_constraintTop_toTopOf="parent"
             app:layout_constraintBottom_toBottomOf="parent"
             android:adjustViewBounds="true"
@@ -80,6 +84,8 @@
             android:id="@+id/media_cover2"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
+            android:minWidth="@dimen/qs_media_rec_album_size"
+            android:minHeight="@dimen/qs_media_rec_album_size"
             android:adjustViewBounds="true"
             android:background="@drawable/bg_smartspace_media_item"
             style="@style/MediaPlayer.Recommendation.Album"
@@ -105,6 +111,8 @@
             android:id="@+id/media_cover3"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
+            android:minWidth="@dimen/qs_media_rec_album_size"
+            android:minHeight="@dimen/qs_media_rec_album_size"
             android:adjustViewBounds="true"
             android:background="@drawable/bg_smartspace_media_item"
             style="@style/MediaPlayer.Recommendation.Album"
diff --git a/packages/SystemUI/res/layout/status_bar_user_chip_container.xml b/packages/SystemUI/res/layout/status_bar_user_chip_container.xml
index b374074..80f5d87 100644
--- a/packages/SystemUI/res/layout/status_bar_user_chip_container.xml
+++ b/packages/SystemUI/res/layout/status_bar_user_chip_container.xml
@@ -24,7 +24,7 @@
     android:orientation="horizontal"
     android:layout_marginEnd="@dimen/status_bar_user_chip_end_margin"
     android:background="@drawable/status_bar_user_chip_bg"
-    android:visibility="visible" >
+    android:visibility="gone" >
     <ImageView android:id="@+id/current_user_avatar"
         android:layout_width="@dimen/status_bar_user_chip_avatar_size"
         android:layout_height="@dimen/status_bar_user_chip_avatar_size"
diff --git a/packages/SystemUI/res/raw/biometricprompt_rear_landscape_base.json b/packages/SystemUI/res/raw/biometricprompt_rear_landscape_base.json
deleted file mode 100644
index 49c1c40..0000000
--- a/packages/SystemUI/res/raw/biometricprompt_rear_landscape_base.json
+++ /dev/null
@@ -1 +0,0 @@
-{"v":"5.8.1","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"BiometricPrompt_Rear_Landscape_Base_Foldable","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 18","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[169.478,169.749,0],"ix":2,"l":2},"a":{"a":0,"k":[-48.123,-30.19,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".grey400","cl":"grey400","parent":13,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.741176486015,0.75686275959,0.776470601559,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"black circle matte","parent":13,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".grey904","cl":"grey904","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-62.577,35.536,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-2.552,0.087],[0,0]],"o":[[0,0],[0,-3.287],[0,0],[0,0]],"v":[[-2.301,8.869],[-2.301,-3.772],[2.301,-9.806],[2.301,9.806]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960813999,0.525490224361,0.54509806633,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"black circle matte 2","parent":13,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".blue401","cl":"blue401","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-62.577,-27.655,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,3.286],[0,0],[-2.552,0.086],[0,0]],"o":[[0,0],[0,-3.286],[0,0],[-2.552,-0.086]],"v":[[-2.301,16.282],[-2.301,-16.281],[2.301,-22.313],[2.301,22.313]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"black circle matte 3","parent":13,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Finger 2","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-129,"s":[-67]},{"t":-29,"s":[0]}],"ix":10},"p":{"a":0,"k":[-75.352,41.307,0],"ix":2,"l":2},"a":{"a":0,"k":[94.648,211.307,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[6.72,-5.642],[0,0],[-9.394,-0.562],[-0.298,-0.038]],"o":[[-5.153,4.329],[3.882,-16.05],[0.31,0.019],[-0.044,0.75]],"v":[[0.863,12.222],[-8.931,14.755],[8.005,-15.108],[8.931,-15.021]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.792156875134,0.454901963472,0.376470595598,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[81.486,130.081],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 9","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.459,6.045],[-5.153,4.329],[-0.044,0.75],[3.116,-24.664],[5.23,-22.052],[8.666,11.92],[-2.9,9.135]],"o":[[0,0],[6.72,-5.642],[12.723,1.335],[-2.369,18.762],[-13.993,-5.333],[2.255,-5.502],[1.843,-5.815]],"v":[[-9.99,-18.348],[-0.196,-20.881],[7.872,-48.124],[21.578,-9.331],[12.104,48.124],[-22.574,21.555],[-14.791,-0.206]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.713725507259,0.384313732386,0.282352954149,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[82.545,163.184],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 8","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"black circle matte 4","parent":13,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".grey903","cl":"grey903","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-18.345,-92.442,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[24.07,0],[0,0],[-8.27,0],[0,0]],"o":[[0,0],[0,8.269],[0,0],[-14.024,-17.379]],"v":[[-29.778,-14.252],[-29.778,-0.721],[-14.805,14.252],[29.778,14.252]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.372549027205,0.388235300779,0.407843142748,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"black circle matte 5","parent":13,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".grey902","cl":"grey902","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-15.947,-30.19,0],"ix":2,"l":2},"a":{"a":0,"k":[154.053,139.81,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[2.3,0.367],[0,0],[-2.364,0.157],[0,0]],"o":[[0,0],[2.3,-0.367],[0,0],[-2.364,-0.157]],"v":[[-3.5,75.533],[-3.5,-75.533],[3.5,-76.312],[3.5,76.312]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960813999,0.525490224361,0.54509806633,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[113.225,139.81],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 7","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,8.269],[0,0],[2.181,-0.187],[0,0],[-2.23,0],[0,42.252],[10.593,13.127],[0,0]],"o":[[0,0],[-2.23,0],[0,0],[2.181,0.187],[42.252,0],[0,-18.182],[0,0],[-8.27,0]],"v":[[-34.946,-62.973],[-34.946,-76.504],[-41.558,-76.201],[-41.558,76.201],[-34.946,76.504],[41.558,0],[24.61,-48],[-19.973,-48]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960813999,0.525490224361,0.54509806633,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[156.824,139.81],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 5","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".black 2","cl":"black","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-48.123,-30.19,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2,0.833],"y":[1,1,1]},"o":{"x":[0.7,0.7,0.167],"y":[0,0,0]},"t":-129,"s":[0,0,100]},{"t":-79,"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":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".grey700","cl":"grey700","parent":15,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-56.481,-59.936,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[3.767,0],[0,0],[0,-3.767],[0,0],[-3.767,0],[0,0],[0,3.767],[0,0]],"o":[[0,0],[-3.767,0],[0,0],[0,3.767],[0,0],[3.767,0],[0,0],[0,-3.767]],"v":[[46.055,-14.479],[-46.056,-14.479],[-52.876,-7.659],[-52.876,7.658],[-46.056,14.479],[46.055,14.479],[52.876,7.658],[52.876,-7.659]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.372549027205,0.388235300779,0.407843142748,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":".grey901","cl":"grey901","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[16.485,2.727,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[4.184,0],[0,0],[0,0],[0,0],[0,-4.375]],"o":[[0,4.184],[0,0],[0,0],[0,0],[4.375,0],[0,0]],"v":[[114.116,92.129],[106.54,99.705],[7.788,99.705],[7.788,-99.704],[106.161,-99.704],[114.116,-91.749]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[5.707,0],[0,0],[1.894,-1.05],[0.886,0.346],[0,0],[2.166,0],[0,0],[0,-5.707],[0,0],[0,-1.46],[0,0],[-1.133,-0.038],[0,0],[0,-1.459],[0,0],[-1.133,-0.038],[0,0],[-5.708,0],[0,0],[-1.894,1.05],[-0.846,-0.289],[0,0],[-2.166,0],[0,0],[0,5.706],[0,0]],"o":[[0,0],[-2.166,0],[-0.883,0.354],[0,0],[-1.895,-1.05],[0,0],[-5.708,0],[0,0],[-1.133,0.038],[0,0],[0,1.46],[0,0],[-1.133,0.038],[0,0],[0,1.46],[0,0],[0,5.707],[0,0],[2.165,0],[0.833,-0.334],[0,0],[1.894,1.05],[0,0],[5.707,0],[0,0],[0,-5.707]],"v":[[106.16,-102.082],[8.455,-102.082],[2.265,-100.48],[-0.488,-100.468],[-0.519,-100.48],[-6.71,-102.082],[-104.116,-102.082],[-114.45,-91.748],[-114.45,-36.119],[-116.494,-33.44],[-116.494,-18.979],[-114.45,-16.3],[-114.45,-0.877],[-116.494,1.802],[-116.494,28.704],[-114.45,31.383],[-114.45,91.749],[-104.116,102.083],[-6.495,102.083],[-0.305,100.481],[2.294,100.425],[2.395,100.481],[9.872,102.083],[106.161,102.083],[116.494,91.75],[116.494,-91.748]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960813999,0.529411792755,0.54509806633,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_rear_portrait_base.json b/packages/SystemUI/res/raw/biometricprompt_rear_portrait_base.json
deleted file mode 100644
index 9ea0d35..0000000
--- a/packages/SystemUI/res/raw/biometricprompt_rear_portrait_base.json
+++ /dev/null
@@ -1 +0,0 @@
-{"v":"5.8.1","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"BiometricPrompt_Rear_Portrait_Base_Foldable","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 18","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[169.478,169.749,0],"ix":2,"l":2},"a":{"a":0,"k":[-48.123,-30.19,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".grey400","cl":"grey400","parent":14,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.741176486015,0.75686275959,0.776470601559,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"black circle matte","parent":14,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".grey904","cl":"grey904","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-62.577,35.536,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-2.552,0.087],[0,0]],"o":[[0,0],[0,-3.287],[0,0],[0,0]],"v":[[-2.301,8.869],[-2.301,-3.772],[2.301,-9.806],[2.301,9.806]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960813999,0.525490224361,0.54509806633,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"black circle matte 2","parent":14,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".blue401","cl":"blue401","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-62.577,-27.655,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,3.286],[0,0],[-2.552,0.086],[0,0]],"o":[[0,0],[0,-3.286],[0,0],[-2.552,-0.086]],"v":[[-2.301,16.282],[-2.301,-16.281],[2.301,-22.313],[2.301,22.313]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"black circle matte 3","parent":14,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Finger 3","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-2,"ix":10},"p":{"a":0,"k":[260.134,83.782,0],"ix":2,"l":2},"a":{"a":0,"k":[302.634,38.782,0],"ix":1,"l":2},"s":{"a":0,"k":[178,178,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.262,5.076],[0,0],[-0.424,-7.095],[-0.028,-0.225]],"o":[[3.269,-3.892],[-12.123,2.932],[0.015,0.234],[0.567,-0.034]],"v":[[9.232,0.652],[11.145,-6.746],[-11.412,6.046],[-11.346,6.746]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.792156875134,0.454901963472,0.376470595598,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[241.281,55.033],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 5","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[4.565,-1.102],[3.269,-3.892],[0.566,-0.033],[-18.63,2.353],[-16.656,3.951],[9.004,6.546],[6.9,-2.19]],"o":[[0,0],[-4.262,5.076],[1.008,9.61],[14.171,-1.79],[-4.028,-10.569],[-4.156,1.703],[-4.392,1.392]],"v":[[-13.858,-7.546],[-15.771,-0.148],[-36.349,5.946],[-7.047,16.299],[36.349,9.142],[16.281,-17.051],[-0.156,-11.172]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.713725507259,0.384313732386,0.282352954149,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[266.285,55.833],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 4","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"black circle matte 4","parent":14,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".grey903","cl":"grey903","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-18.345,-92.442,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[24.07,0],[0,0],[-8.27,0],[0,0]],"o":[[0,0],[0,8.269],[0,0],[-14.024,-17.379]],"v":[[-29.778,-14.252],[-29.778,-0.721],[-14.805,14.252],[29.778,14.252]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.372549027205,0.388235300779,0.407843142748,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"black circle matte 5","parent":14,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".grey902","cl":"grey902","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-15.947,-30.19,0],"ix":2,"l":2},"a":{"a":0,"k":[154.053,139.81,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[2.3,0.367],[0,0],[-2.364,0.157],[0,0]],"o":[[0,0],[2.3,-0.367],[0,0],[-2.364,-0.157]],"v":[[-3.5,75.533],[-3.5,-75.533],[3.5,-76.312],[3.5,76.312]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960813999,0.525490224361,0.54509806633,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[113.225,139.81],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 7","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,8.269],[0,0],[2.181,-0.187],[0,0],[-2.23,0],[0,42.252],[10.593,13.127],[0,0]],"o":[[0,0],[-2.23,0],[0,0],[2.181,0.187],[42.252,0],[0,-18.182],[0,0],[-8.27,0]],"v":[[-34.946,-62.973],[-34.946,-76.504],[-41.558,-76.201],[-41.558,76.201],[-34.946,76.504],[41.558,0],[24.61,-48],[-19.973,-48]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960813999,0.525490224361,0.54509806633,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[156.824,139.81],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 5","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".black 2","cl":"black","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-48.123,-30.19,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2,0.833],"y":[1,1,1]},"o":{"x":[0.7,0.7,0.167],"y":[0,0,0]},"t":-129,"s":[0,0,100]},{"t":-79,"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":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":".grey700","cl":"grey700","parent":16,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-56.481,-59.936,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[3.767,0],[0,0],[0,-3.767],[0,0],[-3.767,0],[0,0],[0,3.767],[0,0]],"o":[[0,0],[-3.767,0],[0,0],[0,3.767],[0,0],[3.767,0],[0,0],[0,-3.767]],"v":[[46.055,-14.479],[-46.056,-14.479],[-52.876,-7.659],[-52.876,7.658],[-46.056,14.479],[46.055,14.479],[52.876,7.658],[52.876,-7.659]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.372549027205,0.388235300779,0.407843142748,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":".grey901","cl":"grey901","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[16.485,2.727,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[4.184,0],[0,0],[0,0],[0,0],[0,-4.375]],"o":[[0,4.184],[0,0],[0,0],[0,0],[4.375,0],[0,0]],"v":[[114.116,92.129],[106.54,99.705],[7.788,99.705],[7.788,-99.704],[106.161,-99.704],[114.116,-91.749]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[5.707,0],[0,0],[1.894,-1.05],[0.886,0.346],[0,0],[2.166,0],[0,0],[0,-5.707],[0,0],[0,-1.46],[0,0],[-1.133,-0.038],[0,0],[0,-1.459],[0,0],[-1.133,-0.038],[0,0],[-5.708,0],[0,0],[-1.894,1.05],[-0.846,-0.289],[0,0],[-2.166,0],[0,0],[0,5.706],[0,0]],"o":[[0,0],[-2.166,0],[-0.883,0.354],[0,0],[-1.895,-1.05],[0,0],[-5.708,0],[0,0],[-1.133,0.038],[0,0],[0,1.46],[0,0],[-1.133,0.038],[0,0],[0,1.46],[0,0],[0,5.707],[0,0],[2.165,0],[0.833,-0.334],[0,0],[1.894,1.05],[0,0],[5.707,0],[0,0],[0,-5.707]],"v":[[106.16,-102.082],[8.455,-102.082],[2.265,-100.48],[-0.488,-100.468],[-0.519,-100.48],[-6.71,-102.082],[-104.116,-102.082],[-114.45,-91.748],[-114.45,-36.119],[-116.494,-33.44],[-116.494,-18.979],[-114.45,-16.3],[-114.45,-0.877],[-116.494,1.802],[-116.494,28.704],[-114.45,31.383],[-114.45,91.749],[-104.116,102.083],[-6.495,102.083],[-0.305,100.481],[2.294,100.425],[2.395,100.481],[9.872,102.083],[106.161,102.083],[116.494,91.75],[116.494,-91.748]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960813999,0.529411792755,0.54509806633,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_rear_portrait_reverse_base.json b/packages/SystemUI/res/raw/biometricprompt_rear_portrait_reverse_base.json
deleted file mode 100644
index f2b2593..0000000
--- a/packages/SystemUI/res/raw/biometricprompt_rear_portrait_reverse_base.json
+++ /dev/null
@@ -1 +0,0 @@
-{"v":"5.8.1","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"BiometricPrompt_Rear_Portrait_Reverse_Base_Foldable","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 18","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":270,"ix":10},"p":{"a":0,"k":[169.478,169.749,0],"ix":2,"l":2},"a":{"a":0,"k":[-48.123,-30.19,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".grey400","cl":"grey400","parent":13,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.741176486015,0.75686275959,0.776470601559,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"black circle matte","parent":13,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".grey904","cl":"grey904","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-62.577,35.536,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-2.552,0.087],[0,0]],"o":[[0,0],[0,-3.287],[0,0],[0,0]],"v":[[-2.301,8.869],[-2.301,-3.772],[2.301,-9.806],[2.301,9.806]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960813999,0.525490224361,0.54509806633,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"black circle matte 2","parent":13,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".blue401","cl":"blue401","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-62.577,-27.655,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,3.286],[0,0],[-2.552,0.086],[0,0]],"o":[[0,0],[0,-3.286],[0,0],[-2.552,-0.086]],"v":[[-2.301,16.282],[-2.301,-16.281],[2.301,-22.313],[2.301,22.313]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"black circle matte 3","parent":13,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Finger 2","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-75.352,41.307,0],"ix":2,"l":2},"a":{"a":0,"k":[94.648,211.307,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[6.72,-5.642],[0,0],[-9.394,-0.562],[-0.298,-0.038]],"o":[[-5.153,4.329],[3.882,-16.05],[0.31,0.019],[-0.044,0.75]],"v":[[0.863,12.222],[-8.931,14.755],[8.005,-15.108],[8.931,-15.021]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.792156875134,0.454901963472,0.376470595598,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[81.486,130.081],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 9","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.459,6.045],[-5.153,4.329],[-0.044,0.75],[3.116,-24.664],[5.23,-22.052],[8.666,11.92],[-2.9,9.135]],"o":[[0,0],[6.72,-5.642],[12.723,1.335],[-2.369,18.762],[-13.993,-5.333],[2.255,-5.502],[1.843,-5.815]],"v":[[-9.99,-18.348],[-0.196,-20.881],[7.872,-48.124],[21.578,-9.331],[12.104,48.124],[-22.574,21.555],[-14.791,-0.206]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.713725507259,0.384313732386,0.282352954149,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[82.545,163.184],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 8","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"black circle matte 4","parent":13,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".grey903","cl":"grey903","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-18.345,-92.442,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[24.07,0],[0,0],[-8.27,0],[0,0]],"o":[[0,0],[0,8.269],[0,0],[-14.024,-17.379]],"v":[[-29.778,-14.252],[-29.778,-0.721],[-14.805,14.252],[29.778,14.252]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.372549027205,0.388235300779,0.407843142748,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"black circle matte 5","parent":13,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".grey902","cl":"grey902","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-15.947,-30.19,0],"ix":2,"l":2},"a":{"a":0,"k":[154.053,139.81,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[2.3,0.367],[0,0],[-2.364,0.157],[0,0]],"o":[[0,0],[2.3,-0.367],[0,0],[-2.364,-0.157]],"v":[[-3.5,75.533],[-3.5,-75.533],[3.5,-76.312],[3.5,76.312]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960813999,0.525490224361,0.54509806633,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[113.225,139.81],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 7","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,8.269],[0,0],[2.181,-0.187],[0,0],[-2.23,0],[0,42.252],[10.593,13.127],[0,0]],"o":[[0,0],[-2.23,0],[0,0],[2.181,0.187],[42.252,0],[0,-18.182],[0,0],[-8.27,0]],"v":[[-34.946,-62.973],[-34.946,-76.504],[-41.558,-76.201],[-41.558,76.201],[-34.946,76.504],[41.558,0],[24.61,-48],[-19.973,-48]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960813999,0.525490224361,0.54509806633,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[156.824,139.81],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 5","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".black 2","cl":"black","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-48.123,-30.19,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2,0.833],"y":[1,1,1]},"o":{"x":[0.7,0.7,0.167],"y":[0,0,0]},"t":-129,"s":[0,0,100]},{"t":-79,"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":[[-42.252,0],[0,42.252],[42.252,0],[0,-42.252]],"o":[[42.252,0],[0,-42.252],[-42.252,0],[0,42.252]],"v":[[0,76.504],[76.504,0],[0,-76.504],[-76.504,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".grey700","cl":"grey700","parent":15,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-56.481,-59.936,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[3.767,0],[0,0],[0,-3.767],[0,0],[-3.767,0],[0,0],[0,3.767],[0,0]],"o":[[0,0],[-3.767,0],[0,0],[0,3.767],[0,0],[3.767,0],[0,0],[0,-3.767]],"v":[[46.055,-14.479],[-46.056,-14.479],[-52.876,-7.659],[-52.876,7.658],[-46.056,14.479],[46.055,14.479],[52.876,7.658],[52.876,-7.659]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.372549027205,0.388235300779,0.407843142748,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":".grey901","cl":"grey901","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[16.485,2.727,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[4.184,0],[0,0],[0,0],[0,0],[0,-4.375]],"o":[[0,4.184],[0,0],[0,0],[0,0],[4.375,0],[0,0]],"v":[[114.116,92.129],[106.54,99.705],[7.788,99.705],[7.788,-99.704],[106.161,-99.704],[114.116,-91.749]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[5.707,0],[0,0],[1.894,-1.05],[0.886,0.346],[0,0],[2.166,0],[0,0],[0,-5.707],[0,0],[0,-1.46],[0,0],[-1.133,-0.038],[0,0],[0,-1.459],[0,0],[-1.133,-0.038],[0,0],[-5.708,0],[0,0],[-1.894,1.05],[-0.846,-0.289],[0,0],[-2.166,0],[0,0],[0,5.706],[0,0]],"o":[[0,0],[-2.166,0],[-0.883,0.354],[0,0],[-1.895,-1.05],[0,0],[-5.708,0],[0,0],[-1.133,0.038],[0,0],[0,1.46],[0,0],[-1.133,0.038],[0,0],[0,1.46],[0,0],[0,5.707],[0,0],[2.165,0],[0.833,-0.334],[0,0],[1.894,1.05],[0,0],[5.707,0],[0,0],[0,-5.707]],"v":[[106.16,-102.082],[8.455,-102.082],[2.265,-100.48],[-0.488,-100.468],[-0.519,-100.48],[-6.71,-102.082],[-104.116,-102.082],[-114.45,-91.748],[-114.45,-36.119],[-116.494,-33.44],[-116.494,-18.979],[-114.45,-16.3],[-114.45,-0.877],[-116.494,1.802],[-116.494,28.704],[-114.45,31.383],[-114.45,91.749],[-104.116,102.083],[-6.495,102.083],[-0.305,100.481],[2.294,100.425],[2.395,100.481],[9.872,102.083],[106.161,102.083],[116.494,91.75],[116.494,-91.748]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960813999,0.529411792755,0.54509806633,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-189,"op":711,"st":-189,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index c5d28ee..789a588 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"As jy met jou volgende poging \'n verkeerde PIN invoer, sal jou werkprofiel en die data daarvan uitgevee word."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"As jy met jou volgende poging \'n verkeerde wagwoord invoer, sal jou werkprofiel en die data daarvan uitgevee word."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Raak die vingerafdruksensor"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Vingerafdrukikoon"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Kan nie gesig herken nie. Gebruik eerder vingerafdruk."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# kontrole bygevoeg.}other{# kontroles bygevoeg.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Verwyder"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Voeg <xliff:g id="APPNAME">%s</xliff:g> by?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Wanneer jy <xliff:g id="APPNAME">%s</xliff:g> byvoeg, kan dit kontroles en inhoud by hierdie paneel voeg. Jy kan in sommige apps kies watter kontroles hier verskyn."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> kan kies watter kontroles en inhoud hier gewys word."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Verwyder kontroles vir <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"As gunsteling gemerk"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"As gunsteling gemerk; posisie <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"As gunsteling ontmerk"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Ander"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Voeg by toestelkontroles"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Voeg by"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Verwyder"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Voorgestel deur <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Toestel is gesluit"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Wys en beheer toestelle van sluitskerm af?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Jy kan vir jou eksterne toestelle kontroles op die sluitskerm byvoeg.\n\nJou toestelprogram kan jou dalk toelaat om sommige toestelle te beheer sonder om jou foon of tablet te ontsluit.\n\nJy kan enige tyd in Instellings veranderings maak."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Beheer toestelle van sluitskerm af?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Jy kan sommige toestelle beheer sonder om jou foon of tablet te ontsluit.\n\nJou toestelprogram bepaal watter toestelle op dié manier beheer kan word."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Jy kan sommige toestelle beheer sonder om jou foon of tablet te ontsluit. Jou toestelapp bepaal watter toestelle op dié manier beheer kan word."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Nee, dankie"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Ja"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN bevat letters of simbole"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Voeg kontroles by"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Wysig kontroles"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Voeg app by"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Verwyder app"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Voeg uitvoere by"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Groep"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 toestel gekies"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 101382e..0faf10c 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"በሚቀጥለው ሙከራ ላይ ትክክል ያልሆነ ፒን ካስገቡ የእርስዎ የሥራ መገለጫ እና ውሂቡ ይሰረዛሉ።"</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"በሚቀጥለው ሙከራ ላይ ትክክል ያልሆነ የይለፍ ቃል ካስገቡ የእርስዎ የሥራ መገለጫ እና ውሂቡ ይሰረዛሉ።"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"የጣት አሻራ ዳሳሹን ይንኩ"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"የጣት አሻራ አዶ"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"መልክን መለየት አልተቻለም። በምትኩ የጣት አሻራ ይጠቀሙ።"</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -197,8 +196,7 @@
     <skip />
     <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"የማሳወቂያ ጥላ።"</string>
     <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ፈጣን ቅንብሮች።"</string>
-    <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
-    <skip />
+    <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"ፈጣን ቅንብሮች እና የማሳወቂያ ጥላ።"</string>
     <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ማያ ገጽ ቆልፍ።"</string>
     <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"የስራ ማያ ገጽ ቁልፍ"</string>
     <string name="accessibility_desc_close" msgid="8293708213442107755">"ዝጋ"</string>
@@ -809,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# ቁጥጥር ታክሏል።}one{# ቁጥጥር ታክሏል።}other{# ቁጥጥሮች ታክለዋል።}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"ተወግዷል"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> ይታከል?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"<xliff:g id="APPNAME">%s</xliff:g>ን ሲያክሉ መቆጣጠሪያዎችን እና ይዘትን ወደዚህ ፓነል ሊያክል ይችላል። በአንዳንድ መተግበሪያዎች ውስጥ የትኛዎቹ መቆጣጠሪያዎች እዚህ ላይ እንደሚታዩ መምረጥ ይችላሉ።"</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> የትኛዎቹ መቆጣጠሪያዎች እና ይዘት እዚህ እንደሚታዩ መምረጥ ይችላል።"</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"የ<xliff:g id="APPNAME">%s</xliff:g> መቆጣጠሪያዎች ይወገዱ?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"ተወዳጅ የተደረገ"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"ተወዳጅ ተደርጓል፣ አቋም <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"ተወዳጅ አልተደረገም"</string>
@@ -827,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ሌላ"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"ወደ የመሣሪያ መቆጣጠሪያዎች ያክሉ"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"አክል"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"አስወግድ"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"በ<xliff:g id="APP">%s</xliff:g> የተጠቆመ"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"መሣሪያ ተቆልፏል"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"ከማያ ገጽ ቆልፍ ላይ መሳሪያዎች ይታዩ እና ይቆጣጠሩ?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"ለውጫዊ መሳሪያዎችዎ መቆጣጠሪያዎችን ወደ ማያ ገጽ ቆልፍ ማከል ይችላሉ።\n\nየእርስዎ መሣሪያ መተግበሪያ የእርስዎን ስልክ ወይም ጡባዊ ሳይከፍቱ አንዳንድ መሣሪያዎችን እንዲቆጣጠሩ ሊፈቅድልዎ ይችላል።\n\nበቅንብሮች ውስጥ በማንኛውም ጊዜ ለውጦችን ማድረግ ይችላሉ።"</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"መሳሪያዎች ከማያ ገጽ ቆልፍ ይቆጣጠሩ?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"የእርስዎን ስልክ ወይም ጡባዊ ሳይከፍቱ አንዳንድ መሳሪያዎችን መቆጣጠር ይችላሉ።\n\nየእርስዎ መሣሪያ መተግበሪያ የትኞቹ መሣሪያዎች በዚህ መንገድ ሊቆጣጠሩ እንደሚችሉ ይወስናል።"</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"የእርስዎን ስልክ ወይም ጡባዊ ሳይከፍቱ አንዳንድ መሣሪያዎችን መቆጣጠር ይችላሉ። የእርስዎ መሣሪያ መተግበሪያ የትኞቹን መሣሪያዎች በዚህ መንገድ መቆጣጠር እንደሚቻል ይወስናል።"</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"አይ፣ አመሰግናለሁ"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"አዎ"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"ፒን ፊደሎችን ወይም ምልክቶችን ይይዛል"</string>
@@ -880,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"መቆጣጠሪያዎችን አክል"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"መቆጣጠሪያዎችን ያርትዑ"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"መተግበሪያ አክል"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"መተግበሪያን አስወግድ"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"ውጽዓቶችን ያክሉ"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"ቡድን"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 መሣሪያ ተመርጧል"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 1352841..d8b37d3 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"عند إدخال رقم تعريف شخصي غير صحيح في المحاولة التالية، سيتم حذف ملفك الشخصي للعمل وبياناته."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"عند إدخال كلمة مرور غير صحيحة في المحاولة التالية، سيتم حذف ملفك الشخصي للعمل وبياناته."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"المس أداة استشعار بصمة الإصبع"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"رمز بصمة الإصبع"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"يتعذّر التعرّف على الوجه. استخدِم بصمة الإصبع بدلاً من ذلك."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -238,8 +237,8 @@
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"التدوير التلقائي للشاشة"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"الموقع الجغرافي"</string>
     <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"شاشة الاستراحة"</string>
-    <string name="quick_settings_camera_label" msgid="5612076679385269339">"الوصول إلى الكاميرا"</string>
-    <string name="quick_settings_mic_label" msgid="8392773746295266375">"الوصول إلى الميكروفون"</string>
+    <string name="quick_settings_camera_label" msgid="5612076679385269339">"الكاميرا"</string>
+    <string name="quick_settings_mic_label" msgid="8392773746295266375">"الميكروفون"</string>
     <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"متاح"</string>
     <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"محظور"</string>
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"جهاز الوسائط"</string>
@@ -808,7 +807,9 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{تمت إضافة عنصر تحكّم واحد.}zero{تمت إضافة # عنصر تحكّم.}two{تمت إضافة عنصرَي تحكّم.}few{تمت إضافة # عناصر تحكّم.}many{تمت إضافة # عنصر تحكّم.}other{تمت إضافة # عنصر تحكّم.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"تمت الإزالة"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"هل تريد إضافة \"<xliff:g id="APPNAME">%s</xliff:g>\"؟"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"عند إضافة تطبيق \"<xliff:g id="APPNAME">%s</xliff:g>\"، يمكنه إضافة عناصر تحكّم ومحتوى إلى هذه اللوحة. في بعض التطبيقات، يمكنك اختيار عناصر التحكّم التي تظهر هنا."</string>
+    <!-- no translation found for controls_panel_authorization (7045551688535104194) -->
+    <skip />
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"هل تريد إزالة عناصر التحكّم في \"<xliff:g id="APPNAME">%s</xliff:g>\"؟"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"تمت الإضافة إلى المفضّلة"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"تمت الإضافة إلى المفضّلة، الموضع <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"تمت الإزالة من المفضّلة"</string>
@@ -826,12 +827,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"غير ذلك"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"إضافة إلى أدوات التحكم بالجهاز"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"إضافة"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"إزالة"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"اقتراح من <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"الجهاز مُقفل."</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"هل تريد عرض أجهزتك والتحكم فيها من شاشة القفل؟"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"يمكنك إضافة عناصر تحكم لشاشة القفل الخاصة بأجهزتك الخارجية.\n\nقد يسمح لك تطبيق الجهاز بالتحكم في بعض الأجهزة بدون فتح قفل هاتفك أو جهازك اللوحي.\n\nيمكنك إجراء التغييرات في أي وقت من الإعدادات."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"هل تريد التحكم في الأجهزة من شاشة القفل؟"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"يمكنك التحكم في بعض الأجهزة بدون فتح قفل هاتفك أو جهازك اللوحي.\n\nيحدِّد تطبيق الجهاز أيًا من الأجهزة يمكن التحكم فيه على هذا النحو."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"يمكنك التحكّم في بعض الأجهزة بدون فتح قفل هاتفك أو جهازك اللوحي. يحدِّد تطبيق التحكّم بجهاز آخر الأجهزة التي يمكن التحكّم فيها على هذا النحو."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"لا، شكرًا"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"نعم"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"يشتمل رقم التعريف الشخصي على أحرف أو رموز."</string>
@@ -879,6 +881,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"إضافة عناصر تحكّم"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"تعديل عناصر التحكّم"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"إضافة تطبيق"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"إزالة التطبيق"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"إضافة مخرجات"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"مجموعة"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"تم اختيار جهاز واحد."</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 13acbde..dbd8096 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"আপুনি পৰৱৰ্তী প্ৰয়াসত এটা ভুল পিন দিলে, আপোনাৰ কৰ্মস্থানৰ প্ৰ’ফাইল আৰু ইয়াৰ ডেটা মচি পেলোৱা হ’ব।"</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"আপুনি পৰৱৰ্তী প্ৰয়াসত এটা ভুল পাছৱৰ্ড দিলে, আপোনাৰ কৰ্মস্থানৰ প্ৰ’ফাইল আৰু ইয়াৰ ডেটা মচি পেলোৱা হ’ব।"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ফিংগাৰপ্ৰিণ্ট ছেন্সৰটো স্পৰ্শ কৰক"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"ফিংগাৰপ্ৰিণ্ট আইকন"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"মুখাৱয়ব চিনিব নোৱাৰি। ফিংগাৰপ্ৰিণ্ট ব্যৱহাৰ কৰক।"</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# টা নিয়ন্ত্ৰণ যোগ দিয়া হৈছে।}one{# টা নিয়ন্ত্ৰণ যোগ দিয়া হৈছে।}other{# টা নিয়ন্ত্ৰণ যোগ দিয়া হৈছে।}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"আঁতৰোৱা হ’ল"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> যোগ দিবনে?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"আপুনি <xliff:g id="APPNAME">%s</xliff:g> যোগ দিলে, ই এই পেনেলত নিয়ন্ত্ৰণ আৰু সমল যোগ দিব পাৰে। কিছুমান এপত আপুনি কোনবোৰ নিয়ন্ত্ৰণ ইয়াত দেখা পোৱা যাব সেয়া বাছনি কৰিব পাৰে।"</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g>এ ইয়াত কোনবোৰ নিয়ন্ত্ৰণ আৰু সমল দেখুওৱা হ’ব সেয়া বাছনি কৰিব পাৰে।"</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g>ৰ নিয়ন্ত্ৰণ আঁতৰাবনে?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"প্ৰিয় হিচাপে চিহ্নিত কৰা হ’ল"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"প্ৰিয় হিচাপে চিহ্নিত কৰা হ’ল, স্থান <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"অপ্ৰিয় হিচাপে চিহ্নিত কৰা হ’ল"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"অন্য"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"ডিভাইচৰ নিয়ন্ত্ৰণসমূহত যোগ দিয়ক"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"যোগ দিয়ক"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"আঁতৰাওক"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g>এ পৰামৰ্শ হিচাপে আগবঢ়োৱা"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"ডিভাইচ লক হৈ আছে"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"লক স্ক্ৰীনৰ পৰা ডিভাইচসমূহ লক আৰু নিয়ন্ত্ৰণ কৰিবনে?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"আপুনি লক স্ক্ৰীনত আপোনাৰ বাহ্যিক ডিভাইচৰ বাবে নিয়ন্ত্ৰণ যোগ দিব পাৰে।\n\nআপোনাৰ ডিভাইচ এপে আপোনাক আপোনাৰ ফ’ন অথবা টেবলেট আনলক নকৰাকৈ কিছুমান ডিভাইচ নিয়ন্ত্ৰণ কৰাৰ অনুমতি দিব পাৰে। \n\nআপুনি যিকোনো সময়তে ছেটিঙত সালসলনি কৰিব পাৰে।"</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"লক স্ক্ৰীনৰ পৰা ডিভাইচসমূহ নিয়ন্ত্ৰণ কৰিবনে?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"আপুনি আপোনাৰ ফ’ন অথবা টেবলেট আনলক নকৰাকৈ কিছুমান ডিভাইচ নিয়ন্ত্ৰণ কৰিব পাৰে।\n\nএইধৰণে কোনবোৰ ডিভাইচ নিয়ন্ত্ৰণ কৰিব পাৰি সেয়া আপোনাৰ ডিভাইচ এপে নিৰ্ধাৰণ কৰে।"</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"আপুনি আপোনাৰ ফ’ন অথবা টেবলেট আনলক নকৰাকৈ কিছুমান ডিভাইচ নিয়ন্ত্ৰণ কৰিব পাৰে।এইধৰণে কোনবোৰ ডিভাইচ নিয়ন্ত্ৰণ কৰিব পাৰি সেয়া আপোনাৰ ডিভাইচ এপে নিৰ্ধাৰণ কৰে।"</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"নালাগে, ধন্যবাদ"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"হয়"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"পিনত বৰ্ণ অথবা প্ৰতীকসমূহ থাকে"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"নিয়ন্ত্ৰণসমূহ যোগ দিয়ক"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"নিয়ন্ত্ৰণসমূহ সম্পাদনা কৰক"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"এপ্‌ যোগ দিয়ক"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"এপ্‌টো আঁতৰাওক"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"আউটপুটসমূহ যোগ দিয়ক"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"গোট"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"১ টা ডিভাইচ বাছনি কৰা হৈছে"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 6a8eb2c..684a13e 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Növbəti cəhddə yanlış PIN daxil etsəniz, iş profili və datası silinəcək."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Növbəti cəhddə yanlış parol daxil etsəniz, iş profili və datası silinəcək."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Barmaq izi sensoruna klikləyin"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Barmaq izi ikonası"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Tanımaq olmur. Barmaq izini işlədin."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# nizamlayıcı əlavə edilib.}other{# nizamlayıcı əlavə edilib.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Silinib"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> əlavə edilsin?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"<xliff:g id="APPNAME">%s</xliff:g> əlavə etdiyiniz zaman, o, bu panelə nizamlayıcılar və məzmun əlavə edə bilər. Bəzi tətbiqlərdə burada hansı nizamlayıcıların göstərilməsini seçə bilərsiniz."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> burada göstəriləcək nizamlayıcı və kontenti seçə bilər."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> nizamlayıcıları silinsin?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Sevimlilərə əlavə edilib"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Sevimlilərə əlavə edilib, sıra: <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Sevimlilərdən silinib"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Digər"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Cihaz idarəetmələrinə əlavə edin"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Əlavə edin"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Silin"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> tərəfindən təklif edilib"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Cihaz kilidlənib"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Kilid ekranından cihazlar göstərilsin və idarə edilsin?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Xarici cihazlarınız üçün kilid ekranına nizamlayıcılar əlavə edə bilərsiniz.\n\nCihaz tətbiqiniz sizə telefon və ya planşetinizin kilidini açmadan bəzi cihazları idarə etməyə imkan verə bilər.\n\nİstənilən vaxt Ayarlarda dəyişiklik edə bilərsiniz."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Cihazları kilid ekranından idarə etmək istəyirsiniz?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Telefon və ya planşetinizin kilidini açmadan bəzi cihazları idarə edə bilərsiniz.\n\nCihaz tətbiqiniz hansı cihazların bu şəkildə idarə oluna biləcəyini müəyyən edir."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Telefon və ya planşetin kilidini açmadan bəzi cihazları idarə edə bilərsiniz. Cihaz tətbiqi hansı cihazların bu qaydada idarə oluna biləcəyini müəyyən edir."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Xeyr, təşəkkür"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Bəli"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN hərflər və ya simvollar ehtiva edir"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Vidcet əlavə edin"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Vidcetlərə düzəliş edin"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Tətbiq əlavə edin"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Tətbiqi silin"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Nəticələri əlavə edin"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Qrup"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 cihaz seçilib"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 3355feb..7727d3a 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ako unesete netačan PIN pri sledećem pokušaju, izbrisaćemo poslovni profil i njegove podatke."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Ako unesete netačnu lozinku pri sledećem pokušaju, izbrisaćemo poslovni profil i njegove podatke."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Dodirnite senzor za otisak prsta"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikona otiska prsta"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Lice nije prepoznato. Koristite otisak prsta."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -401,7 +400,7 @@
     <string name="media_projection_action_text" msgid="3634906766918186440">"Započni"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Nema obaveštenja"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Nema novih obaveštenja"</string>
-    <string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Otključajte da vidite starija obaveštenja"</string>
+    <string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Otključajte za starija obaveštenja"</string>
     <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Ovim uređajem upravlja roditelj"</string>
     <string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Organizacija je vlasnik uređaja i može da nadgleda mrežni saobraćaj"</string>
     <string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> je vlasnik ovog uređaja i može da nadgleda mrežni saobraćaj"</string>
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# kontrola je dodata.}one{# kontrola je dodata.}few{# kontrole su dodate.}other{# kontrola je dodato.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Uklonjeno"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Želite li da dodate <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Kada dodate aplikaciju <xliff:g id="APPNAME">%s</xliff:g>, ona može da dodaje kontrole i sadržaj u ovo okno. U nekim aplikacijama možete da izaberete koje će se kontrole ovde prikazivati."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> može da odabere koje kontrole i sadržaj se prikazuju ovde."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Želite da uklonite kontrole za <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Označeno je kao omiljeno"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Označeno je kao omiljeno, <xliff:g id="NUMBER">%d</xliff:g>. pozicija"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Uklonjeno je iz omiljenih"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Drugo"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Dodajte u kontrole uređaja"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Dodaj"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Ukloni"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Predlaže <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Uređaj je zaključan"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Želite li da prikazujete i kontrolišete uređaje sa zaključanog ekrana?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Možete da dodate kontrole za spoljne uređaje na zaključani ekran.\n\nAplikacija na uređaju može da vam omogući da kontrolišete neke uređaje bez otključavanja telefona ili tableta.\n\nTo možete da promenite kad god želite u Podešavanjima."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Želite li da kontrolišete uređaje sa zaključanog ekrana?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Neke uređaje možete da kontrolišete bez otključavanja telefona ili tableta.\n\nAplikacija na uređaju određuje koji uređaji mogu da se kontrolišu na ovaj način."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Neke uređaje možete da kontrolišete bez otključavanja telefona ili tableta. Aplikacija na uređaju određuje koji uređaji mogu da se kontrolišu na ovaj način."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Ne, hvala"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Da"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN sadrži slova ili simbole"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Dodaj kontrole"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Izmeni kontrole"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Dodaj aplikaciju"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Ukloni aplikaciju"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Dodajte izlaze"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Grupa"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Izabran je 1 uređaj"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index f045b59..bbc52e6 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Калі вы ўведзяце няправільны PIN-код яшчэ раз, ваш працоўны профіль і звязаныя з ім даныя будуць выдалены."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Калі вы ўведзяце няправільны пароль яшчэ раз, ваш працоўны профіль і звязаныя з ім даныя будуць выдалены."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Дакраніцеся да сканера адбіткаў пальцаў"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Значок адбіткаў пальцаў"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Твар не распазнаны. Скарыстайце адбітак пальца."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,9 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Дададзены # элемент кіравання.}one{Дададзена # элемента кіравання.}few{Дададзена # элементы кіравання.}many{Дададзена # элементаў кіравання.}other{Дададзена # элемента кіравання.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Выдалена"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Дадаць праграму \"<xliff:g id="APPNAME">%s</xliff:g>\"?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Калі вы дадасце праграму \"<xliff:g id="APPNAME">%s</xliff:g>\", яна зможа дадаваць на гэту панэль налады і змесціва. Для некаторых праграм вы зможаце выбраць, якія налады будуць тут паказвацца."</string>
+    <!-- no translation found for controls_panel_authorization (7045551688535104194) -->
+    <skip />
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Выдаліць налады для <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Дададзена ў абранае"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Дададзена ў абранае, пазіцыя <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Выдалена з абранага"</string>
@@ -826,12 +827,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Іншае"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Дадаць у элементы кіравання прыладай"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Дадаць"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Выдаліць"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Прапанавана праграмай \"<xliff:g id="APP">%s</xliff:g>\""</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Прылада блакіравана"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Паказваць прылады і кіраваць імі з экрана блакіроўкі?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Вы можаце дадаць на экран блакіроўкі элементы кіравання знешнімі прыладамі.\n\nДзякуючы праграме на вашай прыладзе вы можаце кіраваць некаторымі прыладамі без разблакіроўкі тэлефона ці планшэта.\n\nУнесці змяненні можна ў любы час у Наладах."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Кіраваць прыладамі з экрана блакіроўкі?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Вы можаце кіраваць некаторымі прыладамі без разблакіроўкі тэлефона ці планшэта.\n\nПраграма на вашай прыладзе вызначае, якімі прыладамі можна кіраваць такім спосабам."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Вы можаце кіраваць некаторымі прыладамі без разблакіроўкі тэлефона ці планшэта. Якімі прыладамі можна кіраваць такім спосабам, вызначае праграма на вашай прыладзе."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Не, дзякуй"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Так"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-код складаецца з літар або знакаў"</string>
@@ -879,6 +881,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Дадаць элементы кіравання"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Змяніць элементы кіравання"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Дадаць праграму"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Выдаліць праграму"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Дадайце прылады вываду"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Група"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Выбрана 1 прылада"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index dfb0c5b..c9e6e99 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ако въведете неправилен ПИН код при следващия опит, служебният ви потребителски профил и данните в него ще бъдат изтрити."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Ако въведете неправилна парола при следващия опит, служебният ви потребителски профил и данните в него ще бъдат изтрити."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Докоснете сензора за отпечатъци"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Икона за отпечатък"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Лицето не е разпознато. Използвайте отпечатък."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -238,7 +237,7 @@
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Автоматично завъртане на екрана"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Местоположение"</string>
     <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Скрийнсейвър"</string>
-    <string name="quick_settings_camera_label" msgid="5612076679385269339">"Камера: достъп"</string>
+    <string name="quick_settings_camera_label" msgid="5612076679385269339">"Достъп до камерата"</string>
     <string name="quick_settings_mic_label" msgid="8392773746295266375">"Достъп до микрофона"</string>
     <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Налице"</string>
     <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Блокирано"</string>
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Добавена е # контрола.}other{Добавени са # контроли.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Премахнато"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Да се добави ли <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Когато добавите <xliff:g id="APPNAME">%s</xliff:g>, приложението може да добави контроли и съдържание към този панел. Някои приложения ви дават възможност да избирате кои контроли да се показват тук."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> може да избира съдържанието и контролите, които да се показват тук."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Да се премахнат ли контролите за <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Означено като любимо"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Означено като любимо – позиция <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Не е означено като любимо"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Друго"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Добавяне към контролите за устройството"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Добавяне"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Премахване"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Предложено от <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"У-вото е заключено"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Да се показват ли устройствата на заключения екран и да се контролират ли оттам?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Можете да добавите към заключения екран контроли за външните си устройства.\n\nПриложението на устройството ви може да ви дава възможност да управлявате някои устройства, без да отключвате телефона или таблета си.\n\nПо всяко време можете да правите промени в „Настройки“."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Да се контролират ли устройствата от заключения екран?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Имате възможност да контролирате някои устройства, без да отключвате телефона или таблета си.\n\nПриложението на устройството ви определя кои устройства могат да бъдат контролирани по този начин."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Имате възможност да контролирате някои устройства, без да отключвате телефона или таблета си. Приложението на устройството ви определя кои устройства могат да бъдат контролирани по този начин."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Не, благодаря"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Да"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"ПИН кодът съдържа букви или символи"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Добавяне на контроли"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Редактиране на контролите"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Добавяне на приложение"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Премахване на приложението"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Добавяне на изходящи устройства"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Група"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 избрано устройство"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 42e8492..35af7ec 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"আপনি পরের বারও ভুল পিন দিলে আপনার অফিস প্রোফাইল এবং তার ডেটা মুছে দেওয়া হবে।"</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"আপনি পরের বারও ভুল পাসওয়ার্ড দিলে আপনার অফিস প্রোফাইল এবং তার ডেটা মুছে দেওয়া হবে।"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"আঙ্গুলের ছাপের সেন্সর স্পর্শ করুন"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"আঙ্গুলের ছাপের আইকন"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"মুখ শনাক্ত করতে পারছি না। পরিবর্তে আঙ্গুলের ছাপ ব্যবহার করুন।"</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{#টি কন্ট্রোল যোগ করা হয়েছে।}one{#টি কন্ট্রোল যোগ করা হয়েছে।}other{#টি কন্ট্রোল যোগ করা হয়েছে।}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"সরানো হয়েছে"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> যোগ করবেন?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"আপনি <xliff:g id="APPNAME">%s</xliff:g> যোগ করলে, এই প্যানেলে এটি কন্ট্রোল ও কন্টেন্ট যোগ করতে পারবে। কিছু অ্যাপের ক্ষেত্রে, এখানে কোন কোন কন্ট্রোল দেখা যাবে আপনি তা নিয়ন্ত্রণ করতে পারবেন।"</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"এখানে কোন কন্ট্রোল ও কন্টেন্ট দেখানো হবে <xliff:g id="APPNAME">%s</xliff:g> তা বেছে নিতে পারবে।"</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g>-এর জন্য নিয়ন্ত্রণ সরিয়ে দেবেন?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"পছন্দসই হিসেবে চিহ্নিত করেছেন"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"পছন্দসই হিসেবে চিহ্নিত করেছেন, অবস্থান <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"পছন্দসই থেকে সরিয়ে দিয়েছেন"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"অন্য"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"ডিভাইস কন্ট্রোলে যোগ করুন"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"যোগ করুন"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"সরিয়ে দিন"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> সাজেস্ট করেছে"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"ডিভাইস লক করা আছে"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"লক স্ক্রিন থেকে ডিভাইস দেখতে এবং নিয়ন্ত্রণ করতে চান?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"লক স্ক্রিনে আপনার বাইরের ডিভাইসের জন্য কন্ট্রোল যোগ করা যাবে।\n\nআপনার ফোন বা ট্যাবলেট আনলক না করেই আপনার ডিভাইস অ্যাপ হয়ত কিছু ডিভাইস নিয়ন্ত্রণ করার সুবিধা দেবে\n\nসেটিংস থেকে যেকোনও সময়ে আপনি পরিবর্তন করতে পারবেন।"</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"লক স্ক্রিন থেকে ডিভাইস নিয়ন্ত্রণ করতে চান?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"আপনি ফোন বা ট্যাবলেট আনলক না করেই কিছু ডিভাইস নিয়ন্ত্রণ করতে পারবেন।\n\nএইভাবে কোন ডিভাইস নিয়ন্ত্রণ করা হবে সেটি আপনার ডিভাইস অ্যাপ ঠিক করে।"</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"আপনি ফোন বা ট্যাবলেট আনলক না করেই কিছু ডিভাইস নিয়ন্ত্রণ করতে পারবেন। এইভাবে কোন ডিভাইস নিয়ন্ত্রণ করতে পারা যাবে তা আপনার ডিভাইস অ্যাপ ঠিক করে।"</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"না থাক"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"হ্যাঁ"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"পিন-এ অক্ষর বা চিহ্ন রয়েছে"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"কন্ট্রোল যোগ করুন"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"কন্ট্রোল এডিট করুন"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"অ্যাপ যোগ করুন"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"অ্যাপটি সরিয়ে দিন"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"আউটপুট যোগ করুন"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"গ্রুপ"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"১টি ডিভাইস বেছে নেওয়া হয়েছে"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 6da1913..5af4836 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ako u sljedećem pokušaju unesete neispravan PIN, vaš radni profil i njegovi podaci će se izbrisati."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Ako u sljedećem pokušaju unesete neispravnu lozinku, vaš radni profil i njegovi podaci će se izbrisati."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Dodirnite senzor za otisak prsta"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikona za otisak prsta"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nije moguće prepoznati lice. Koristite otisak prsta."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Dodana je # kontrola.}one{Dodana je # kontrola.}few{Dodane su # kontrole.}other{Dodano je # kontrola.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Uklonjeno"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Dodati aplikaciju <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Kada dodate aplikaciju <xliff:g id="APPNAME">%s</xliff:g>, ona može dodavati kontrole i sadržaj na ovu ploču. U nekim aplikacijama možete odabrati koje kontrole se prikazuju ovdje."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"Aplikacija <xliff:g id="APPNAME">%s</xliff:g> može odabrati koje će kontrole i sadržaj prikazivati ovdje."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Ukloniti kontrole za aplikaciju <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Dodano u omiljeno"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Dodano u omiljeno, pozicija <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Uklonjeno iz omiljenog"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Drugo"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Dodajte u kontrole uređaja"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Dodaj"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Uklanjanje"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Predlaže <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Uređaj je zaključan"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Prikazati uređaje i kontrolirati njima sa zaključanog ekrana?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Na zaključani ekran možete dodati kontrole za eksterne uređaje.\n\nAplikacija vašeg uređaja vam može omogućiti da kontrolirate određene uređaje bez otključavanja telefona ili tableta.\n\nPromjene možete izvršiti bilo kada u Postavkama."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Kontrolirati uređaje sa zaključanog ekrana?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Neke uređaje možete kontrolirati bez otključavanja telefona ili tableta.\n\nAplikacija vašeg uređaja određuje koji uređaji se mogu kontrolirati na ovaj način."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Neke uređaje možete kontrolirati bez otključavanja telefona ili tableta. Aplikacija uređaja određuje koji se uređaji mogu kontrolirati na ovaj način."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Ne, hvala"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Da"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN sadrži slova ili simbole"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Dodaj kontrole"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Uredi kontrole"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Dodaj aplikaciju"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Ukloni aplikaciju"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Dodajte izlaze"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Grupa"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Odabran je 1 uređaj"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 81903a7..02b4b38 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Si tornes a introduir un PIN incorrecte, se suprimirà el perfil de treball i les dades que contingui."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Si tornes a introduir una contrasenya incorrecta, se suprimirà el perfil de treball i les dades que contingui."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Toca el sensor d\'empremtes digitals"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Icona d\'empremta digital"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"No podem detectar la cara. Usa l\'empremta digital."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -239,7 +238,7 @@
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Ubicació"</string>
     <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Estalvi de pantalla"</string>
     <string name="quick_settings_camera_label" msgid="5612076679385269339">"Accés a la càmera"</string>
-    <string name="quick_settings_mic_label" msgid="8392773746295266375">"Accés al micròfon"</string>
+    <string name="quick_settings_mic_label" msgid="8392773746295266375">"Accés al micro"</string>
     <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Disponible"</string>
     <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Bloquejat"</string>
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Dispositiu multimèdia"</string>
@@ -401,7 +400,7 @@
     <string name="media_projection_action_text" msgid="3634906766918186440">"Comença ara"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"No hi ha cap notificació"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"No hi ha cap notificació nova"</string>
-    <string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Desbloq. per veure notificacions antigues"</string>
+    <string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Desbloqueja per veure notif. anteriors"</string>
     <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Els teus pares gestionen aquest dispositiu"</string>
     <string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"La teva organització és propietària del dispositiu i és possible que supervisi el trànsit de xarxa"</string>
     <string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> és propietària d\'aquest dispositiu i és possible que supervisi el trànsit de xarxa"</string>
@@ -675,7 +674,7 @@
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"suprimir el mosaic"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"afegir un mosaic al final"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mou el mosaic"</string>
-    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Afegeix un mosaic"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Afegeix una icona"</string>
     <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Mou a la posició <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Afegeix a la posició <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posició <xliff:g id="POSITION">%1$d</xliff:g>"</string>
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{S\'ha afegit # control.}many{S\'han afegit # controls.}other{S\'han afegit # controls.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Suprimit"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Vols afegir <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"En afegir <xliff:g id="APPNAME">%s</xliff:g>, podrà afegir controls i contingut en aquest tauler. En algunes aplicacions, pots triar quins controls es mostren aquí."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> pot triar quins controls i continguts es mostren aquí."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Vols suprimir els controls per a <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Afegit als preferits"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Afegit als preferits, posició <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Suprimit dels preferits"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Altres"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Afegeix als controls de dispositius"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Afegeix"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Suprimeix"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Suggerit per <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Dispositiu bloquejat"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Vols mostrar i controlar dispositius a la pantalla de bloqueig?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Pots afegir controls dels teus dispositius externs a la pantalla de bloqueig.\n\nL\'aplicació del dispositiu et pot permetre controlar alguns dispositius sense desbloquejar el telèfon o la tauleta.\n\nPots fer canvis en qualsevol moment a Configuració."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Vols controlar dispositius des de la pantalla de bloqueig?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Pots controlar alguns dispositius sense desbloquejar el telèfon o la tauleta.\n\nL\'aplicació del dispositiu determina quins dispositius es poden controlar d\'aquesta manera."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Pots controlar alguns dispositius sense desbloquejar el telèfon o la tauleta. L\'aplicació del dispositiu determina quins dispositius es poden controlar d\'aquesta manera."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"No, gràcies"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Sí"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"El PIN conté lletres o símbols"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Afegeix controls"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Edita els controls"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Afegeix una aplicació"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Suprimeix l\'aplicació"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Afegeix sortides"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Grup"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 dispositiu seleccionat"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 6369fe5..867e6f9 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Pokud při příštím pokusu zadáte nesprávný PIN, váš pracovní profil a přidružená data budou smazána."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Pokud při příštím pokusu zadáte nesprávné heslo, váš pracovní profil a přidružená data budou smazána."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Dotkněte se snímače otisků prstů"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikona otisku prstu"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Obličej se nepodařilo rozpoznat. Použijte místo něj otisk prstu."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,9 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Byl přidán # ovládací prvek.}few{Byly přidány # ovládací prvky.}many{Bylo přidáno # ovládacího prvku.}other{Bylo přidáno # ovládacích prvků.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Odstraněno"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Přidat aplikaci <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Když přidáte aplikaci <xliff:g id="APPNAME">%s</xliff:g>, může do tohoto panelu přidat ovládací prvky a obsah. V některých aplikacích si můžete vybrat, které ovládací prvky se zde zobrazí."</string>
+    <!-- no translation found for controls_panel_authorization (7045551688535104194) -->
+    <skip />
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Odstranit ovládací prvky aplikace <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Přidáno do oblíbených"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Přidáno do oblíbených na pozici <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Odebráno z oblíbených"</string>
@@ -826,12 +827,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Jiné"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Přidání ovládání zařízení"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Přidat"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Odstranit"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Návrh z aplikace <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Zařízení uzamčeno"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Zobrazovat a ovládat zařízení z obrazovky uzamčení?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Na obrazovku uzamčení můžete přidat ovládací prvky pro svá externí zařízení.\n\nAplikace zařízení vám může umožnit ovládat některá zařízení bez odemykání telefonu nebo tabletu.\n\nZměny můžete kdykoli provést v Nastavení."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Ovládat zařízení z obrazovky uzamčení?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Některá zařízení můžete ovládat bez odemykání telefonu nebo tabletu.\n\nAplikace zařízení určuje, která zařízení lze tímto způsobem ovládat."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Některá zařízení můžete ovládat bez odemykání telefonu nebo tabletu. Aplikace zařízení určuje, která zařízení lze tímto způsobem ovládat."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Ne, díky"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Ano"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Kód PIN obsahuje písmena nebo symboly"</string>
@@ -879,6 +881,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Přidat ovládací prvky"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Upravit ovládací prvky"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Přidat aplikaci"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Odstranit aplikaci"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Přidání výstupů"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Skupina"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Je vybráno 1 zařízení"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 514e0cb..7499ffc 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Hvis du angiver en forkert pinkode i næste forsøg, slettes din arbejdsprofil og de tilhørende data."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Hvis du angiver en forkert adgangskode i næste forsøg, slettes din arbejdsprofil og de tilhørende data."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Sæt fingeren på fingeraftrykssensoren"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikon for fingeraftryk"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ansigtet kan ikke genkendes. Brug fingeraftryk i stedet."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,9 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# styringselement er tilføjet.}one{# styringselement er tilføjet.}other{# styringselementer er tilføjet.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Fjernet"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Vil du tilføje <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Når du tilføjer <xliff:g id="APPNAME">%s</xliff:g>, kan den føje styringselementer og indhold til dette panel. I nogle apps kan du vælge, hvilke styringselementer der vises her."</string>
+    <!-- no translation found for controls_panel_authorization (7045551688535104194) -->
+    <skip />
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Vil du fjerne styringselementerne for <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Angivet som favorit"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Angivet som favorit. Position <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Fjernet fra favoritter"</string>
@@ -826,12 +827,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Andre"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Føj til enhedsstyring"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Tilføj"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Fjern"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Foreslået af <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Enheden er låst"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Vil du se og styre enheder via låseskærmen?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Du kan tilføje styringselementer til dine eksterne enheder på låseskærmen.\n\nMed din enhedsapp kan du muligvis styre visse enheder uden at låse op for din telefon eller tablet.\n\nDu kan til enhver tid foretage ændringer i Indstillinger."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Vil du styre enheder via låseskærmen?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Du kan styre visse enheder uden at låse op for din telefon eller tablet.\n\nDin enhedsapp bestemmer, hvilke enheder der kan styres på denne måde."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Du kan styre visse enheder uden at låse op for din telefon eller tablet. Din enhedsapp bestemmer, hvilke enheder der kan styres på denne måde."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Nej tak"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Ja"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Pinkoden indeholder bogstaver eller symboler"</string>
@@ -879,6 +881,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Tilføj styring"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Rediger styring"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Tilføj app"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Fjern app"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Tilføj medieudgange"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Gruppe"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Der er valgt 1 enhed"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index c7f792c..2fc7ddc 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Wenn du beim nächsten Versuch eine falsche PIN eingibst, werden dein Arbeitsprofil und die zugehörigen Daten gelöscht."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Wenn du beim nächsten Versuch ein falsches Passwort eingibst, werden dein Arbeitsprofil und die zugehörigen Daten gelöscht."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Berühre den Fingerabdrucksensor"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Fingerabdruck-Symbol"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Gesicht wurde nicht erkannt. Verwende stattdessen den Fingerabdruck."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# Steuerelement hinzugefügt.}other{# Steuerelemente hinzugefügt.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Entfernt"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> hinzufügen?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Wenn du <xliff:g id="APPNAME">%s</xliff:g> hinzufügst, kann diese App Einstellungen und Inhalte zu diesem Bereich hinzufügen. In einigen Apps kannst du festlegen, welche Einstellungen hier angezeigt werden sollen."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> darf auswählen, welche Einstellungen und Inhalte hier angezeigt werden."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Einstellungen für <xliff:g id="APPNAME">%s</xliff:g> entfernen?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Zu Favoriten hinzugefügt"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Zu Favoriten hinzugefügt, Position <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Aus Favoriten entfernt"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Andere"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Zur Gerätesteuerung hinzufügen"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Hinzufügen"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Entfernen"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Vorgeschlagen von <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Gerät gesperrt"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Geräte auf Sperrbildschirm anzeigen und steuern?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Du kannst dem Sperrbildschirm Steuerelemente für deine externen Geräte hinzufügen.\n\nDie App deines Geräts ermöglicht dir eventuell, einige Geräte zu steuern, ohne dein Smartphone oder Tablet zu entsperren.\n\nDu kannst jederzeit Änderungen in den Einstellungen vornehmen."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Geräte über den Sperrbildschirm steuern?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Du kannst einige Geräte steuern, ohne das Smartphone oder Tablet zu entsperren.\n\nDie App deines Geräts bestimmt, welche Geräte auf diese Weise gesteuert werden können."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Du kannst einige Geräte steuern, ohne dass dazu das Smartphone oder Tablet entsperrt werden muss. Die Geräte-App ermittelt, welche Geräte auf diese Weise gesteuert werden können."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Nein danke"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Ja"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Die PIN enthält Buchstaben oder Symbole"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Steuerelemente hinzufügen"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Steuerelemente bearbeiten"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"App hinzufügen"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"App entfernen"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Ausgabegeräte hinzufügen"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Gruppe"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Ein Gerät ausgewählt"</string>
@@ -1043,14 +1045,9 @@
     <string name="call_from_work_profile_action" msgid="2937701298133010724">"Zum Arbeitsprofil wechseln"</string>
     <string name="call_from_work_profile_close" msgid="7927067108901068098">"Schließen"</string>
     <string name="lock_screen_settings" msgid="9197175446592718435">"Sperrbildschirm-Einstellungen"</string>
-    <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) -->
-    <skip />
-    <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) -->
-    <skip />
-    <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) -->
-    <skip />
-    <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) -->
-    <skip />
-    <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) -->
-    <skip />
+    <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Kein WLAN verfügbar"</string>
+    <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera blockiert"</string>
+    <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera und Mikrofon blockiert"</string>
+    <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon blockiert"</string>
+    <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioritätsmodus an"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 99fa0bf..fe2a23c 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Εάν εισαγάγετε εσφαλμένο PIN στην επόμενη προσπάθεια, το προφίλ εργασίας σας και τα δεδομένα του θα διαγραφούν."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Εάν εισαγάγετε εσφαλμένο κωδικό πρόσβασης στην επόμενη προσπάθεια, το προφίλ εργασίας σας και τα δεδομένα του θα διαγραφούν."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Αγγίξτε τον αισθητήρα δακτυλικού αποτυπώματος"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Εικονίδιο δακτυλικών αποτυπωμάτων"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Το πρόσωπο δεν αναγνωρίζεται. Χρησιμ. δακτ. αποτ."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Προστέθηκε # στοιχείο ελέγχου.}other{Προστέθηκαν # στοιχεία ελέγχου.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Καταργήθηκε"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Προσθήκη <xliff:g id="APPNAME">%s</xliff:g>;"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Όταν προσθέσετε την εφαρμογή <xliff:g id="APPNAME">%s</xliff:g>, μπορεί να προσθέσει στοιχεία ελέγχου και περιεχόμενο σε αυτό το πλαίσιο. Σε ορισμένες εφαρμογές, μπορείτε να επιλέξετε ποια στοιχεία ελέγχου θα εμφανίζονται εδώ."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"Η εφαρμογή <xliff:g id="APPNAME">%s</xliff:g> μπορεί να επιλέξει τα στοιχεία ελέγχου και το περιεχόμενο που θα εμφανίζεται εδώ."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Κατάργηση στοιχείων ελέγχου για την εφαρμογή <xliff:g id="APPNAME">%s</xliff:g>;"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Προστέθηκε στα αγαπημένα"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Προστέθηκε στα αγαπημένα, στη θέση <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Αφαιρέθηκε από τα αγαπημένα"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Άλλο"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Προσθήκη στα στοιχεία ελέγχου συσκευής"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Προσθήκη"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Κατάργηση"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Προτείνεται από <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Η συσκευή κλειδώθηκε"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Εμφάνιση και έλεγχος συσκευών από την οθόνη κλειδώματος;"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Μπορείτε να προσθέσετε στοιχεία ελέγχου για τις εξωτερικές συσκευές σας στην οθόνη κλειδώματος.\n\nΗ εφαρμογή της συσκευής σας μπορεί να σας παρέχει τη δυνατότητα ελέγχου ορισμένων συσκευών χωρίς να ξεκλειδώσετε το τηλέφωνο ή το tablet.\n\nΜπορείτε να κάνετε αλλαγές στις Ρυθμίσεις ανά πάσα στιγμή."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Έλεγχος συσκευών από την οθόνη κλειδώματος;"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Μπορείτε να ελέγχετε ορισμένες συσκευές χωρίς να ξεκλειδώσετε το τηλέφωνο ή το tablet σας.\n\nΗ εφαρμογή της συσκευής σας καθορίζει ποιες συσκευές μπορούν να ελέγχονται με αυτόν τον τρόπο."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Μπορείτε να ελέγχετε ορισμένες συσκευές χωρίς να ξεκλειδώσετε το τηλέφωνο ή το tablet σας. Η εφαρμογή της συσκευής σας καθορίζει ποιες συσκευές μπορούν να ελέγχονται με αυτόν τον τρόπο."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Όχι, ευχαριστώ"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Ναι"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Το PIN περιέχει γράμματα ή σύμβολα"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Προσθήκη στοιχείων ελέγχου"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Επεξεργασία στοιχείων ελέγχου"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Προσθήκη εφαρμογής"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Κατάργηση εφαρμογής"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Προσθήκη εξόδων"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Ομάδα"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Επιλέχτηκε 1 συσκευή"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 59eaeab3..1a1c202 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"If you enter an incorrect PIN on the next attempt, your work profile and its data will be deleted."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"If you enter an incorrect password on the next attempt, your work profile and its data will be deleted."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Touch the fingerprint sensor"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Fingerprint icon"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Can’t recognise face. Use fingerprint instead."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# control added.}other{# controls added.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Removed"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Add <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"When you add <xliff:g id="APPNAME">%s</xliff:g>, it can add controls and content to this panel. In some apps, you can choose which controls show up here."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> can choose which controls and content show here."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Remove controls for <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Favourited"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Favourited, position <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Unfavourited"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Other"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Add to device controls"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Add"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Remove"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Suggested by <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Device locked"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Show and control devices from the lock screen?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"You can add controls for your external devices to the lock screen.\n\nYour device app may allow you to control some devices without unlocking your phone or tablet.\n\nYou can make changes at any time in Settings."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Control devices from the lock screen?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"You can control some devices without unlocking your phone or tablet.\n\nYour device app determines which devices can be controlled in this way."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"You can control some devices without unlocking your phone or tablet. Your device app determines which devices can be controlled in this way."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"No, thanks"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Yes"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN contains letters or symbols"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Add controls"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Edit controls"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Add app"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Remove app"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Add outputs"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Group"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"One device selected"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index cbc9d6a..7b2eb27 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"If you enter an incorrect PIN on the next attempt, your work profile and its data will be deleted."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"If you enter an incorrect password on the next attempt, your work profile and its data will be deleted."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Touch the fingerprint sensor"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Fingerprint icon"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Can’t recognize face. Use fingerprint instead."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# control added.}other{# controls added.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Removed"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Add <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"When you add <xliff:g id="APPNAME">%s</xliff:g>, it can add controls and content to this panel. In some apps, you can choose which controls show up here."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> can choose which controls and content show here."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Remove controls for <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Favorited"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Favorited, position <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Unfavorited"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Other"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Add to device controls"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Add"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Remove"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Suggested by <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Device locked"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Show and control devices from lock screen?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"You can add controls for your external devices to the lock screen.\n\nYour device app may allow you to control some devices without unlocking your phone or tablet.\n\nYou can make changes any time in Settings."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Control devices from lock screen?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"You can control some devices without unlocking your phone or tablet.\n\nYour device app determines which devices can be controlled in this way."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"You can control some devices without unlocking your phone or tablet. Your device app determines which devices can be controlled in this way."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"No thanks"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Yes"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN contains letters or symbols"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Add controls"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Edit controls"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Add app"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Remove app"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Add outputs"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Group"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 device selected"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 59eaeab3..1a1c202 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"If you enter an incorrect PIN on the next attempt, your work profile and its data will be deleted."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"If you enter an incorrect password on the next attempt, your work profile and its data will be deleted."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Touch the fingerprint sensor"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Fingerprint icon"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Can’t recognise face. Use fingerprint instead."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# control added.}other{# controls added.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Removed"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Add <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"When you add <xliff:g id="APPNAME">%s</xliff:g>, it can add controls and content to this panel. In some apps, you can choose which controls show up here."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> can choose which controls and content show here."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Remove controls for <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Favourited"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Favourited, position <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Unfavourited"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Other"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Add to device controls"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Add"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Remove"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Suggested by <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Device locked"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Show and control devices from the lock screen?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"You can add controls for your external devices to the lock screen.\n\nYour device app may allow you to control some devices without unlocking your phone or tablet.\n\nYou can make changes at any time in Settings."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Control devices from the lock screen?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"You can control some devices without unlocking your phone or tablet.\n\nYour device app determines which devices can be controlled in this way."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"You can control some devices without unlocking your phone or tablet. Your device app determines which devices can be controlled in this way."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"No, thanks"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Yes"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN contains letters or symbols"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Add controls"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Edit controls"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Add app"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Remove app"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Add outputs"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Group"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"One device selected"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 59eaeab3..1a1c202 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"If you enter an incorrect PIN on the next attempt, your work profile and its data will be deleted."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"If you enter an incorrect password on the next attempt, your work profile and its data will be deleted."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Touch the fingerprint sensor"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Fingerprint icon"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Can’t recognise face. Use fingerprint instead."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# control added.}other{# controls added.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Removed"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Add <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"When you add <xliff:g id="APPNAME">%s</xliff:g>, it can add controls and content to this panel. In some apps, you can choose which controls show up here."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> can choose which controls and content show here."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Remove controls for <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Favourited"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Favourited, position <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Unfavourited"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Other"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Add to device controls"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Add"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Remove"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Suggested by <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Device locked"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Show and control devices from the lock screen?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"You can add controls for your external devices to the lock screen.\n\nYour device app may allow you to control some devices without unlocking your phone or tablet.\n\nYou can make changes at any time in Settings."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Control devices from the lock screen?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"You can control some devices without unlocking your phone or tablet.\n\nYour device app determines which devices can be controlled in this way."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"You can control some devices without unlocking your phone or tablet. Your device app determines which devices can be controlled in this way."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"No, thanks"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Yes"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN contains letters or symbols"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Add controls"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Edit controls"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Add app"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Remove app"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Add outputs"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Group"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"One device selected"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index e718dde..6b1fc66c 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‏‎‎‏‎‎‏‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‏‏‎‏‏‏‎‏‏‎‏‏‏‏‎‎‏‎‎‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‎If you enter an incorrect PIN on the next attempt, your work profile and its data will be deleted.‎‏‎‎‏‎"</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‏‏‎‏‎‎‏‎‏‏‏‏‏‏‎‎‎‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‎If you enter an incorrect password on the next attempt, your work profile and its data will be deleted.‎‏‎‎‏‎"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‏‎‎‎‏‏‎‏‏‎‎‏‎‎‏‎‏‎‏‏‎‎‏‎‏‎‎‎‏‏‏‎‎‎‏‎‏‎‏‎‏‎‏‎‏‏‏‏‏‏‏‎‏‏‏‏‏‎Touch the fingerprint sensor‎‏‎‎‏‎"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‏‏‏‏‏‎‎‏‎‏‎‏‏‎‎‏‏‎‎‏‎‎‏‏‏‎‏‎‎‏‎‎‏‏‎‏‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‎‏‎‏‎Fingerprint icon‎‏‎‎‏‎"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‏‏‏‎‏‎‏‏‏‏‎‏‎‎‏‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‎‏‎‏‎‎‏‏‎‎‎‏‎‎‎‏‎‎‎Can’t recognize face. Use fingerprint instead.‎‏‎‎‏‎"</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‏‏‎‎‏‎‏‎‎‏‎‎‏‏‏‎‎‎‎‏‏‏‎‏‏‎‏‎‎‏‎‎‏‏‎‎‏‎‎‏‎‎‏‎‏‎‎‏‎‎‎‎‏‏‎# control added.‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‏‏‎‎‏‎‏‎‎‏‎‎‏‏‏‎‎‎‎‏‏‏‎‏‏‎‏‎‎‏‎‎‏‏‎‎‏‎‎‏‎‎‏‎‏‎‎‏‎‎‎‎‏‏‎# controls added.‎‏‎‎‏‎}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‏‏‎‎‏‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‏‏‎‏‏‎‎‏‎‎‏‏‎‏‎‏‏‏‎‏‎‎‏‎‏‏‏‎‏‏‏‏‏‏‏‏‎Removed‎‏‎‎‏‎"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‏‎‏‏‎‏‏‎‎‎‎‏‏‎‎‏‏‎‎‏‎‎‎‏‎‎‎‏‎‏‎‎‏‏‎‏‏‎‎‏‎‏‎‏‏‏‎‎‏‎‎‎‏‎‏‎‎Add ‎‏‎‎‏‏‎<xliff:g id="APPNAME">%s</xliff:g>‎‏‎‎‏‏‏‎?‎‏‎‎‏‎"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‎‎‎‎‏‎‏‏‏‏‏‎‎‏‏‎‏‏‎‏‎‎‏‏‎‏‎‎‎‎‏‎‏‏‏‎‎‏‏‎‏‏‏‎‏‎‏‎‏‎‏‏‏‎When you add ‎‏‎‎‏‏‎<xliff:g id="APPNAME">%s</xliff:g>‎‏‎‎‏‏‏‎, it can add controls and content to this panel. In some apps, you can choose which controls show up here.‎‏‎‎‏‎"</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‎‎‏‏‎‏‏‎‏‎‎‏‏‏‏‏‎‏‏‏‎‏‎‎‎‏‎‎‏‏‏‎‎‏‎‎‏‏‏‎‏‏‎‏‎‏‏‎‎‎‎‏‎‎‎‏‎‎‏‏‎<xliff:g id="APPNAME">%s</xliff:g>‎‏‎‎‏‏‏‎ can choose which controls and content show here.‎‏‎‎‏‎"</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‎‏‎‏‎‎‏‏‎‏‎‎‎‏‎‏‎‏‏‎‏‎‏‎‏‎‎‏‏‎‏‏‏‏‎‏‏‎‎‏‎‏‎‏‏‏‎‎‏‎‎‎‎‏‎‎Remove controls for ‎‏‎‎‏‏‎<xliff:g id="APPNAME">%s</xliff:g>‎‏‎‎‏‏‏‎?‎‏‎‎‏‎"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‎‎‎‏‎‎‏‎‏‎‎‏‏‎‎‏‏‎‏‏‎‏‏‏‏‎‎‎‎‏‏‎‏‎‏‎‎‎‏‏‎‏‏‎‎‎‎‎‎‎‏‎Favorited‎‏‎‎‏‎"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‏‎‎‎‎‎‎‏‎‏‎‎‎‎‏‎‎‎‎‏‎‎‏‏‎‎‏‎‏‎‎‏‎‏‎‎‎‏‎‏‏‏‎‏‏‎‏‏‏‎‎‎‏‎‏‎Favorited, position ‎‏‎‎‏‏‎<xliff:g id="NUMBER">%d</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‏‏‏‏‎‏‏‎‏‎‏‎‎‎‎‎‏‎‎‎‏‏‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‎‏‎‏‏‏‎‏‏‎‎‎‎‏‏‏‎Unfavorited‎‏‎‎‏‎"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‎‎‏‏‎‎‏‎‏‏‎‎‎‏‏‎‏‏‎‏‏‎‏‎‏‏‏‏‏‎‏‎‎‏‏‎‎‎‎‏‎‏‏‎‎‎‎‏‎‎‎Other‎‏‎‎‏‎"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎‎‎‏‏‎‎‎‎‎‎‏‎‎‎‎‏‏‎‎‎‏‏‎‏‎‏‎‎‎‏‏‎‎‎‏‏‎‎‏‏‎‏‎‏‎‏‎‏‏‏‎‏‎‎Add to device controls‎‏‎‎‏‎"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‏‏‎‎‎‏‏‏‎‏‎‏‎‏‏‎‎‎‎‏‎‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‏‎‎‎‏‎‏‎‎‏‏‎‏‏‏‏‎‎Add‎‏‎‎‏‎"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‏‎‎‏‎‎‏‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‎‎‏‏‎‎‏‏‎‏‎‏‎‏‎‏‎‎‏‏‎‏‏‎‏‎‎‎‎‎Remove‎‏‎‎‏‎"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‎‏‎‏‏‏‏‏‏‎‏‎‎‎‏‎‎‎‎‎‏‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‏‏‏‎‎‏‎‏‎‎‏‎‏‎‏‎‎‏‎‎‎Suggested by ‎‏‎‎‏‏‎<xliff:g id="APP">%s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‎‎‎‏‎‎‏‏‎‏‏‏‏‏‎‏‎‏‏‎‏‎‎‎‏‏‎‏‏‏‎‏‎‏‏‎‎‎‏‎‎‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‎Device locked‎‏‎‎‏‎"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‎‏‎‎‏‏‎‎‏‎‏‏‏‏‏‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‎‏‏‏‏‎‏‏‎‎‎‏‏‏‎‎‏‎‎‏‎‎‏‎‎Show and control devices from lock screen?‎‏‎‎‏‎"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‎‎‏‏‏‏‎‏‏‎‏‎‏‏‏‎‏‏‎‎‏‎‎‏‏‏‏‎‏‎‏‏‎‏‏‎‎‎‎‏‏‎‏‏‏‏‎‎‎‎‎‏‎You can add controls for your external devices to the lock screen.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎Your device app may allow you to control some devices without unlocking your phone or tablet.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎You can make changes any time in Settings.‎‏‎‎‏‎"</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‎‎‎‎‎‎‏‏‎‏‏‎‎‎‏‏‎‎‏‏‎‎‎‏‎‎‎‎‏‏‎‏‏‏‎‏‏‎‎‏‏‎‎‏‏‎‎‎‎‎‏‎‏‎Control devices from lock screen?‎‏‎‎‏‎"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‎‏‎‎‏‎‏‎‏‎‏‎‎‏‎‏‎‏‏‎‎‏‎‏‏‏‏‏‎‏‎‏‏‎‏‎‎‏‎‏‏‎‎‎‎‏‎‎‏‎‎‏‎‎‏‎‎You can control some devices without unlocking your phone or tablet.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎Your device app determines which devices can be controlled in this way.‎‏‎‎‏‎"</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‏‏‎‎‎‎‎‏‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‎‎‎‏‏‎‏‏‏‏‎‎‏‏‎‎‎‏‎‎‎‎‏‏‏‏‏‏‏‎You can control some devices without unlocking your phone or tablet. Your device app determines which devices can be controlled in this way.‎‏‎‎‏‎"</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‎‎‎‏‎‎‏‎‎‎‎‏‎‏‎‏‎‎‎‎‏‏‏‎‎‎‎‎‎‎‎‎‏‎‏‎‎‎‏‎‎‏‎‏‏‎‎‎No thanks‎‏‎‎‏‎"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‎‎‎‎‎‏‏‎‏‎‎‏‏‏‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‏‏‎‎‏‏‎‏‎‎‎‏‎‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎Yes‎‏‎‎‏‎"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‎‏‎‎‏‎‎‏‏‏‎‏‎‎‏‎‎‏‎‎‏‏‎‎‎‏‎‎‏‏‏‏‏‎‎‏‎‎‏‎‎‎‎‏‎‏‏‎‏‏‏‏‎‎PIN contains letters or symbols‎‏‎‎‏‎"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‏‎‏‏‎‏‏‏‏‏‎‎‏‎‏‎‏‏‎‎‏‎‎‎‎‏‏‎‏‏‎‏‎‏‏‎‏‏‏‏‎‎‎‏‎‎‏‏‎‎‏‏‎‎‏‎‎Add controls‎‏‎‎‏‎"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‏‏‏‎‎‏‏‎‎‎‎‏‎‎‎‏‎‏‎‏‎‏‏‎‏‎‏‎‏‏‎‏‏‎‏‏‏‎‏‏‎‎Edit controls‎‏‎‎‏‎"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‎‏‎‏‎‏‎‏‎‏‎‎‏‎‏‎‎‏‎‎‏‏‏‏‏‎‏‎‎‏‎‏‎‎‏‎‏‎‏‎‏‏‏‏‎‎‏‎‎‎‏‎Add app‎‏‎‎‏‎"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‏‏‎‎‏‎‏‎‏‎‎‏‎‏‏‎‎‏‏‏‏‎‎‏‎‏‎‏‎‎‎‏‏‎‎‎‎‎‎‏‎‎‏‏‏‎‎‏‎‏‏‎‎‎Remove app‎‏‎‎‏‎"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‎‏‏‏‎‏‏‏‎‏‎‎‎‏‎‏‏‎‎‏‏‎‎‎‎‏‏‏‎‎‎‏‏‏‎‏‎‏‎‏‏‏‎‎‎‎‏‏‎‏‏‏‎‎Add outputs‎‏‎‎‏‎"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‏‎‏‎‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‎‏‎‏‎‎‏‎‎‎‏‎‏‎‎‏‏‎‏‏‎‏‏‎‎‏‏‎‏‏‎‏‎‎‎Group‎‏‎‎‏‎"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‎‎‎‎‏‏‏‏‎‎‏‏‎‏‏‎‏‏‎‏‏‎‏‎‏‎‎‏‎‎‎‎‏‏‏‎‎‏‏‎‎‏‏‎‏‎‏‎‎‎‎‏‎‎‏‎‎1 device selected‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index ad386ec..b3bc7da 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Si ingresas un PIN incorrecto en el próximo intento, se borrarán tu perfil de trabajo y sus datos."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Si ingresas una contraseña incorrecta en el próximo intento, se borrarán tu perfil de trabajo y sus datos."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Toca el sensor de huellas dactilares"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ícono de huella dactilar"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"No se reconoce el rostro. Usa la huella dactilar."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -401,7 +400,7 @@
     <string name="media_projection_action_text" msgid="3634906766918186440">"Comenzar ahora"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"No hay notificaciones"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"No hay notificaciones nuevas"</string>
-    <string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Desbloquea para ver notif. anteriores"</string>
+    <string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Desbloquea para ver notificaciones anteriores"</string>
     <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Tu padre o madre administra este dispositivo"</string>
     <string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Tu organización es propietaria de este dispositivo y podría controlar el tráfico de red"</string>
     <string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> es la organización propietaria de este dispositivo y podría controlar el tráfico de red"</string>
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Se agregó # control.}many{Se agregaron # controles.}other{Se agregaron # controles.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Quitados"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"¿Quieres agregar <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Si agregas la app de <xliff:g id="APPNAME">%s</xliff:g>, se incluirán controles y contenido en este panel. Algunas apps te permiten elegir qué controles mostrar aquí."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> puede elegir qué controles y contenido mostrar aquí."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"¿Quieres quitar los controles para <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Está en favoritos"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Está en favoritos en la posición <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"No está en favoritos"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Otros"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Agregar a controles de dispositivos"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Agregar"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Quitar"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Sugerido por <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Dispos. bloqueado"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"¿Quieres mostrar y controlar dispositivos desde la pantalla de bloqueo?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Puedes agregar controles para dispositivos externos a la pantalla de bloqueo.\n\nLa app de tu dispositivo podría permitirte controlar algunos dispositivos sin desbloquear el teléfono o la tablet.\n\nPuedes realizar cambios en cualquier momento en Configuración."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"¿Quieres controlar dispositivos desde la pantalla de bloqueo?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Puedes controlar algunos dispositivos sin desbloquear el teléfono o la tablet.\n\nLa app de tu dispositivo determina los que se pueden controlar de esa manera."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Puedes controlar algunos dispositivos sin desbloquear el teléfono o la tablet. La app de tu dispositivo determina los que se pueden controlar de esa manera."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"No, gracias"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Sí"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"El PIN contiene letras o símbolos"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Agregar controles"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Editar controles"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Agregar app"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Quitar app"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Agregar salidas"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Grupo"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Se seleccionó 1 dispositivo"</string>
@@ -1028,9 +1030,9 @@
     <string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Mantener presionado atajo"</string>
     <string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Cancelar"</string>
     <string name="rear_display_bottom_sheet_confirm" msgid="1507591562761552899">"Cambiar de pantalla ahora"</string>
-    <string name="rear_display_folded_bottom_sheet_title" msgid="3930008746560711990">"Desplegar teléfono"</string>
+    <string name="rear_display_folded_bottom_sheet_title" msgid="3930008746560711990">"Despliega el teléfono"</string>
     <string name="rear_display_unfolded_bottom_sheet_title" msgid="6291111173057304055">"¿Quieres cambiar de pantalla?"</string>
-    <string name="rear_display_folded_bottom_sheet_description" msgid="6842767125783222695">"Para obtener una resolución más alta, usa la cámara posterior"</string>
+    <string name="rear_display_folded_bottom_sheet_description" msgid="6842767125783222695">"Para obtener una resolución más alta, usa la cámara posterior."</string>
     <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"Para obtener una resolución más alta, gira el teléfono"</string>
     <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo plegable siendo desplegado"</string>
     <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo plegable siendo girado"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index e28f194..0fe2cdc 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -51,8 +51,8 @@
     <string name="usb_debugging_message" msgid="5794616114463921773">"La huella digital de tu clave RSA es:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="4003121804294739548">"Permitir siempre desde este ordenador"</string>
     <string name="usb_debugging_allow" msgid="1722643858015321328">"Permitir"</string>
-    <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Depuración USB no permitida"</string>
-    <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"El usuario con el que se ha iniciado sesión en este dispositivo no puede activar la depuración USB. Para utilizar esta función, inicia sesión con la cuenta de usuario principal."</string>
+    <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Depuración por USB no permitida"</string>
+    <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"El usuario con el que se ha iniciado sesión en este dispositivo no puede activar la depuración por USB. Para utilizar esta función, inicia sesión con la cuenta de usuario principal."</string>
     <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"¿Quieres cambiar el idioma del sistema a <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Otro dispositivo ha solicitado un cambio en el idioma del sistema"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Cambiar idioma"</string>
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Si vuelves a introducir un PIN incorrecto, tu perfil de trabajo y sus datos se eliminarán."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Si vuelves a introducir una contraseña incorrecta, tu perfil de trabajo y sus datos se eliminarán."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Toca el sensor de huellas digitales"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Icono de huella digital"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"No se reconoce la cara. Usa la huella digital."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -401,7 +400,7 @@
     <string name="media_projection_action_text" msgid="3634906766918186440">"Empezar ahora"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"No hay notificaciones"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"No hay notificaciones nuevas"</string>
-    <string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Desbloquea para ver notif. anteriores"</string>
+    <string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Desbloquea para ver notificaciones anteriores"</string>
     <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Este dispositivo lo gestionan tu padre o tu madre"</string>
     <string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"El dispositivo pertenece a tu organización, que puede monitorizar su tráfico de red"</string>
     <string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"El dispositivo pertenece a <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>, que puede monitorizar su tráfico de red"</string>
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# control añadido.}many{# controles añadidos.}other{# controles añadidos.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Quitado"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"¿Añadir <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Si añades <xliff:g id="APPNAME">%s</xliff:g>, podrá añadir controles y contenido a este panel. En algunas aplicaciones, puedes elegir qué controles aparecen aquí."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> puede elegir qué controles y contenido se muestran aquí."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"¿Quitar los controles de <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Añadido a favoritos"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Añadido a favoritos (posición <xliff:g id="NUMBER">%d</xliff:g>)"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Quitado de favoritos"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Otros"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Añadir a control de dispositivos"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Añadir"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Quitar"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Sugerido por <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Dispositivo bloqueado"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"¿Mostrar y controlar otros dispositivos en la pantalla de bloqueo?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Puedes añadir controles de tus dispositivos externos a la pantalla de bloqueo.\n\nPuede que la aplicación de tu dispositivo permita que controles algunos dispositivos sin desbloquear tu teléfono o tablet.\n\nPuedes hacer cambios en cualquier momento en Ajustes."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"¿Controlar dispositivos desde la pantalla de bloqueo?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Puedes controlar algunos dispositivos sin desbloquear tu teléfono o tablet.\n\nLa aplicación de tu dispositivo determina qué dispositivos se pueden controlar de esta forma."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Puedes controlar algunos dispositivos sin desbloquear tu teléfono o tablet. La aplicación de tu dispositivo determina qué dispositivos se pueden controlar de esta forma."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"No, gracias"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Sí"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"El PIN contiene letras o símbolos"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Añadir controles"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Editar controles"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Añadir aplicación"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Quitar aplicación"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Añadir dispositivos de salida"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Grupo"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 dispositivo seleccionado"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 5fc1abe..a1ccd82 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Kui sisestate järgmisel katsel vale PIN-koodi, kustutatakse teie tööprofiil ja selle andmed."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Kui sisestate järgmisel katsel vale parooli, kustutatakse teie tööprofiil ja selle andmed."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Puudutage sõrmejäljeandurit"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Sõrmejälje ikoon"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nägu ei õnnestu tuvastada. Kasutage sõrmejälge."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -401,7 +400,7 @@
     <string name="media_projection_action_text" msgid="3634906766918186440">"Alusta kohe"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Märguandeid pole"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Uusi märguandeid ei ole"</string>
-    <string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Uute märguannete nägemiseks avage"</string>
+    <string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Vanemate märguannete nägemiseks avage"</string>
     <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Seda seadet haldab sinu vanem"</string>
     <string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Teie organisatsioon on selle seadme omanik ja võib jälgida võrguliiklust"</string>
     <string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> on selle seadme omanik ja võib jälgida võrguliiklust"</string>
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Lisati # juhtnupp.}other{Lisati # juhtnuppu.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Eemaldatud"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Kas lisada <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Kui lisate rakenduse <xliff:g id="APPNAME">%s</xliff:g>, saab see sellele paneelile lisada juhtelemendid ja sisu. Mõnes rakenduses saate valida, millised juhtelemendid siin kuvatakse."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"Rakendus <xliff:g id="APPNAME">%s</xliff:g> saab valida, millised juhtelemendid ja milline sisu siin kuvatakse."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Kas soovite rakenduse <xliff:g id="APPNAME">%s</xliff:g> juhtelemendid eemaldada?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Lisatud lemmikuks"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Lisatud lemmikuks, positsioon <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Eemaldatud lemmikute hulgast"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Muu"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Seadmete juhtimisvidinate hulka lisamine"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Lisa"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Eemalda"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Soovitas <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Seade on lukustatud"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Kas soovite seadmete juhtelemente lukustuskuval kuvada ja kasutada?"</string>
-    <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Võite lukustuskuvale oma väliste seadmete juhtelemendid lisada.\n\nTeie seadmerakendus võib võimaldada teil teatud seadmeid ilma telefoni või tahvelarvutit avamata hallata.\n\nSaate igal ajal seadetes muudatusi teha."</string>
-    <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Kas soovite seadmeid lukustuskuva kaudu hallata?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Võite teatud seadmeid ilma telefoni või tahvelarvutit avamata hallata.\n\nTeie seadmerakendus määrab, milliseid seadmeid saab sel viisil hallata."</string>
+    <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Võite lukustuskuvale oma väliste seadmete juhtelemendid lisada.\n\nTeie seadmerakendus võib võimaldada teil teatud seadmeid ilma telefoni või tahvelarvutit avamata juhtida.\n\nSaate igal ajal seadetes muudatusi teha."</string>
+    <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Kas soovite seadmeid lukustuskuva kaudu juhtida?"</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Võite teatud seadmeid ilma telefoni või tahvelarvutit avamata juhtida. Teie seadmerakendus määrab, milliseid seadmeid saab sel viisil juhtida."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Tänan, ei"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Jah"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-kood sisaldab tähti või sümboleid"</string>
@@ -878,7 +879,8 @@
     <string name="controls_error_failed" msgid="960228639198558525">"Ilmnes viga, proovige uuesti"</string>
     <string name="controls_menu_add" msgid="4447246119229920050">"Lisa juhtelemente"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Muuda juhtelemente"</string>
-    <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Rakenduse lisamine"</string>
+    <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Lisa rakendus"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Eemalda rakendus"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Väljundite lisamine"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Grupp"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 seade on valitud"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index a3dcbb6..aec32a5 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Hurrengo saiakeran PINa oker idazten baduzu, laneko profila eta bertako datuak ezabatuko dira."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Hurrengo saiakeran pasahitza oker idazten baduzu, laneko profila eta bertako datuak ezabatuko dira."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Sakatu hatz-marken sentsorea"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Hatz-markaren ikonoa"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ezin da hauteman aurpegia. Erabili hatz-marka."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -197,8 +196,7 @@
     <skip />
     <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Jakinarazpenen panela."</string>
     <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Ezarpen bizkorrak."</string>
-    <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
-    <skip />
+    <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Ezarpen bizkorrak eta jakinarazpenen panela."</string>
     <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Pantaila blokeatzeko aukera."</string>
     <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Laneko pantaila blokeatua"</string>
     <string name="accessibility_desc_close" msgid="8293708213442107755">"Itxi"</string>
@@ -809,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Kontrolatzeko # aukera gehitu da.}other{Kontrolatzeko # aukera gehitu dira.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Kenduta"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> gehitu nahi duzu?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"<xliff:g id="APPNAME">%s</xliff:g> gehitzen duzunean, kontrolatzeko aukerak eta edukia gehi ditzake panelean. Aplikazio batzuetan, hemen zein kontrolatzeko aukera agertzen diren aukera dezakezu."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"Hemen zein kontrolatzeko aukera eta eduki agertzen diren aukera dezake <xliff:g id="APPNAME">%s</xliff:g> aplikazioak."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> kontrolatzeko aukerak kendu nahi dituzu?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Gogokoetan dago"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"<xliff:g id="NUMBER">%d</xliff:g>. gogokoa da"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Ez dago gogokoetan"</string>
@@ -827,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Beste bat"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Gehitu gailuak kontrolatzeko widgetetan"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Gehitu"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Kendu"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> aplikazioak iradoki du"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Gailua blokeatuta"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Gailuak pantaila blokeatuan ikusi eta kontrolatu nahi dituzu?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Kanpoko gailuak kontrolatzeko aukerak gehi ditzakezu pantaila blokeatuan.\n\nBaliteke telefonoa edo tableta desblokeatu gabe gailu batzuk kontrolatzeko baimena ematea gailuaren aplikazioak.\n\nAldaketak egiteko, joan Ezarpenak atalera."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Gailuak pantaila blokeatuan kontrolatu nahi dituzu?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Gailu batzuk telefonoa edo tableta desblokeatu gabe kontrola ditzakezu.\n\nGailuaren aplikazioak zehaztuko du zer gailu kontrola daitezkeen modu horretan."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Gailu batzuk telefonoa edo tableta desblokeatu gabe kontrola ditzakezu. Gailuaren aplikazioak zehaztuko du zein gailu kontrola daitezkeen modu horretan."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Ez, eskerrik asko"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Bai"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN kodeak hizkiak edo ikurrak ditu"</string>
@@ -880,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Gehitu aukerak"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Editatu aukerak"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Gehitu aplikazio bat"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Kendu aplikazioa"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Gehitu irteerak"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Taldea"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 gailu hautatu da"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index d345736..e8ff3bf 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -85,7 +85,7 @@
     <string name="screenshot_share_description" msgid="2861628935812656612">"هم‌رسانی نماگرفت"</string>
     <string name="screenshot_scroll_label" msgid="2930198809899329367">"ضبط محتوای بیشتر"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"رد کردن نماگرفت"</string>
-    <string name="screenshot_dismiss_work_profile" msgid="3101530842987697045">"رد کردن پیام نمایه کاری"</string>
+    <string name="screenshot_dismiss_work_profile" msgid="3101530842987697045">"بستن پیام نمایه کاری"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"پیش‌نمایش نماگرفت"</string>
     <string name="screenshot_top_boundary_pct" msgid="2520148599096479332">"مرز بالا <xliff:g id="PERCENT">%1$d</xliff:g> درصد"</string>
     <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"مرز پایین <xliff:g id="PERCENT">%1$d</xliff:g> درصد"</string>
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"اگر در تلاش بعدی‌ پین نادرستی وارد کنید، نمایه کاری شما و داده‌های آن حذف خواهند شد."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"اگر در تلاش بعدی‌ گذرواژه نادرستی وارد کنید، نمایه کاری شما و داده‌های آن حذف خواهند شد."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"حسگر اثر انگشت را لمس کنید"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"نماد اثر انگشت"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"چهره شناسایی نشد. درعوض از اثر انگشت استفاده کنید."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# کنترل اضافه شد.}one{# کنترل اضافه شد.}other{# کنترل اضافه شد.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"حذف شد"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> افزوده شود؟"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"وقتی <xliff:g id="APPNAME">%s</xliff:g> را اضافه می‌کنید، می‌تواند کنترل‌ها و محتوا را به این پانل اضافه کند. در برخی‌از برنامه‌ها می‌توانید انتخاب کنید چه کنترل‌هایی در اینجا نشان داده شود."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> می‌تواند انتخاب کند چه کنترل‌ها و محتوایی اینجا نشان داده شود."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"کنترل‌های <xliff:g id="APPNAME">%s</xliff:g> برداشته شود؟"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"به موارد دلخواه اضافه شد"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"اضافه‌شده به موارد دلخواه، جایگاه <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"حذف‌شده از موارد دلخواه"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"موارد دیگر"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"افزودن به کنترل‌های دستگاه"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"افزودن"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"برداشتن"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"پیشنهاد <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"دستگاه قفل است"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"امکان دیدن و کنترل دستگاه‌ها از صفحه قفل وجود داشته باشد؟"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"می‌توانید کنترل‌هایی برای دستگاه‌های خارجی به صفحه قفل اضافه کنید.\n\nبرنامه دستگاهتان ممکن است به شما اجازه دهد بعضی‌از دستگاه‌ها را بدون باز کردن قفل تلفن یا رایانه لوحی‌تان کنترل کنید.\n\nهرزمان بخواهید می‌توانید در «تنظیمات» تغییراتی اعمال کنید."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"امکان کنترل دستگاه‌ها از صفحه قفل وجود داشته باشد؟"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"می‌توانید بعضی‌از دستگاه‌ها را بدون باز کردن قفل تلفن یا رایانه لوحی‌تان کنترل کنید.\n\nبرنامه دستگاهتان تعیین می‌کند کدام دستگاه‌ها را می‌توان به این روش کنترل کرد."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"می‌توانید بعضی‌از دستگاه‌ها را بدون باز کردن قفل تلفن یا رایانه لوحی‌تان کنترل کنید. برنامه دستگاهتان تعیین می‌کند که کدام دستگاه‌ها را می‌توان با این روش کنترل کرد."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"نه متشکرم"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"بله"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"پین شامل حروف یا نماد است"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"افزودن کنترل‌ها"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"ویرایش کنترل‌ها"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"افزودن برنامه"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"برداشتن برنامه"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"افزودن خروجی"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"گروه"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"۱ دستگاه انتخاب شد"</string>
@@ -987,7 +989,7 @@
     <string name="clipboard_edit_text_done" msgid="4551887727694022409">"تمام"</string>
     <string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"کپی شد"</string>
     <string name="clipboard_edit_source" msgid="9156488177277788029">"از <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
-    <string name="clipboard_dismiss_description" msgid="3335990369850165486">"رد شدن نوشتار کپی‌شده"</string>
+    <string name="clipboard_dismiss_description" msgid="3335990369850165486">"بستن نوشتار کپی‌شده"</string>
     <string name="clipboard_edit_text_description" msgid="805254383912962103">"ویرایش نوشتار کپی‌شده"</string>
     <string name="clipboard_edit_image_description" msgid="8904857948976041306">"ویرایش تصویر کپی‌شده"</string>
     <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ارسال به دستگاهی در اطراف"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 8aaafe1..76f96e1 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Jos annat väärän PIN-koodin seuraavalla yrityskerralla, työprofiilisi ja sen data poistetaan."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Jos annat väärän salasanan seuraavalla yrityskerralla, työprofiilisi ja sen data poistetaan."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Kosketa sormenjälkitunnistinta"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Sormenjälkikuvake"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Kasvoja ei voi tunnistaa. Käytä sormenjälkeä."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -401,7 +400,7 @@
     <string name="media_projection_action_text" msgid="3634906766918186440">"Aloita nyt"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Ei ilmoituksia"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Ei uusia ilmoituksia"</string>
-    <string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Avaa lukitus uusia ilmoituksia varten"</string>
+    <string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Avaa lukitus niin näet ilmoituksia"</string>
     <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Vanhempasi ylläpitää tätä laitetta"</string>
     <string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Organisaatiosi omistaa laitteen ja voi valvoa verkkoliikennettä"</string>
     <string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> omistaa laitteen ja voi valvoa verkkoliikennettä"</string>
@@ -808,7 +807,9 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# säädin lisätty.}other{# säädintä lisätty.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Poistettu"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Lisätäänkö <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Kun <xliff:g id="APPNAME">%s</xliff:g> lisätään, se voi lisätä asetuksia ja sisältöä tähän paneeliin. Joissakin sovelluksissa voit valita, mitä asetukset näkyvät täällä."</string>
+    <!-- no translation found for controls_panel_authorization (7045551688535104194) -->
+    <skip />
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Poistetaanko säätimet: <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Lisätty suosikkeihin"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Lisätty suosikkeihin sijalle <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Poistettu suosikeista"</string>
@@ -826,12 +827,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Muu"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Lisää laitteiden hallintaan"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Lisää"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Poista"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Ehdottaja: <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Laite lukittu"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Haluatko nähdä ja hallita laitteita lukitusnäytöltä?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Voit lisätä lukitusnäytölle ohjaimia ulkoisia laitteita varten.\n\nLaitteen sovellus voi sallia joidenkin laitteiden ohjaamisen avaamatta puhelimen tai tabletin lukitusta.\n\nVoit milloin tahansa tehdä muutoksia asetuksissa."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Haluatko ohjata laitteita lukitusnäytöllä?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Voit ohjata joitakin laitteita avaamatta puhelimen tai tabletin lukitusta.\n\nRiippuu laitteen sovelluksesta, mitä laitteita voi ohjata näin."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Voit ohjata joitakin laitteita avaamatta puhelimen tai tabletin lukitusta. Riippuu laitesovelluksesta, mitä laitteita voi ohjata näin."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Ei kiitos"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Kyllä"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-koodi sisältää kirjaimia tai symboleja"</string>
@@ -879,6 +881,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Lisää säätimiä"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Muokkaa säätimiä"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Lisää sovellus"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Poista sovellus"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Lisää toistotapoja"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Ryhmä"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 laite valittu"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index d45677e..82d58e2 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Si vous entrez un NIP incorrect à la prochaine tentative, votre profil professionnel et ses données seront supprimés."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Si vous entrez un mot de passe incorrect à la prochaine tentative suivante, votre profil professionnel et ses données seront supprimés."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Touchez le capteur d\'empreintes digitales"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Icône d\'empreinte digitale"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Visage non reconnu. Utilisez plutôt l\'empreinte digitale."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -197,8 +196,7 @@
     <skip />
     <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Volet des notifications"</string>
     <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Paramètres rapides"</string>
-    <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
-    <skip />
+    <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Paramètres rapides et volet des notifications."</string>
     <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Écran de verrouillage"</string>
     <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Verrouillage de l\'écran du profil professionnel"</string>
     <string name="accessibility_desc_close" msgid="8293708213442107755">"Fermer"</string>
@@ -809,7 +807,9 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# commande ajoutée.}one{# commande ajoutée.}many{# de commandes ajoutées.}other{# commandes ajoutées.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Supprimé"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Ajouter <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Lorsque vous ajoutez <xliff:g id="APPNAME">%s</xliff:g>, elle peut ajouter des commandes et du contenu à ce panneau. Dans certaines applications, vous pouvez choisir les commandes qui s\'affichent ici."</string>
+    <!-- no translation found for controls_panel_authorization (7045551688535104194) -->
+    <skip />
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Retirer les commandes pour <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Ajouté aux favoris"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Ajouté aux favoris, en position <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Supprimé des favoris"</string>
@@ -827,12 +827,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Autre"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Ajouter aux commandes des appareils"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Ajouter"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Retirer"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Suggestion de <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Appareil verrouillé"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Afficher et contrôler les appareils à partir de l\'écran de verrouillage?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Vous pouvez ajouter des commandes pour vos appareils externes à l\'écran de verrouillage.\n\nL\'application de votre appareil peut vous permettre de contrôler certains appareils sans déverrouiller votre téléphone ou votre tablette.\n\nVous pouvez apporter des modifications à tout moment dans les paramètres."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Contrôler les appareils à partir de l\'écran de verrouillage?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Vous pouvez contrôler certains appareils sans déverrouiller votre téléphone ou votre tablette.\n\nL\'application de votre appareil détermine quels appareils peuvent être contrôlés de cette manière."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Vous pouvez contrôler certains appareils sans déverrouiller votre téléphone ou votre tablette. L\'application de votre appareil détermine quels appareils peuvent être contrôlés de cette manière."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Non merci"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Oui"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Le NIP contient des lettres ou des symboles"</string>
@@ -880,6 +881,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Ajouter des commandes"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Modifier des commandes"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Ajouter une application"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Retirer l\'application"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Ajouter des sorties"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Groupe"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Un appareil sélectionné"</string>
@@ -1044,14 +1046,9 @@
     <string name="call_from_work_profile_action" msgid="2937701298133010724">"Passer au profil professionnel"</string>
     <string name="call_from_work_profile_close" msgid="7927067108901068098">"Fermer"</string>
     <string name="lock_screen_settings" msgid="9197175446592718435">"Paramètres écran de verrouillage"</string>
-    <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) -->
-    <skip />
-    <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) -->
-    <skip />
-    <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) -->
-    <skip />
-    <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) -->
-    <skip />
-    <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) -->
-    <skip />
+    <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi non accessible"</string>
+    <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Appareil photo bloqué"</string>
+    <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Appareil photo et microphone bloqués"</string>
+    <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microphone bloqué"</string>
+    <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Mode Priorité activé"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 0d612aa..68c5b51 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Si vous saisissez un code incorrect lors de la prochaine tentative, votre profil professionnel et les données associées seront supprimés."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Si vous saisissez un mot de passe incorrect lors de la prochaine tentative, votre profil professionnel et les données associées seront supprimés."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Appuyez sur le lecteur d\'empreinte digitale"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Icône d\'empreinte digitale"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Visage non reconnu. Utilisez votre empreinte."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# commande ajoutée.}one{# commande ajoutée.}many{# commandes ajoutées.}other{# commandes ajoutées.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Supprimé"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Ajouter <xliff:g id="APPNAME">%s</xliff:g> ?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Lorsque vous ajoutez l\'appli <xliff:g id="APPNAME">%s</xliff:g>, elle peut ajouter des commandes et contenus dans ce panneau. Dans certaines applis, vous pouvez choisir les commandes à afficher ici."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> peut choisir les commandes et contenus à afficher ici."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Supprimer les commandes pour <xliff:g id="APPNAME">%s</xliff:g> ?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Ajouté aux favoris"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Ajouté aux favoris, en position <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Supprimé des favoris"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Autre"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Ajouter aux commandes des appareils"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Ajouter"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Supprimer"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Suggérée par <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Appareil verrouillé"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Afficher et contrôler les appareils depuis l\'écran de verrouillage ?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Vous pouvez ajouter des commandes pour vos appareils externes sur l\'écran de verrouillage.\n\nL\'appli de votre appareil peut vous autoriser à contrôler certains appareils sans déverrouiller votre téléphone ou tablette.\n\nVous pouvez apporter des modifications à tout moment dans les paramètres."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Contrôler des appareils depuis l\'écran de verrouillage ?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Vous pouvez contrôler certains appareils sans déverrouiller votre téléphone ou tablette.\n\nL\'appli de votre appareil détermine les appareils qui peuvent être contrôlés de cette manière."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Vous pouvez contrôler certains appareils sans déverrouiller votre téléphone ou tablette. L\'appli de votre appareil détermine les appareils qui peuvent être contrôlés de cette manière."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Non, merci"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Oui"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Le code contient des lettres ou des symboles"</string>
@@ -873,12 +874,13 @@
     <string name="controls_error_removed" msgid="6675638069846014366">"Introuvable"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Commande indisponible"</string>
     <string name="controls_error_removed_message" msgid="2885911717034750542">"Impossible d\'accéder à \"<xliff:g id="DEVICE">%1$s</xliff:g>\". Vérifiez l\'application <xliff:g id="APPLICATION">%2$s</xliff:g> pour vous assurer que la commande est toujours disponible et que les paramètres de l\'application n\'ont pas changé."</string>
-    <string name="controls_open_app" msgid="483650971094300141">"Ouvrir l\'application"</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Ouvrir l\'appli"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Impossible de charger l\'état"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Erreur. Veuillez réessayer."</string>
     <string name="controls_menu_add" msgid="4447246119229920050">"Ajouter des commandes"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Modifier des commandes"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Ajouter une appli"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Supprimer l\'application"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Ajouter des sorties"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Groupe"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 appareil sélectionné"</string>
@@ -958,7 +960,7 @@
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Données mobiles"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"Connecté"</string>
-    <string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Connectée temporairement"</string>
+    <string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Connexion temporaire"</string>
     <string name="mobile_data_poor_connection" msgid="819617772268371434">"Connexion médiocre"</string>
     <string name="mobile_data_off_summary" msgid="3663995422004150567">"Pas de connexion automatique des données mobiles"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"Aucune connexion"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index b1eb70b..32bd234 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Se indicas un PIN incorrecto no seguinte intento, eliminaranse o teu perfil de traballo e os datos asociados."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Se indicas un contrasinal incorrecto no seguinte intento, eliminaranse o teu perfil de traballo e os datos asociados."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Toca o sensor de impresión dixital"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Icona de impresión dixital"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Non se recoñeceu a cara. Usa a impresión dixital."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -401,7 +400,7 @@
     <string name="media_projection_action_text" msgid="3634906766918186440">"Iniciar agora"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Non hai notificacións"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Non hai notificacións novas"</string>
-    <string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Desbloquea para ver notificacións"</string>
+    <string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Desbloquea para ver máis notificacións"</string>
     <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"O teu pai ou nai xestiona este dispositivo"</string>
     <string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"A túa organización é propietaria deste dispositivo e pode controlar o tráfico de rede"</string>
     <string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> é a organización propietaria deste dispositivo e pode controlar o tráfico de rede"</string>
@@ -808,7 +807,9 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Engadiuse # control.}other{Engadíronse # controis.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Quitouse"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Queres engadir <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Cando engadas a aplicación <xliff:g id="APPNAME">%s</xliff:g>, poderá incluír controis e contido neste panel Nalgunhas aplicacións, podes escoller os controis que se mostrarán aquí."</string>
+    <!-- no translation found for controls_panel_authorization (7045551688535104194) -->
+    <skip />
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Queres quitar os controis de <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Está entre os controis favoritos"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Está entre os controis favoritos (posición: <xliff:g id="NUMBER">%d</xliff:g>)"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Non está entre os controis favoritos"</string>
@@ -826,12 +827,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Outra"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Engadir ao control de dispositivos"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Engadir"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Quitar"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Control suxerido por <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Disposit. bloqueado"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Queres que se mostren dispositivos na pantalla de bloqueo e poder controlalos desde ela?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Podes engadir á pantalla de bloqueo controis para os dispositivos externos.\n\nÉ posible que a aplicación do dispositivo che permita controlar algúns dispositivos sen desbloquear o teléfono ou a tableta.\n\nPodes realizar cambios cando queiras en Configuración."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Queres controlar dispositivos desde a pantalla de bloqueo?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Podes controlar algúns dispositivos sen desbloquear o teléfono ou a tableta.\n\nA aplicación do dispositivo determina os dispositivos que se poden controlar deste xeito."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Podes controlar algúns dispositivos sen desbloquear o teléfono ou a tableta. A aplicación do dispositivo determina os dispositivos que se poden controlar deste xeito."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Non, grazas"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Si"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"O PIN contén letras ou símbolos"</string>
@@ -879,6 +881,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Engadir controis"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Editar controis"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Engadir aplicación"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Quitar aplicación"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Engadir saídas"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Grupo"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Seleccionouse 1 dispositivo"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index cb2966e..4bf9078 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"જો તમે આગલા પ્રયત્નમાં ખોટો પિન દાખલ કરશો, તો તમારી કાર્યાલયની પ્રોફાઇલ અને તેનો ડેટા ડિલીટ કરવામાં આવશે."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"જો તમે આગલા પ્રયત્નમાં ખોટો પાસવર્ડ દાખલ કરશો, તો તમારી કાર્યાલયની પ્રોફાઇલ અને તેનો ડેટા ડિલીટ કરવામાં આવશે."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ફિંગરપ્રિન્ટના સેન્સરને સ્પર્શ કરો"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"ફિંગરપ્રિન્ટનું આઇકન"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ચહેરો ઓળખી શકતા નથી. તેને બદલે ફિંગરપ્રિન્ટ વાપરો."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# નિયંત્રણ ઉમેર્યું.}one{# નિયંત્રણ ઉમેર્યું.}other{# નિયંત્રણ ઉમેર્યા.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"કાઢી નાખ્યું"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> ઉમેરીએ?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"જ્યારે તમે <xliff:g id="APPNAME">%s</xliff:g> ઉમેરો, ત્યારે તે આ પૅનલમાં નિયંત્રણો અને કન્ટેન્ટ ઉમેરી શકે છે. કેટલીક ઍપમાં, અહીં કયા નિયંત્રણો દેખાય તે તમે પસંદ કરી શકો છો."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> પસંદ કરી શકે છે કે કયા નિયંત્રણો અને કન્ટેન્ટ અહીં બતાવવામાં આવે."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> માટે નિયંત્રણો કાઢી નાખીએ?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"મનપસંદમાં ઉમેર્યું"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"મનપસંદમાં ઉમેર્યું, સ્થાન <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"મનપસંદમાંથી કાઢી નાખ્યું"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"અન્ય"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"ડિવાઇસનાં નિયંત્રણોમાં ઉમેરો"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"ઉમેરો"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"કાઢી નાખો"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> દ્વારા સૂચવેલા"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"ડિવાઇસ લૉક કરેલું છે"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"લૉક સ્ક્રીનમાંથી ડિવાઇસ બતાવીએ અને નિયંત્રિત કરીએ?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"તમે તમારા બાહ્ય ડિવાઇસ માટેના નિયંત્રણો લૉક સ્ક્રીન પર ઉમેરી શકો છો.\n\nતમારી ડિવાઇસ ઍપ કદાચ તમને તમારો ફોન કે ટૅબ્લેટ અનલૉક કર્યા વિના અમુક ડિવાઇસ નિયંત્રિત કરવાની મંજૂરી આપી શકે.\n\nતમે ગમે ત્યારે સેટિંગમાં જઈને ફેરફાર કરી શકો છો."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"લૉક સ્ક્રીનમાંથી ડિવાઇસ નિયંત્રિત કરીએ?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"તમે તમારા ફોન કે ટૅબ્લેટને અનલૉક કર્યા વિના અમુક ડિવાઇસ નિયંત્રિત કરી શકો છો.\n\nતમારી ડિવાઇસ ઍપ નક્કી કરે છે કે આ રીતે કયા ડિવાઇસને નિયંત્રિત કરવા."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"તમે તમારા ફોન કે ટૅબ્લેટને અનલૉક કર્યા વિના અમુક ડિવાઇસ નિયંત્રિત કરી શકો છો. તમારી ડિવાઇસ ઍપ નક્કી કરે છે કે આ રીતે કયા ડિવાઇસને નિયંત્રિત કરવા."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"ના, આભાર"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"હા"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"પિનમાં અક્ષરો અથવા પ્રતીકોનો સમાવેશ થાય છે"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"નિયંત્રણો ઉમેરો"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"નિયંત્રણોમાં ફેરફાર કરો"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"ઍપ ઉમેરો"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"ઍપ કાઢી નાખો"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"આઉટપુટ ઉમેરો"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"ગ્રૂપ"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 ડિવાઇસ પસંદ કર્યું"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 7bbd2d1..cdd8ecb 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"अगर आप फिर से गलत पिन डालते हैं, तो आपकी वर्क प्रोफ़ाइल और उसका डेटा मिटा दिया जाएगा."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"अगर आप फिर से गलत पासवर्ड डालते हैं, तो आपकी वर्क प्रोफ़ाइल और उसका डेटा मिटा दिया जाएगा."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"फ़िंगरप्रिंट सेंसर को छुएं"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"फ़िंगरप्रिंट आइकॉन"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"चेहरे की पहचान नहीं हुई. फ़िंगरप्रिंट इस्तेमाल करें."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# कंट्रोल जोड़ा गया.}one{# कंट्रोल जोड़ा गया.}other{# कंट्रोल जोड़े गए.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"हटाया गया"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> को जोड़ना है?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"<xliff:g id="APPNAME">%s</xliff:g> को जोड़ने पर, वह इस पैनल पर कुछ कंट्रोल और कॉन्टेंट दिखा सकता है. कुछ ऐप्लिकेशन के लिए यह चुना जा सकता है कि वे इस पैनल पर कौनसे कंट्रोल दिखाएं."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> यह चुन सकता है कि इस पैनल पर कौनसे कंट्रोल और कॉन्टेंट दिखे."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> के लिए कंट्रोल हटाने हैं?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"पसंदीदा बनाया गया"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"पसंदीदा बनाया गया, क्रम संख्या <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"पसंदीदा से हटाया गया"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"अन्य"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"डिवाइस कंट्रोल में जोड़ें"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"जोड़ें"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"हटाएं"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> से मिला सुझाव"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"डिवाइस लॉक है"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"क्या डिवाइसों को लॉक स्क्रीन पर देखना है और उन्हें वहीं से कंट्रोल करना है?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"लॉक स्क्रीन पर अपने बाहरी डिवाइसों के लिए कंट्रोल जोड़े जा सकते हैं.\n\nअपने डिवाइस के ऐप्लिकेशन से कुछ डिवाइसों को कंट्रोल किया जा सकता है. इसके लिए, फ़ोन या टैबलेट को अनलॉक नहीं करना पड़ता.\n\nकिसी भी समय सेटिंग में जाकर बदलाव किए जा सकते हैं."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"क्या लॉक स्क्रीन से डिवाइसों को कंट्रोल करना है?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"फ़ोन या टैबलेट को अनलॉक किए बिना, कुछ डिवाइसों को कंट्रोल किया जा सकता है.\n\nआपके डिवाइस के ऐप्लिकेशन से यह तय किया जाता है कि किन डिवाइसों को इस तरह कंट्रोल किया जा सकता है."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"फ़ोन या टैबलेट को अनलॉक किए बिना, कुछ डिवाइसों को कंट्रोल किया जा सकता है. आपके डिवाइस के ऐप्लिकेशन से यह तय किया जाता है कि किन डिवाइसों को इस तरह कंट्रोल किया जा सकता है."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"नहीं, रहने दें"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"हां"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"पिन में अक्षर या चिह्न शामिल होते हैं"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"कंट्राेल जोड़ें"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"कंट्रोल में बदलाव करें"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"ऐप्लिकेशन जोड़ें"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"ऐप्लिकेशन हटाएं"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"आउटपुट जोड़ें"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"ग्रुप"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"एक डिवाइस चुना गया"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 5a9bf91..c53be7e 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ako pri sljedećem pokušaju unesete netočan PIN, izbrisat će se vaš poslovni profil i njegovi podaci."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Ako pri sljedećem pokušaju unesete netočnu zaporku, izbrisat će se vaš poslovni profil i njegovi podaci."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Dodirnite senzor otiska prsta"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikona otiska prsta"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Prepoznavanje lica nije uspjelo. Upotrijebite otisak prsta."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Dodana je # kontrola.}one{Dodana je # kontrola.}few{Dodane su # kontrole.}other{Dodano je # kontrola.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Uklonjeno"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Želite li dodati aplikaciju <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Kada dodate aplikaciju <xliff:g id="APPNAME">%s</xliff:g>, može dodati kontrole i sadržaj na ovu ploču. U nekim aplikacijama možete odabrati koje se kontrole prikazuju ovdje."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"U aplikaciji <xliff:g id="APPNAME">%s</xliff:g> možete odabrati koje se kontrole i sadržaj ovdje prikazuju."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Ukloniti kontrole za aplikaciju <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Dodano u favorite"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Dodano u favorite, položaj <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Uklonjeno iz favorita"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Drugo"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Dodavanje kontrolama uređaja"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Dodaj"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Ukloni"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Preporuka s kanala <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Uređaj je zaključan"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Prikazati uređaje i omogućiti upravljanje njima na zaključanom zaslonu?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Na zaključan zaslon možete dodati kontrole za svoje vanjske uređaje.\n\nAplikacija vašeg uređaja može vam dopustiti upravljanje nekim uređajima bez otključavanja telefona ili tableta.\n\nPromjene uvijek možete unijeti u Postavkama."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Upravljati uređajima na zaključanom zaslonu?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Nekim uređajima možete upravljati bez otključavanja telefona ili tableta.\n\nAplikacija vašeg uređaja odlučuje kojim se uređajima može upravljati na taj način."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Nekim uređajima možete upravljati bez otključavanja telefona ili tableta. Aplikacija vašeg uređaja odlučuje kojim se uređajima može upravljati na taj način."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Ne, hvala"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Da"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN sadrži slova ili simbole"</string>
@@ -873,12 +874,13 @@
     <string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrola nije dostupna"</string>
     <string name="controls_error_removed_message" msgid="2885911717034750542">"Nije moguće pristupiti uređaju: <xliff:g id="DEVICE">%1$s</xliff:g>. U aplikaciji <xliff:g id="APPLICATION">%2$s</xliff:g> provjerite je li kontrola i dalje dostupna te potvrdite da se postavke aplikacije nisu promijenile."</string>
-    <string name="controls_open_app" msgid="483650971094300141">"Otvori apl."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Otvori aplikaciju"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Status se ne može učitati"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Pogreška, pokušajte ponovo"</string>
     <string name="controls_menu_add" msgid="4447246119229920050">"Dodaj kontrole"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Uredi kontrole"</string>
-    <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Dodavanje aplikacije"</string>
+    <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Dodaj aplikaciju"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Ukloni aplikaciju"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Dodavanje izlaza"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Grupa"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Odabran je jedan uređaj"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 16761f5..d45491f 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Amennyiben helytelen PIN-kódot ad meg a következő kísérletnél, a rendszer törli munkaprofilját és a kapcsolódó adatokat."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Amennyiben helytelen jelszót ad meg a következő kísérletnél, a rendszer törli munkaprofilját és a kapcsolódó adatokat."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Érintse meg az ujjlenyomat-érzékelőt"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ujjlenyomat ikonja"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Az arc nem felismerhető. Használjon ujjlenyomatot."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# vezérlő hozzáadva.}other{# vezérlő hozzáadva.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Eltávolítva"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Hozzáadja a(z) <xliff:g id="APPNAME">%s</xliff:g> alkalmazást?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"A(z) <xliff:g id="APPNAME">%s</xliff:g> hozzáadását követően az alkalmazás vezérlőelemeket és tartalmakat adhat hozzá ehhez a panelhez. Egyes alkalmazásokban kiválasztható, hogy mely vezérlőelemek jelenjenek meg itt."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"A(z) <xliff:g id="APPNAME">%s</xliff:g> eldöntheti, milyen vezérlőket és tartalmakat jelenít meg itt."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Eltávolítja a(z) <xliff:g id="APPNAME">%s</xliff:g> vezérlőit?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Hozzáadva a kedvencekhez"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Hozzáadva a kedvencekhez <xliff:g id="NUMBER">%d</xliff:g>. helyen"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Eltávolítva a kedvencek közül"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Más"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Hozzáadás az eszközvezérlőkhöz"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Hozzáadás"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Eltávolítás"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> javasolta"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Az eszköz zárolva van"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Szeretne megtekinteni és vezérelni eszközöket a lezárási képernyőn?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Hozzáadhatja külső eszközök vezérlőit a lezárási képernyőhöz.\n\nAz eszközön lévő alkalmazás segítségével telefonja vagy táblagépe feloldása nélkül is vezérelhet néhány eszközt.\n\nA Beállításokban bármikor módosíthatja ezt a funkciót."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Szeretne eszközöket vezérelni a lezárási képernyőn?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Telefonja vagy táblagépe feloldása nélkül is vezérelhet néhány eszközt.\n\nAz eszközön lévő alkalmazással határozhatja meg, hogy mely eszközöket kívánja ilyen módon vezérelni."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Telefonja vagy táblagépe feloldása nélkül is vezérelhet néhány eszközt. Az eszközalkalmazás határozza meg, hogy mely eszközök vezérelhetők ilyen módon."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Most nem"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Igen"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"A PIN-kód betűket vagy szimbólumokat tartalmaz"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Vezérlők hozzáadása"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Vezérlők szerkesztése"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Alkalmazás hozzáadása"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Alkalmazás eltávolítása"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Kimenetek hozzáadása"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Csoport"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 eszköz kiválasztva"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 7d2d638..fe3f6de 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Հաջորդ փորձի ժամանակ սխալ PIN կոդ մուտքագրելու դեպքում աշխատանքային պրոֆիլը և դրա տվյալները կջնջվեն։"</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Հաջորդ փորձի ժամանակ սխալ գաղտնաբառ մուտքագրելու դեպքում աշխատանքային պրոֆիլը և դրա տվյալները կջնջվեն։"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Հպեք մատնահետքի սկաներին"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Մատնահետքի պատկերակ"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Դեմքը չի հաջողվում ճանաչել։ Օգտագործեք մատնահետքը։"</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,9 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Ավելացվեց կառավարման # տարր։}one{Ավելացվեց կառավարման # տարր։}other{Ավելացվեց կառավարման # տարր։}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Հեռացված է"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Ավելացնե՞լ <xliff:g id="APPNAME">%s</xliff:g> հավելվածը"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Եթե ավելացնեք <xliff:g id="APPNAME">%s</xliff:g> հավելվածը, այն կարող է կարգավորումներ և բովանդակություն ավելացնել այս վահանակում։ Որոշ հավելվածներում դուք կարող եք ընտրել, թե որ կարգավորումները ցուցադրվեն այստեղ։"</string>
+    <!-- no translation found for controls_panel_authorization (7045551688535104194) -->
+    <skip />
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Հեռացնե՞լ <xliff:g id="APPNAME">%s</xliff:g> հավելվածի համար կարգավորումները։"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Ավելացված է ընտրանիում"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Ավելացված է ընտրանիում, դիրքը՝ <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Հեռացված է ընտրանուց"</string>
@@ -826,12 +827,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Այլ"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Ավելացրեք սարքերի կառավարման տարրերում"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Ավելացնել"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Հեռացնել"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Առաջարկվել է <xliff:g id="APP">%s</xliff:g> հավելվածի կողմից"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Սարքը կողպված է"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Ցույց տա՞լ և կառավարել սարքերը կողպէկրանից"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Դուք կարող եք կարգավորումներ ավելացնել ձեր արտաքին սարքերի համար կողպէկրանին։\n\nՁեր սարքի հավելվածը կարող է ձեզ թույլ տալ որոշ սարքեր կառավարել առանց ապակողպելու հեռախոսը կամ պլանշետը։\n\nՑանկացած ժամանակ փոփոխություններ կատարեք Կարգավորումներում։"</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Կառավարե՞լ սարքերը կողպէկրանից"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Դուք կարող եք կառավարել որոշ սարքեր՝ առանց ապակողպելու ձեր հեռախոսը կամ պլանշետը։\n\nՁեր սարքի հավելվածը որոշում է, թե որ սարքերը կարելի է կառավարել այս եղանակով։"</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Դուք կարող եք կառավարել որոշ սարքեր առանց ապակողպելու ձեր հեռախոսը կամ պլանշետը։ Ձեր սարքի հավելվածը որոշում է, թե որ սարքերը կարելի է կառավարել այս եղանակով։"</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Ոչ, շնորհակալություն"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Այո"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN կոդը տառեր և նշաններ է պարունակում"</string>
@@ -879,6 +881,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Ավելացնել կառավարման տարրեր"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Փոփոխել կառավարման տարրերը"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Ավելացնել հավելված"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Հեռացնել հավելվածը"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Ավելացրեք մուտքագրման սարքեր"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Խումբ"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Ընտրված է 1 սարք"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 97e2316..6be304c 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Jika Anda memasukkan PIN yang salah saat mencoba lagi, profil kerja dan datanya akan dihapus."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Jika Anda memasukkan sandi yang salah saat mencoba lagi, profil kerja dan datanya akan dihapus."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Sentuh sensor sidik jari"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikon sidik jari"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Tidak dapat mengenali wajah. Gunakan sidik jari."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# kontrol ditambahkan.}other{# kontrol ditambahkan.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Dihapus"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Tambahkan <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Jika Anda menambahkannya, <xliff:g id="APPNAME">%s</xliff:g> dapat menambahkan kontrol dan konten ke panel ini. Di beberapa aplikasi, Anda dapat memilih kontrol yang akan muncul di sini."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> dapat memilih kontrol dan konten yang ditampilkan di sini."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Hapus kontrol untuk <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Difavoritkan"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Difavoritkan, posisi <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Batal difavoritkan"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Lainnya"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Tambahkan ke kontrol perangkat"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Tambahkan"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Hapus"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Disarankan oleh <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Perangkat terkunci"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Tampilkan dan kontrol perangkat dari layar kunci?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Anda dapat menambahkan kontrol untuk perangkat eksternal ke layar kunci.\n\nAplikasi perangkat Anda mungkin mengizinkan Anda mengontrol beberapa perangkat tanpa membuka kunci ponsel atau tablet.\n\nAnda dapat melakukan perubahan kapan saja di Setelan."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Kontrol perangkat dari layar kunci?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Anda dapat mengontrol beberapa perangkat eksternal tanpa membuka kunci ponsel atau tablet.\n\nAplikasi perangkat Anda menentukan perangkat yang dapat dikontrol dengan cara ini."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Anda dapat mengontrol beberapa perangkat tanpa membuka kunci ponsel atau tablet. Aplikasi perangkat Anda menentukan perangkat yang dapat dikontrol dengan cara ini."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Lain kali"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Ya"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN berisi huruf atau simbol"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Tambahkan kontrol"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Edit kontrol"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Tambahkan aplikasi"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Hapus aplikasi"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Tambahkan output"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Grup"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 perangkat dipilih"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 28f1fb6..ad803ca 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ef þú slærð inn rangt PIN-númer í næstu tilraun verður vinnusniðinu þínu og gögnum þess eytt."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Ef þú slærð inn rangt aðgangsorð í næstu tilraun verður vinnusniðinu þínu og gögnum þess eytt."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Snertu fingrafaralesarann"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Fingrafaratákn"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Andlit þekkist ekki. Notaðu fingrafar í staðinn."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# stýringu bætt við.}one{# stýringu bætt við.}other{# stýringum bætt við.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Fjarlægt"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Viltu bæta <xliff:g id="APPNAME">%s</xliff:g> við?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Þegar þú bætir <xliff:g id="APPNAME">%s</xliff:g> við getur það bætt stýringum og efni við þetta svæði. Í sumum forritum geturðu valið hvaða stýringar birtast hér."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> getur valið hvaða stýringar og efni birtist hér."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Fjarlægja stýringar fyrir <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Eftirlæti"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Eftirlæti, staða <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Fjarlægt úr eftirlæti"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Annað"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Bæta við tækjastjórnun"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Bæta við"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Fjarlægja"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Tillaga frá <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Tækið er læst"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Sjá og stjórna tækjum á lásskjánum?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Þú getur bætt við stýringum fyrir ytri tæki á lásskjáinn.\n\nForrit tækisins kann að leyfa þér að stjórna sumum tækjum án þess að taka símann eða spjaldtölvuna úr lás.\n\nÞú getur gert breytingar hvenær sem er í stillingunum."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Stjórna tækjum á lásskjá?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Þú getur stjórnað sumum tækjum án þess að taka símann eða spjaldtölvuna úr lás.\n\nForrit tækisins ákvarðar hvaða tækjum er hægt að stjórna á þennan hátt."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Þú getur stjórnað sumum tækjum án þess að taka símann eða spjaldtölvuna úr lás. Tækisforritið ákvarðar hvaða tækjum er hægt að stjórna á þennan hátt."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Nei, takk"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Já"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN inniheldur bókstafi eða tákn"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Bæta við stýringum"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Breyta stýringum"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Bæta við forriti"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Fjarlægja forrit"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Bæta við úttaki"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Hópur"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 tæki valið"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 5c8ce7c..7a2ace6 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Se al prossimo tentativo inserirai un PIN sbagliato, il tuo profilo di lavoro e i relativi dati verranno eliminati."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Se al prossimo tentativo inserirai una password sbagliata, il tuo profilo di lavoro e i relativi dati verranno eliminati."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Tocca il sensore di impronte"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Icona dell\'impronta"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Impossibile riconoscere il volto. Usa l\'impronta."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -401,7 +400,7 @@
     <string name="media_projection_action_text" msgid="3634906766918186440">"Avvia adesso"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Nessuna notifica"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Nessuna nuova notifica"</string>
-    <string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Sblocca per notifiche meno recenti"</string>
+    <string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Sblocca per vedere le notifiche meno recenti"</string>
     <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Questo dispositivo è gestito dai tuoi genitori"</string>
     <string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Questo dispositivo appartiene alla tua organizzazione, che potrebbe monitorare il traffico di rete"</string>
     <string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"Questo dispositivo appartiene a <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>, che potrebbe monitorare il traffico di rete"</string>
@@ -760,7 +759,7 @@
     <string name="slice_permission_deny" msgid="6870256451658176895">"Rifiuta"</string>
     <string name="auto_saver_title" msgid="6873691178754086596">"Tocca per programmare il Risparmio energetico"</string>
     <string name="auto_saver_text" msgid="3214960308353838764">"Attiva questa funzionalità se è probabile che la batteria si scarichi"</string>
-    <string name="no_auto_saver_action" msgid="7467924389609773835">"No grazie"</string>
+    <string name="no_auto_saver_action" msgid="7467924389609773835">"No, grazie"</string>
     <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump heap SysUI"</string>
     <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"In uso"</string>
     <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Le app stanno usando <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
@@ -808,7 +807,9 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# controllo aggiunto.}many{# controlli aggiunti.}other{# controlli aggiunti.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Rimosso"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Vuoi aggiungere <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Se la aggiungi, l\'app <xliff:g id="APPNAME">%s</xliff:g> può aggiungere controlli e contenuti a questo riquadro. In alcune app puoi scegliere quali controlli visualizzare qui."</string>
+    <!-- no translation found for controls_panel_authorization (7045551688535104194) -->
+    <skip />
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Vuoi rimuovere i controlli per l\'app <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Aggiunto ai preferiti"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Preferito, posizione <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Rimosso dai preferiti"</string>
@@ -826,12 +827,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Altro"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Aggiungi al controllo dei dispositivi"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Aggiungi"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Rimuovi"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Suggerito da <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Dispositivo bloccato"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Vuoi visualizzare e controllare i dispositivi dalla schermata di blocco?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Puoi aggiungere impostazioni alla schermata di blocco per i tuoi dispositivi esterni.\n\nL\'app del tuo dispositivo potrebbe consentirti di controllare alcuni dispositivi senza dover sbloccare il tuo telefono o tablet.\n\nPuoi apportare modifiche in qualsiasi momento in Impostazioni."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Vuoi controllare i dispositivi dalla schermata di blocco?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Puoi controllare alcuni dispositivi senza dover sbloccare il tuo telefono o tablet.\n\nL\'app del tuo dispositivo determina quali dispositivi possono essere controllati in questo modo."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Puoi controllare alcuni dispositivi senza sbloccare il telefono o il tablet. L\'app del dispositivo determina quali dispositivi possono essere controllati in questo modo."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"No, grazie"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Sì"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Il PIN contiene lettere o simboli"</string>
@@ -879,6 +881,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Aggiungi controlli"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Modifica controlli"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Aggiungi app"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Rimuovi l\'app"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Aggiungi uscite"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Gruppo"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 dispositivo selezionato"</string>
@@ -957,7 +960,7 @@
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Telefonata in corso"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Dati mobili"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
-    <string name="mobile_data_connection_active" msgid="944490013299018227">"Connessione attiva"</string>
+    <string name="mobile_data_connection_active" msgid="944490013299018227">"Connessa"</string>
     <string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Connessa temporaneamente"</string>
     <string name="mobile_data_poor_connection" msgid="819617772268371434">"Connessione debole"</string>
     <string name="mobile_data_off_summary" msgid="3663995422004150567">"Nessuna connessione dati mobili automatica"</string>
@@ -1040,7 +1043,7 @@
     <string name="video_camera" msgid="7654002575156149298">"Videocamera"</string>
     <string name="call_from_work_profile_title" msgid="6991157106804289643">"Impossibile chiamare da questo profilo"</string>
     <string name="call_from_work_profile_text" msgid="3458704745640229638">"Le norme di lavoro ti consentono di fare telefonate soltanto dal profilo di lavoro"</string>
-    <string name="call_from_work_profile_action" msgid="2937701298133010724">"Passa a profilo di lavoro"</string>
+    <string name="call_from_work_profile_action" msgid="2937701298133010724">"Passa al profilo di lavoro"</string>
     <string name="call_from_work_profile_close" msgid="7927067108901068098">"Chiudi"</string>
     <string name="lock_screen_settings" msgid="9197175446592718435">"Impostazioni schermata di blocco"</string>
     <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi non disponibile"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index c2392d9..b4cb279 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"הזנה של קוד אימות שגוי בניסיון הבא תגרום למחיקת פרופיל העבודה והנתונים המשויכים אליו."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"הזנת סיסמה שגויה בניסיון הבא תגרום למחיקת פרופיל העבודה והנתונים המשויכים אליו."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"יש לגעת בחיישן טביעות האצבע"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"סמל טביעת אצבע"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"לא ניתן לזהות את הפנים. יש להשתמש בטביעת אצבע במקום."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{נוסף אמצעי בקרה אחד (#).}one{נוספו # אמצעי בקרה.}two{נוספו # אמצעי בקרה.}other{נוספו # אמצעי בקרה.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"הוסר"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"להוסיף את <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"כשמוסיפים את האפליקציה <xliff:g id="APPNAME">%s</xliff:g>, היא תוכל להוסיף אמצעי בקרה ותוכן לחלונית הזו. חלק מהאפליקציות מאפשרות לבחור אילו אמצעי בקרה יוצגו כאן."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"האפליקציה <xliff:g id="APPNAME">%s</xliff:g> יכולה לבחור אילו אמצעי בקרה ותוכן להראות כאן."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"להסיר את אמצעי הבקרה של <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"סומן כמועדף"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"סומן כמועדף, במיקום <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"הוסר מהמועדפים"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"אחר"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"הוספה לפקדי המכשירים"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"הוספה"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"הסרה"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"הוצע על-ידי <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"המכשיר נעול"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"להציג מכשירים ולאפשר שליטה בהם במסך הנעילה?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"ניתן להוסיף למסך הנעילה אמצעי בקרה למכשירים החיצוניים.\n\nיכול להיות שהאפליקציה של המכשיר תאפשר לך לשלוט בחלק מהמכשירים בלי לבטל את הנעילה של הטלפון או הטאבלט.\n\nאפשר לבצע שינויים בכל שלב בהגדרות."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"לאפשר שליטה במכשירים במסך הנעילה?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"אפשר לשלוט בחלק מהמכשירים בלי לבטל את הנעילה של הטלפון או הטאבלט.\n\nהמכשירים שניתן לשלוט בהם באופן הזה נקבעים באפליקציה של המכשיר."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"אפשר לשלוט בחלק מהמכשירים בלי לבטל את הנעילה של הטלפון או הטאבלט. המכשירים שניתן לשלוט בהם באופן הזה נקבעים באפליקציה לניהול מכשיר המשני."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"לא תודה"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"כן"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"קוד האימות מכיל אותיות או סמלים"</string>
@@ -873,12 +874,13 @@
     <string name="controls_error_removed" msgid="6675638069846014366">"לא נמצא"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"הפקד לא זמין"</string>
     <string name="controls_error_removed_message" msgid="2885911717034750542">"לא ניתן להתחבר אל <xliff:g id="DEVICE">%1$s</xliff:g>. יש לבדוק את האפליקציה <xliff:g id="APPLICATION">%2$s</xliff:g> כדי לוודא שהפקד עדיין זמין ושהגדרות האפליקציה לא השתנו."</string>
-    <string name="controls_open_app" msgid="483650971094300141">"לפתיחת האפליקציה"</string>
+    <string name="controls_open_app" msgid="483650971094300141">"פתיחת האפליקציה"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"לא ניתן לטעון את הסטטוס"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"שגיאה, יש לנסות שוב"</string>
     <string name="controls_menu_add" msgid="4447246119229920050">"הוספת פקדים"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"עריכת פקדים"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"הוספת אפליקציה"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"הסרת האפליקציה"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"הוספת מכשירי פלט"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"קבוצה"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"נבחר מכשיר אחד"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 630f1f8..656a9f3 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"PIN をあと 1 回間違えると、仕事用プロファイルと関連データが削除されます。"</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"パスワードをあと 1 回間違えると、仕事用プロファイルと関連データが削除されます。"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"指紋認証センサーをタッチ"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"指紋アイコン"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"顔を認識できません。指紋認証を使用してください。"</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,9 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# 件のコントロールを追加しました。}other{# 件のコントロールを追加しました。}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"削除済み"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> を追加しますか?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"<xliff:g id="APPNAME">%s</xliff:g> を追加することで、コントロールやコンテンツをこのパネルに追加できます。一部のアプリでは、ここに表示されるコントロールを選択できます。"</string>
+    <!-- no translation found for controls_panel_authorization (7045551688535104194) -->
+    <skip />
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> のコントロールを削除しますか?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"お気に入りに追加済み"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"お気に入りに追加済み、位置: <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"お気に入りから削除済み"</string>
@@ -826,12 +827,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"その他"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"デバイス コントロールに追加"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"追加"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"削除"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> によるおすすめ"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"デバイス: ロック状態"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"ロック画面にデバイスを表示して操作しますか?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"ロック画面に外部デバイスのコントロールを追加できます。\n\nスマートフォンやタブレットのロックを解除しなくても、デバイスアプリによって一部のデバイスを操作できる可能性があります。\n\n設定でいつでも変更できます。"</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"ロック画面でデバイスを操作しますか?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"スマートフォンやタブレットのロックを解除しなくても一部のデバイスを操作できます。\n\nこの方法でどのデバイスを操作できるかは、デバイスアプリが判断します。"</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"スマートフォンやタブレットのロックを解除しなくても、一部のデバイスを操作できます。この方法でどのデバイスを操作できるかは、デバイスアプリが判断します。"</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"いいえ"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"はい"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN に英字や記号を含める"</string>
@@ -879,6 +881,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"コントロールを追加"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"コントロールを編集"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"アプリを追加"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"アプリを削除"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"出力の追加"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"グループ"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"選択したデバイス: 1 台"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 76277bd..7188d68 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"შემდეგი მცდელობისას PIN-კოდის არასწორად შეყვანის შემთხვევაში, თქვენი სამსახურის პროფილი და მისი მონაცემები წაიშლება."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"შემდეგი მცდელობისას პაროლის არასწორად შეყვანის შემთხვევაში, თქვენი სამსახურის პროფილი და მისი მონაცემები წაიშლება."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"შეეხეთ თითის ანაბეჭდის სენსორს"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"თითის ანაბეჭდის ხატულა"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"სახის ამოცნობა ვერ ხერხდება. სანაცვლოდ თითის ანაბეჭდი გამოიყენეთ."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{დაემატა მართვის # საშუალება.}other{დაემატა მართვის # საშუალება.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"ამოიშალა"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"გსურთ <xliff:g id="APPNAME">%s</xliff:g>-ის დამატება?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"როდესაც <xliff:g id="APPNAME">%s</xliff:g>-ს ამატებთ, მან შეიძლება დაამატოს მართვის საშუალებები და კონტენტი მოცემულ არეში. ზოგიერთ აპში შეგიძლიათ აირჩიოთ, რომელი მართვის საშუალებები უნდა გამოჩნდეს აქ."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g>-ს შეუძლია აირჩიოს, მართვის რომელი საშუალებები და კონტენტი უნდა გამოჩნდეს აქ."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"ამოიშალოს <xliff:g id="APPNAME">%s</xliff:g>-ის მართვის საშუალებები?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"რჩეულებშია"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"რჩეულებშია, პოზიციაზე <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"რჩეულებიდან ამოღებულია"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"სხვა"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"მოწყობილ. მართვის საშუალებებში დამატება"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"დამატება"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"ამოშლა"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"შემოთავაზებულია <xliff:g id="APP">%s</xliff:g>-ის მიერ"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"მოწყობილ. ჩაკეტილია"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"გსურთ მოწყობილობების ჩვენება და მართვა ჩაკეტილი ეკრანიდან?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"შეგიძლიათ დაამატოთ მართვის საშუალებები გარე მოწყობილობებისთვის, ჩაკეტილ ეკრანზე.\n\nთქვენი მოწყობილობის აპმა შეიძლება მოგცეთ საშუალება, მართოთ ზოგიერთი მოწყობილობა თქვენი ტელეფონის ან ტაბლეტის განბლოკვის გარეშე.\n\nცვლილებების შეტანა ნებისმიერ დროს შეგიძლიათ პარამეტრებიდან."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"გსურთ მოწყობილობების მართვა ჩაკეტილი ეკრანიდან?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"შეგიძლიათ ზოგიერთი მოწყობილობის მართვა ტელეფონის ან ტაბლეტის განბლოკვის გარეშე.\n\nთქვენი მოწყობილობის აპი განსაზღვრავს, რომელი მოწყობილობა იმართება ამგვარად."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"შეგიძლიათ ზოგიერთი მოწყობილობის მართვა ტელეფონის ან ტაბლეტის განბლოკვის გარეშე. თქვენი მოწყობილობის აპი განსაზღვრავს, რომელი მოწყობილობები იმართება ამგვარად."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"არა, გმადლობთ"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"დიახ"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-კოდი შეიცავს ასოებს ან სიმბოლოებს"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"მართვის საშუალებების დამატება"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"მართვის საშუალებათა რედაქტირება"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"აპის დამატება"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"აპის ამოშლა"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"მედია-გამოსავლების დამატება"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"ჯგუფი"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"არჩეულია 1 მოწყობილობა"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index d7c24cf..915c5bc 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Келесі әрекет кезінде қате PIN кодын енгізсеңіз, жұмыс профиліңіз бен оның деректері жойылады."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Келесі әрекет кезінде қате құпия сөз енгізсеңіз, жұмыс профиліңіз бен оның деректері жойылады."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Саусақ ізін оқу сканерін түртіңіз"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Саусақ ізі белгішесі"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Бет танылмады. Орнына саусақ ізін пайдаланыңыз."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# басқару элементі қосылды.}other{# басқару элементі қосылды.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Өшірілді"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> қолданбасын қосу керек пе?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"<xliff:g id="APPNAME">%s</xliff:g> қолданбасын қосқан кезде, басқару элементтері мен контент осы панельге енгізіледі. Кейбір қолданбада басқару элементтерінің қайсысы осы жерде көрсетілетінін таңдай аласыз."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> қолданбасы осы жерде көрсетілетін басқару құралдары мен контентті таңдай алады."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> қолданбасының басқару элементтері жойылсын ба?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Таңдаулыларға қосылды"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Таңдаулыларға қосылды, <xliff:g id="NUMBER">%d</xliff:g>-позиция"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Таңдаулылардан алып тасталды"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Басқа"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Құрылғы басқару элементтеріне қосу"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Енгізу"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Өшіру"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ұсынған"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Құрылғы құлыпталды."</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Құрылғыларды құлып экранынан көрсетуге және басқаруға рұқсат берілсін бе?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Сыртқы құрылғылардың басқару элементтерін құлып экранына қоса аласыз.\n\nҚұрылғы қолданбасы кейбір құрылғыларды телефонның немесе планшеттің құлпын ашпастан басқаруға мүмкіндік береді.\n\n\"Параметрлер\" бөлімінде кез келген уақытта өзгерістер енгізуге болады."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Құрылғылар құлып экранынан басқарылсын ба?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Кейбір құрылғыларды телефонның немесе планшеттің құлпын ашпастан басқара аласыз.\n\nҚұрылғы қолданбасы осылай басқаруға болатын құрылғыларды анықтайды."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Кейбір құрылғыларды телефонның немесе планшеттің құлпын ашпастан басқара аласыз. Құрылғы қолданбасы осылай басқаруға болатын құрылғыларды анықтайды."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Жоқ, рақмет"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Иә"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN коды әріптерден не таңбалардан құралады."</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Басқару элементтерін қосу"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Басқару элементтерін өзгерту"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Қолданба қосу"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Қолданбаны өшіру"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Шығыс сигналдарды қосу"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Топ"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 құрылғы таңдалды."</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 521302e..e853bea 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"ប្រសិនបើអ្នក​បញ្ចូលកូដ PIN មិនត្រឹមត្រូវ នៅពេលព្យាយាមបញ្ចូល​លើកក្រោយ កម្រងព័ត៌មានការងាររបស់អ្នក និងទិន្នន័យរបស់កម្រងព័ត៌មាននេះ​នឹងត្រូវបានលុប។"</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"ប្រសិនបើអ្នក​បញ្ចូលពាក្យសម្ងាត់មិន​ត្រឹមត្រូវ នៅពេលព្យាយាមបញ្ចូល​លើកក្រោយ កម្រងព័ត៌មាន​ការងាររបស់អ្នក និងទិន្នន័យ​របស់កម្រងព័ត៌មាននេះនឹងត្រូវបានលុប។"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ប៉ះ​ឧបករណ៍​ចាប់ស្នាម​ម្រាមដៃ"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"រូប​ស្នាម​ម្រាមដៃ"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"មិនអាចសម្គាល់មុខបានទេ។ សូមប្រើស្នាមម្រាមដៃជំនួសវិញ។"</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{បានបញ្ចូល​ការគ្រប់គ្រង #។}other{បានបញ្ចូល​ការគ្រប់គ្រង #។}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"បានដកចេញ"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"បញ្ចូល <xliff:g id="APPNAME">%s</xliff:g> ឬ?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"នៅពេលអ្នកបញ្ចូល <xliff:g id="APPNAME">%s</xliff:g> កម្មវិធីនេះអាចបញ្ចូលការគ្រប់គ្រង និងខ្លឹមសារទៅផ្ទាំងនេះបាន។ ក្នុងកម្មវិធីមួយចំនួន អ្នកអាចជ្រើសរើសឱ្យការគ្រប់គ្រងណាខ្លះបង្ហាញនៅទីនេះបាន។"</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> អាចជ្រើសរើសឱ្យ​ការគ្រប់គ្រង និងខ្លឹមសារណាខ្លះ​បង្ហាញនៅទីនេះ។"</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"ដកការគ្រប់គ្រងសម្រាប់ <xliff:g id="APPNAME">%s</xliff:g> ចេញឬ?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"បានដាក់ជា​សំណព្វ"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"បានដាក់ជា​សំណព្វ ទីតាំង​ទី <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"បានដកចេញ​ពី​សំណព្វ"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ផ្សេងៗ"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"បញ្ចូល​ទៅក្នុងផ្ទាំងគ្រប់គ្រងឧបករណ៍"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"បញ្ចូល"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"ដកចេញ"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"បាន​ណែនាំដោយ <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"បានចាក់សោ​ឧបករណ៍"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"បង្ហាញ និង​គ្រប់គ្រង​ឧបករណ៍ពី​អេក្រង់ចាក់សោឬ?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"អ្នកអាចបញ្ចូល​ការគ្រប់គ្រង​សម្រាប់ឧបករណ៍​ខាងក្រៅ​របស់អ្នក​ទៅក្នុងអេក្រង់​ចាក់សោបាន។\n\nកម្មវិធី​ឧបករណ៍​របស់អ្នក​អាចអនុញ្ញាតឱ្យអ្នក​គ្រប់គ្រង​ឧបករណ៍​មួយចំនួន ដោយមិនចាំបាច់​ដោះសោ​ទូរសព្ទ ឬ​ថេប្លេត​របស់អ្នក។\n\nអ្នកអាចធ្វើការផ្លាស់ប្ដូរ​បានគ្រប់ពេល​នៅក្នុង​ការកំណត់។"</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"គ្រប់គ្រង​ឧបករណ៍ពី​អេក្រង់ចាក់សោឬ?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"អ្នកអាចគ្រប់គ្រង​ឧបករណ៍​មួយចំនួន ដោយមិនចាំបាច់​ដោះសោ​ទូរសព្ទ ឬថេប្លេត​របស់អ្នក។\n\nកម្មវិធី​ឧបករណ៍​របស់អ្នក​កំណត់ឧបករណ៍​ដែលអាចត្រូវបានគ្រប់គ្រង​តាមវិធីនេះ។"</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"អ្នកអាចគ្រប់គ្រង​ឧបករណ៍​មួយចំនួន ដោយមិនចាំបាច់​ដោះសោ​ទូរសព្ទ ឬថេប្លេត​របស់អ្នក។ កម្មវិធី​ឧបករណ៍​របស់អ្នក​កំណត់ឧបករណ៍​ដែលអាចត្រូវបានគ្រប់គ្រង​តាមវិធីនេះ។"</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"ទេ អរគុណ"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"បាទ/ចាស"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"កូដ PIN មាន​អក្សរ ឬនិមិត្តសញ្ញា"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"បញ្ចូល​ផ្ទាំងគ្រប់គ្រង"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"កែ​ផ្ទាំងគ្រប់គ្រង"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"បញ្ចូល​កម្មវិធី"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"ដក​កម្មវិធី​ចេញ"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"បញ្ចូល​ឧបករណ៍​មេឌៀ"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"ក្រុម"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"បានជ្រើសរើស​ឧបករណ៍ 1"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 9f47e94..361e35c 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"ಮುಂದಿನ ಪ್ರಯತ್ನದಲ್ಲಿ ನೀವು ತಪ್ಪಾದ ಪಿನ್ ನಮೂದಿಸಿದರೆ, ನಿಮ್ಮ ಉದ್ಯೋಗದ ಪ್ರೊಫೈಲ್ ಮತ್ತು ಅದರ ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"ಮುಂದಿನ ಪ್ರಯತ್ನದಲ್ಲಿ ನೀವು ತಪ್ಪಾದ ಪಾಸ್‌ವರ್ಡ್ ನಮೂದಿಸಿದರೆ, ನಿಮ್ಮ ಉದ್ಯೋಗದ ಪ್ರೊಫೈಲ್ ಮತ್ತು ಅದರ ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್‌‌ ಅನ್ನು ಸ್ಪರ್ಶಿಸಿ"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಐಕಾನ್"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ಮುಖ ಗುರುತಿಸಲಾಗುತ್ತಿಲ್ಲ ಬದಲಿಗೆ ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಬಳಸಿ."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# ನಿಯಂತ್ರಣವನ್ನು ಸೇರಿಸಲಾಗಿದೆ.}one{# ನಿಯಂತ್ರಣಗಳನ್ನು ಸೇರಿಸಲಾಗಿದೆ.}other{# ನಿಯಂತ್ರಣಗಳನ್ನು ಸೇರಿಸಲಾಗಿದೆ.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"ತೆಗೆದುಹಾಕಲಾಗಿದೆ"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> ಅನ್ನು ಸೇರಿಸಬೇಕೆ?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"ನೀವು <xliff:g id="APPNAME">%s</xliff:g> ಅನ್ನು ಸೇರಿಸಿದಾಗ, ಅದು ಈ ಪ್ಯಾನೆಲ್‌ಗೆ ನಿಯಂತ್ರಣಗಳು ಮತ್ತು ವಿಷಯವನ್ನು ಸೇರಿಸಬಹುದು. ಕೆಲವು ಆ್ಯಪ್‌ಗಳಲ್ಲಿ, ಇಲ್ಲಿ ಯಾವ ನಿಯಂತ್ರಣಗಳು ಕಾಣಿಸಬೇಕು ಎಂಬುದನ್ನು ನೀವು ಆಯ್ಕೆಮಾಡಬಹುದು."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> ಯಾವ ಕಂಟ್ರೋಲ್‌ಗಳು ಮತ್ತು ವಿಷಯವನ್ನು ತೋರಿಸುತ್ತದೆ ಎಂಬುದನ್ನು ಆಯ್ಕೆಮಾಡಬಹುದು."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> ಗಾಗಿ ನಿಯಂತ್ರಣಗಳನ್ನು ತೆಗೆದುಹಾಕಬೇಕೆ?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"ಮೆಚ್ಚಲಾಗಿರುವುದು"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"ಮೆಚ್ಚಲಾಗಿರುವುದು, ಸ್ಥಾನ <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"ಮೆಚ್ಚಿನದಲ್ಲದ್ದು"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ಇತರ"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"ಸಾಧನ ನಿಯಂತ್ರಣಗಳಿಗೆ ಸೇರಿಸಿ"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"ಸೇರಿಸಿ"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"ತೆಗೆದುಹಾಕಿ"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ಆ್ಯಪ್ ಸೂಚಿಸಿದೆ"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"ಸಾಧನ ಲಾಕ್ ಆಗಿದೆ"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"ಲಾಕ್ ಸ್ಕ್ರೀನ್‌ನಿಂದ ಸಾಧನಗಳನ್ನು ತೋರಿಸಬೇಕೇ ಹಾಗೂ ನಿಯಂತ್ರಿಸಬೇಕೇ?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"ಲಾಕ್ ಸ್ಕ್ರೀನ್‌ನಲ್ಲಿ ನಿಮ್ಮ ಬಾಹ್ಯ ಸಾಧನಗಳಿಗಾಗಿ ನೀವು ನಿಯಂತ್ರಣಗಳನ್ನು ಸೇರಿಸಬಹುದು.\n\nನಿಮ್ಮ ಫೋನ್ ಅಥವಾ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡದೆಯೇ ನಿಮ್ಮ ಕೆಲವು ಸಾಧನಗಳನ್ನು ನಿಯಂತ್ರಿಸಲು ನಿಮ್ಮ ಸಾಧನ ಆ್ಯಪ್ ಅನುಮತಿಸಬಹುದು.\n\nಸೆಟ್ಟಿಂಗ್‌ಗಳಲ್ಲಿ ನೀವು ಯಾವಾಗ ಬೇಕಾದರೂ ಬದಲಾವಣೆಗಳನ್ನು ಮಾಡಬಹುದು."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"ಲಾಕ್ ಸ್ಕ್ರೀನ್‌ನಿಂದ ಸಾಧನಗಳನ್ನು ನಿಯಂತ್ರಿಸಬೇಕೇ?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"ನಿಮ್ಮ ಫೋನ್ ಅಥವಾ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡದೆಯೇ ನಿಮ್ಮ ಕೆಲವು ಸಾಧನಗಳನ್ನು ನೀವು ನಿಯಂತ್ರಿಸಬಹುದು.\n\nಈ ವಿಧಾನದ ಮೂಲಕ ಯಾವ ಸಾಧನಗಳನ್ನು ನಿಯಂತ್ರಿಸಬಹುದು ಎಂಬುದನ್ನು ನಿಮ್ಮ ಸಾಧನದ ಆ್ಯಪ್ ನಿರ್ಧರಿಸುತ್ತದೆ."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"ನಿಮ್ಮ ಫೋನ್ ಅಥವಾ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡದೆಯೇ ನಿಮ್ಮ ಕೆಲವು ಸಾಧನಗಳನ್ನು ನೀವು ಕಂಟ್ರೋಲ್ ಮಾಡಬಹುದು. ಈ ವಿಧಾನದ ಮೂಲಕ ಯಾವ ಸಾಧನಗಳನ್ನು ಕಂಟ್ರೋಲ್ ಮಾಡಬಹುದು ಎಂಬುದನ್ನು ನಿಮ್ಮ ಸಾಧನದ ಆ್ಯಪ್ ನಿರ್ಧರಿಸುತ್ತದೆ."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"ಬೇಡ"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"ಹೌದು"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"ಪಿನ್ ಅಕ್ಷರಗಳು ಅಥವಾ ಸಂಕೇತಗಳನ್ನು ಒಳಗೊಂಡಿದೆ"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"ನಿಯಂತ್ರಣಗಳನ್ನು ಸೇರಿಸಿ"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"ನಿಯಂತ್ರಣಗಳನ್ನು ಎಡಿಟ್ ಮಾಡಿ"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"ಆ್ಯಪ್ ಅನ್ನು ಸೇರಿಸಿ"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"ಆ್ಯಪ್ ತೆಗೆದುಹಾಕಿ"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"ಔಟ್‌ಪುಟ್‌ಗಳನ್ನು ಸೇರಿಸಿ"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"ಗುಂಪು"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 ಸಾಧನವನ್ನು ಆಯ್ಕೆ ಮಾಡಲಾಗಿದೆ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 9d90602..be4ef11 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"다음번 시도에서 잘못된 PIN을 입력하면 직장 프로필 및 관련 데이터가 삭제됩니다."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"다음번 시도에서 잘못된 비밀번호를 입력하면 직장 프로필 및 관련 데이터가 삭제됩니다."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"지문 센서를 터치하세요."</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"지문 아이콘"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"얼굴을 인식할 수 없습니다. 대신 지문을 사용하세요."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{설정이 #개 추가되었습니다.}other{설정이 #개 추가되었습니다.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"삭제됨"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g>을(를) 추가할까요?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"<xliff:g id="APPNAME">%s</xliff:g> 앱을 추가하면 이 패널에 컨트롤과 콘텐츠가 추가됩니다. 일부 앱에서는 여기 표시되는 컨트롤을 선택할 수 있습니다."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g>에서 여기에 표시되는 컨트롤 및 콘텐츠를 선택할 수 있습니다."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> 컨트롤을 삭제할까요?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"즐겨찾기에 추가됨"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"즐겨찾기에 추가됨, 위치 <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"즐겨찾기에서 삭제됨"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"기타"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"기기 컨트롤에 추가"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"추가"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"삭제"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g>에서 제안"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"기기 잠김"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"잠금 화면에서 기기를 표시하고 제어하시겠습니까?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"외부 기기에 대한 제어 권한을 잠금 화면에 추가할 수 있습니다.\n\n기기 앱을 사용하여 휴대전화나 태블릿의 잠금을 해제하지 않고 해당 기기를 제어할 수도 있습니다.\n\n언제든지 설정에서 옵션을 변경할 수 있습니다."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"잠금 화면에서 기기를 제어하시겠습니까?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"휴대전화나 태블릿의 화면을 잠금 해제하지 않고 해당 기기를 제어할 수 있습니다.\n\n기기 앱에 이러한 방식으로 어떤 기기를 제어할 수 있는지 표시됩니다."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"일부 기기의 경우 휴대전화나 태블릿을 잠금 해제하지 않고 해당 기기를 제어할 수 있습니다. 기기 앱에 어떤 기기를 이러한 방식으로 제어할 수 있는지 표시됩니다."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"아니요"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"예"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN에 문자나 기호가 포함됨"</string>
@@ -877,8 +878,9 @@
     <string name="controls_error_generic" msgid="352500456918362905">"통계를 로드할 수 없음"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"오류. 다시 시도하세요."</string>
     <string name="controls_menu_add" msgid="4447246119229920050">"컨트롤 추가"</string>
-    <string name="controls_menu_edit" msgid="890623986951347062">"컨트롤 수정"</string>
+    <string name="controls_menu_edit" msgid="890623986951347062">"제어 설정 수정"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"앱 추가"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"앱 삭제"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"출력 추가"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"그룹"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"기기 1대 선택됨"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 0b89bd3..c67b751 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Эгер PIN кодду дагы бир жолу туура эмес киргизсеңиз, жумуш профилиңиз жана андагы маалыматтын баары өчөт."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Эгер сырсөздү дагы бир жолу туура эмес киргизсеңиз, жумуш профилиңиз жана андагы маалыматтын баары өчөт."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Манжа изинин сенсорун басыңыз"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Манжа изинин сүрөтчөсү"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Жүз таанылбай жатат. Манжа изин колдонуңуз."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# көзөмөл кошулду.}other{# көзөмөл кошулду.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Өчүрүлдү"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> кошулсунбу?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"<xliff:g id="APPNAME">%s</xliff:g> колдонмосун кошсоңуз, ал бул панелге башкаруу элементтерин жана контентти кошо алат. Айрым колдонмолордо бул жерде көрүнүүчү башкаруу элементтерин тандай аласыз."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> бул жерде көрсөтүлө турган башкаруу элементтерин жана контентти тандай алат."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> башкаруу элементтери өчүрүлсүнбү?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Сүйүктүүлөргө кошулду"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Сүйүктүүлөргө <xliff:g id="NUMBER">%d</xliff:g>-позицияга кошулду"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Сүйүктүүлөрдөн чыгарылды"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Башка"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Түзмөктү башкаруу элементтерине кошуу"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Кошуу"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Өчүрүү"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> сунуштайт"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Түзмөк кулпуланды"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Түзмөктөрдү кулпуланган экрандан көрүп, көзөмөлдөйсүзбү?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Тышкы түзмөктөрүңүздү көзөмөлдөө каражаттарын кулпу экранына кошо аласыз.\n\nТүзмөгүңүздүн колдонмосу айрым түзмөктөрдү телефонуңуздун же планшетиңиздин кулпусун ачпастан көзөмөлдөөгө уруксат бериши мүмкүн.\n\nКаалаган убакта Жөндөөлөрдөн өзгөртүүлөрдү жасай аласыз."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Түзмөктөрдү кулпуланган экрандан көзөмөлдөйсүзбү?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Айрым түзмөктөрдү телефонуңуздун же планшетиңиздин кулпусун ачпастан көзөмөлдөй аласыз.\n\nКайсы түзмөктөрдү ушул жол менен көзөмөлдөөгө болорун түзмөгүңүздүн колдонмосу аныктайт."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Айрым түзмөктөрдү телефонуңуздун же планшетиңиздин кулпусун ачпастан көзөмөлдөй аласыз. Кайсы түзмөктөрдү ушул жол менен көзөмөлдөөгө болорун түзмөгүңүздүн колдонмосу аныктайт."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Жок, рахмат"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Ооба"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN код тамгалардан же символдордон турат"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Башкаруу элементтерин кошуу"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Башкаруу элементтерин түзөтүү"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Колдонмо кошуу"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Колдонмону алып салуу"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Медиа түзмөктөрдү кошуу"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Топ"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 түзмөк тандалды"</string>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index 4f38e60..908aac4 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -66,4 +66,8 @@
 
     <dimen name="controls_header_horizontal_padding">12dp</dimen>
     <dimen name="controls_content_margin_horizontal">16dp</dimen>
+
+    <!-- Bouncer user switcher margins -->
+    <dimen name="bouncer_user_switcher_view_mode_user_switcher_bottom_margin">0dp</dimen>
+    <dimen name="bouncer_user_switcher_view_mode_view_flipper_bottom_margin">0dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 85910fd..01e35cf 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"ຫາກທ່ານໃສ່ລະຫັດ PIN ຜິດໃນຄວາມພະຍາຍາມເທື່ອຕໍ່ໄປ, ໂປຣໄຟລ໌ບ່ອນເຣັດວຽກຂອງທ່ານ ແລະ ຂໍ້ມູນຂອງມັນຈະຖືກລຶບອອກ."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"ຫາກທ່ານໃສ່ລະຫັດຜິດໃນຄວາມພະຍາຍາມເທື່ອຕໍ່ໄປ, ໂປຣໄຟລ໌ບ່ອນເຣັດວຽກຂອງທ່ານ ແລະ ຂໍ້ມູນຂອງມັນຈະຖືກລຶບອອກ."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ແຕະໃສ່ເຊັນເຊີລາຍນິ້ວມື"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"ໄອຄອນລາຍນິ້ວມື"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ບໍ່ສາມາດຈຳແນກໜ້າໄດ້. ກະລຸນາໃຊ້ລາຍນິ້ວມືແທນ."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{ເພີ່ມ # ການຄວບຄຸມແລ້ວ.}other{ເພີ່ມ # ການຄວບຄຸມແລ້ວ.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"ລຶບອອກແລ້ວ"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"ເພີ່ມ <xliff:g id="APPNAME">%s</xliff:g> ບໍ?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"ເມື່ອທ່ານເພີ່ມ <xliff:g id="APPNAME">%s</xliff:g>, ມັນຈະສາມາດເພີ່ມການຄວບຄຸມ ແລະ ເນື້ອຫາໃສ່ແຜງນີ້ໄດ້. ໃນບາງແອັບ, ທ່ານສາມາດເລືອກວ່າຈະໃຫ້ສ່ວນຄວບຄຸມໃດສະແດງຂຶ້ນຢູ່ບ່ອນນີ້ໄດ້."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> ສາມາດເລືອກໄດ້ວ່າການຄວບຄຸມ ແລະ ເນື້ອຫາໃດຈະສະແດງຢູ່ບ່ອນນີ້."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"ລຶບການຄວບຄຸມສຳລັບ <xliff:g id="APPNAME">%s</xliff:g> ອອກບໍ?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"ເພີ່ມລາຍການທີ່ມັກແລ້ວ"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"ເພີ່ມລາຍການທີ່ມັກແລ້ວ, ຕຳແໜ່ງ <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"ຍົກເລີກລາຍການທີ່ມັກແລ້ວ"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ອື່ນໆ"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"ເພີ່ມໃສ່ການຄວບຄຸມອຸປະກອນ"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"ເພີ່ມ"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"ລຶບອອກ"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"ແນະນຳໂດຍ <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"ອຸປະກອນຖືກລັອກໄວ້"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"ສະແດງ ແລະ ຄວບຄຸມອຸປະກອນຈາກໜ້າຈໍລັອກບໍ?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"ທ່ານສາມາດເພີ່ມການຄວບຄຸມສຳລັບອຸປະກອນພາຍນອກຂອງທ່ານໄປໃສ່ໜ້າຈໍລັອກໄດ້.\n\nແອັບອຸປະກອນຂອງທ່ານອາດອະນຸຍາດໃຫ້ທ່ານຄວບຄຸມອຸປະກອນບາງຢ່າງໄດ້ໂດຍບໍ່ຕ້ອງປົດລັອກໂທລະສັບ ຫຼື ແທັບເລັດຂອງທ່ານ.\n\nທ່ານສາມາດປ່ຽນແປງຕອນໃດກໍໄດ້ໃນການຕັ້ງຄ່າ."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"ຄວບຄຸມອຸປະກອນຈາກໜ້າຈໍລັອກບໍ?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"ທ່ານສາມາດຄວບຄຸມອຸປະກອນບາງຢ່າງໄດ້ໂດຍບໍ່ຕ້ອງປົດລັອກໂທລະສັບ ຫຼື ແທັບເລັດຂອງທ່ານ.\n\nແອັບອຸປະກອນຂອງທ່ານຈະກຳນົດວ່າອຸປະກອນໃດສາມາດຖືກຄວບຄຸມດ້ວຍວິທີນີ້ໄດ້."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"ທ່ານສາມາດຄວບຄຸມອຸປະກອນບາງຢ່າງໄດ້ໂດຍບໍ່ຕ້ອງປົດລັອກໂທລະສັບ ຫຼື ແທັບເລັດຂອງທ່ານ. ແອັບຈັດການອຸປະກອນຂອງທ່ານຈະກຳນົດວ່າອຸປະກອນໃດສາມາດຖືກຄວບຄຸມດ້ວຍວິທີນີ້ໄດ້."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"ບໍ່, ຂອບໃຈ"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"ແມ່ນແລ້ວ"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN ປະກອບມີຕົວອັກສອນ ຫຼື ສັນຍາລັກ"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"ເພີ່ມການຄວບຄຸມ"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"ແກ້ໄຂການຄວບຄຸມ"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"ເພີ່ມແອັບ"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"ລຶບແອັບອອກ"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"ເພີ່ມເອົ້າພຸດ"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"ກຸ່ມ"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"ເລືອກ 1 ອຸປະກອນແລ້ວ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 8161025..893c978 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Jei kitu bandymu įvesite netinkamą PIN kodą, darbo profilis ir jo duomenys bus ištrinti."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Jei kitu bandymu įvesite netinkamą slaptažodį, darbo profilis ir jo duomenys bus ištrinti."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Palieskite piršto antspaudo jutiklį"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Piršto antspaudo piktograma"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Veidas neatpažintas. Naudokite kontrolinį kodą."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Pridėtas # valdiklis.}one{Pridėtas # valdiklis.}few{Pridėti # valdikliai.}many{Pridėta # valdiklio.}other{Pridėta # valdiklių.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Pašalinta"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Pridėti „<xliff:g id="APPNAME">%s</xliff:g>“?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Pridėjus programą „<xliff:g id="APPNAME">%s</xliff:g>“, ji gali pridėti valdiklių ir turinio prie šio skydelio. Kai kuriose programose galite pasirinkti, kurie valdikliai čia rodomi."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"„<xliff:g id="APPNAME">%s</xliff:g>“ gali pasirinkti, kuriuos valdiklius ir turinį čia rodyti."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Pašalinti „<xliff:g id="APPNAME">%s</xliff:g>“ valdiklius?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Įtraukta į mėgstamiausius"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Įtraukta į mėgstamiausius, padėtis: <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Pašalinta iš mėgstamiausių"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Kita"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Pridėjimas prie įrenginio valdiklių"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Pridėti"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Pašalinti"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Siūlo „<xliff:g id="APP">%s</xliff:g>“"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Įrenginys užrakintas"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Rodyti ir valdyti įrenginius užrakinimo ekrane?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Galite pridėti išorinių įrenginių valdiklių užrakinimo ekrane.\n\nĮrenginio programoje gali būti leidžiama valdyti tam tikrus įrenginius neatrakinus telefono ar planšetinio kompiuterio.\n\nGalite bet kada pakeisti „Nustatymų“ skiltyje."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Valdyti įrenginius užrakinimo ekrane?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Galite valdyti tam tikrus išorinius įrenginius neatrakinę telefono ar planšetinio kompiuterio.\n\nĮrenginio programoje nustatoma, kuriuos įrenginius galima valdyti tokiu būdu."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Galite valdyti kai kuriuos išorinius įrenginius neatrakinę telefono ar planšetinio kompiuterio. Įrenginio programoje nustatoma, kuriuos įrenginius galima valdyti tokiu būdu."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Ne, ačiū"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Taip"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN kodą sudaro raidės arba simboliai"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Pridėti valdiklių"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Redaguoti valdiklius"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Pridėti programą"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Pašalinti programą"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Išvesčių pridėjimas"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Grupė"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Pasirinktas 1 įrenginys"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 72ca071..befcfbe 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ja nākamajā mēģinājumā ievadīsiet nepareizu PIN, jūsu darba profils un ar to saistītie dati tiks dzēsti."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Ja nākamajā mēģinājumā ievadīsiet nepareizu paroli, jūsu darba profils un ar to saistītie dati tiks dzēsti."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Pieskarieties pirksta nospieduma sensoram"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Pirksta nospieduma ikona"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nevar atpazīt seju. Lietojiet pirksta nospiedumu."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Pievienota # vadīkla.}zero{Pievienotas # vadīklas.}one{Pievienota # vadīkla.}other{Pievienotas # vadīklas.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Noņemta"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Vai pievienot lietotni <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Ja pievienosiet lietotni <xliff:g id="APPNAME">%s</xliff:g>, tā varēs pievienot vadīklas un saturu šim panelim. Dažās lietotnēs varat izvēlēties, kuras vadīklas šeit rādīt."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> var izvēlēties, kuras vadīklas un saturu šeit rādīt."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Vai noņemt vadīklas lietotnei <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Pievienota izlasei"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Pievienota izlasei, <xliff:g id="NUMBER">%d</xliff:g>. pozīcija"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Noņemta no izlases"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Cita"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Pievienošana ierīču vadīklām"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Pievienot"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Noņemt"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Ieteica: <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Ierīce ir bloķēta"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Vai skatīt un kontrolēt ierīces no bloķēšanas ekrāna?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Varat pievienot bloķēšanas ekrānam vadīklas, ar kurām kontrolēt savas ārējās ierīces.\n\nJūsu ierīces lietotne var ļaut jums kontrolēt dažas ierīces, neatbloķējot tālruni vai planšetdatoru.\n\nVarat jebkurā laikā veikt izmaiņas iestatījumos."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Vai kontrolēt ierīces no bloķēšanas ekrāna?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Varat kontrolēt dažas ierīces, neatbloķējot tālruni vai planšetdatoru.\n\nJūsu ierīces lietotne nosaka, kuras ierīces var šādi kontrolēt."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Varat kontrolēt noteiktas ierīces, neatbloķējot tālruni vai planšetdatoru. Jūsu ierīces lietotne nosaka, kuras ierīces varat šādi kontrolēt."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Nē, paldies"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Jā"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN ietver burtus vai simbolus."</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Pievienot vadīklas"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Rediģēt vadīklas"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Pievienot lietotni"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Noņemt lietotni"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Izejas ierīču pievienošana"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Grupa"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Atlasīta viena ierīce"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index e168121..ca1ac64 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ако внесете погрешен PIN при следниот обид, работниот профил и неговите податоци ќе се избришат."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Ако внесете погрешна лозинка при следниот обид, работниот профил и неговите податоци ќе се избришат."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Допрете го сензорот за отпечатоци"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Икона за отпечаток"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Не се препознава ликот. Користете отпечаток."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Додадена е # контрола.}one{Додадени се # контрола.}other{Додадени се # контроли.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Отстранета"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Да се додаде <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Кога ќе ја додадете <xliff:g id="APPNAME">%s</xliff:g>, таа ќе може да додава контроли и содржини на таблава. Кај некои апликации, може да изберете кои контроли ќе се прикажуваат тука."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> може да избере кои контроли и содржини се прикажуваат овде."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Да се отстранат контролите за <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Омилена"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Омилена, позиција <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Неомилена"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Друга"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Додајте во контроли за уредите"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Додај"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Отстрани"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Предложено од <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Уредот е заклучен"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Да се прикажуваат и контролираат уреди од заклучениот екран?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Може да додадете контроли за надворешните уреди на заклучениот екран.\n\nАпликацијата на уредот може да ви дозволи да контролирате одредени уреди без да го отклучувате телефонот или таблетот.\n\nМоже да извршите промени во секое време во „Поставки“."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Да се контролираат уреди од заклучен екран?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Може да контролирате одредени уреди без отклучување на телефонот или таблетот.\n\nАпликацијата на вашиот уред одредува кои уреди може да се контролираат вака."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Може да контролирате одредени уреди без отклучување на телефонот или таблетот. Апликацијата на вашиот уред одредува кои уреди може да се контролираат вака."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Не, фала"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Да"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-кодот содржи букви или симболи"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Додајте контроли"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Изменете ги контролите"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Додајте апликација"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Отстранете ја апликацијата"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Додајте излези"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Група"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Избран е 1 уред"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 36c1a5f..102d81e 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"അടുത്ത തവണയും നിങ്ങൾ തെറ്റായ പിൻ നൽകിയാൽ, നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈലും അതിന്റെ ഡാറ്റയും ഇല്ലാതാക്കപ്പെടും."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"അടുത്ത തവണയും നിങ്ങൾ തെറ്റായ പാസ്‌വേഡ് നൽകിയാൽ, നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈലും അതിന്റെ ഡാറ്റയും ഇല്ലാതാക്കപ്പെടും."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ഫിംഗർപ്രിന്റ് സെൻസർ സ്‌പർശിക്കുക"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"ഫിംഗർപ്രിന്റ് ഐക്കൺ"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"മുഖം തിരിച്ചറിയാനായില്ല. പകരം ഫിംഗർപ്രിന്റ് ഉപയോഗിക്കൂ."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# നിയന്ത്രണം ചേർത്തു.}other{# നിയന്ത്രണങ്ങൾ ചേർത്തു.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"നീക്കം ചെയ്‌തു"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> ചേർക്കണോ?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"നിങ്ങൾ <xliff:g id="APPNAME">%s</xliff:g> ചേർത്താൽ, അതിന് ഈ പാനലിലേക്ക് നിയന്ത്രണങ്ങളും ഉള്ളടക്കവും ചേർക്കാനാകും. ചില ആപ്പുകളിൽ, ഇവിടെ ഏത് നിയന്ത്രണങ്ങൾ ദൃശ്യമാകണമെന്ന് നിങ്ങൾക്ക് തിരഞ്ഞെടുക്കാനാകും."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"ഏതൊക്കെ നിയന്ത്രണങ്ങളും ഉള്ളടക്കവും ഇവിടെ ദൃശ്യമാകണമെന്ന് <xliff:g id="APPNAME">%s</xliff:g> എന്നതിന് തിരഞ്ഞെടുക്കാനാകും."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> എന്നതിനുള്ള നിയന്ത്രണങ്ങൾ നീക്കം ചെയ്യണോ?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"പ്രിയപ്പെട്ടതാക്കി"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"പ്രിയപ്പെട്ടതാക്കി, സ്ഥാനം <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"പ്രിയപ്പെട്ടതല്ലാതാക്കി"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"മറ്റുള്ളവ"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"ഉപകരണ നിയന്ത്രണങ്ങളിലേക്ക് ചേർക്കുക"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"ചേർക്കുക"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"നീക്കം ചെയ്യുക"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> നിർദ്ദേശിച്ചത്"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"ഉപകരണം ലോക്ക് ചെയ്തു"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"ലോക്ക് സ്‌ക്രീനിൽ നിന്ന് ഉപകരണങ്ങൾ കാണിക്കുകയും നിയന്ത്രിക്കുകയും ചെയ്യണോ?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"നിങ്ങളുടെ ബാഹ്യ ഉപകരണങ്ങൾക്കുള്ള നിയന്ത്രണങ്ങൾ ലോക്ക് സ്‌ക്രീനിലേക്ക് ചേർക്കാനാകും.\n\nനിങ്ങളുടെ ഫോണോ ടാബ്‌ലെറ്റോ അൺലോക്ക് ചെയ്യാതെ ചില ഉപകരണങ്ങൾ നിയന്ത്രിക്കാൻ നിങ്ങളുടെ ഉപകരണ ആപ്പ് അനുവദിച്ചേക്കും.\n\nനിങ്ങൾക്ക് ക്രമീകരണത്തിൽ ഏതുസമയത്തും മാറ്റങ്ങൾ വരുത്താം."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"ലോക്ക് സ്‌ക്രീനിൽ നിന്ന് ഉപകരണങ്ങൾ നിയന്ത്രിക്കണോ?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"നിങ്ങളുടെ ഫോണോ ടാബ്‌ലെറ്റോ അൺലോക്ക് ചെയ്യാതെ ചില ഉപകരണങ്ങൾ നിയന്ത്രിക്കാം.\n\nഏതൊക്കെ ഉപകരണങ്ങൾ ഈ രീതിയിൽ നിയന്ത്രിക്കാൻ കഴിയുമെന്ന് നിങ്ങളുടെ ഉപകരണ ആപ്പ് നിർണ്ണയിക്കുന്നു."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"നിങ്ങളുടെ ഫോണോ ടാബ്‌ലെറ്റോ അൺലോക്ക് ചെയ്യാതെ ചില ഉപകരണങ്ങൾ നിയന്ത്രിക്കാം. ഏതൊക്കെ ഉപകരണങ്ങൾ ഈ രീതിയിൽ നിയന്ത്രിക്കാൻ കഴിയുമെന്ന് നിങ്ങളുടെ ഉപകരണ ആപ്പ് നിർണ്ണയിക്കുന്നു."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"വേണ്ട, നന്ദി"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"ഉവ്വ്"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"പിന്നിൽ അക്ഷരങ്ങളോ ചിഹ്നങ്ങളോ അടങ്ങിയിരിക്കുന്നു"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"നിയന്ത്രണങ്ങൾ ചേർക്കുക"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"നിയന്ത്രണങ്ങൾ എഡിറ്റ് ചെയ്യുക"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"ആപ്പ് ചേർക്കുക"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"ആപ്പ് നീക്കം ചെയ്യുക"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"ഔട്ട്പുട്ടുകൾ ചേർക്കുക"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"ഗ്രൂപ്പ്"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"ഒരു ഉപകരണം തിരഞ്ഞെടുത്തു"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 9042bf5..020fe3f 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Та дараагийн оролдлогоор буруу ПИН оруулбал таны ажлын профайлыг өгөгдөлтэй нь цуг устгах болно."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Та дараагийн оролдлогоор буруу нууц үг оруулбал таны ажлын профайлыг өгөгдөлтэй нь цуг устгах болно."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Хурууны хээ мэдрэгчид хүрэх"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Хурууны хээний дүрс тэмдэг"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Царай таних боломжгүй. Оронд нь хурууны хээ ашигла"</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# хяналт нэмсэн.}other{# хяналт нэмсэн.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Хассан"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g>-г нэмэх үү?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Та <xliff:g id="APPNAME">%s</xliff:g>-г нэмэх үед энэ нь уг түр зуурын самбарт тохиргоо болон контент нэмэх боломжтой. Зарим аппад та энд ямар тохиргоог харуулахыг сонгох боломжтой."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> аль хяналт болон контент энд харагдахыг сонгож болно."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g>-н тохиргоог хасах уу?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Дуртай гэж тэмдэглэсэн"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"<xliff:g id="NUMBER">%d</xliff:g>-р байршилд дуртай гэж тэмдэглэсэн"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Дургүй гэж тэмдэглэсэн"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Бусад"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Төхөөрөмжийн хяналт руу нэмэх"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Нэмэх"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Хасах"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g>-н санал болгосон"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Төхөөрөмжийг түгжсэн"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Түгжигдсэн дэлгэцээс төхөөрөмжүүдийг харуулж, хянах уу?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Та түгжигдсэн дэлгэцэд гадаад төхөөрөмжүүдийнхээ хяналтыг нэмэх боломжтой.\n\nТаны төхөөрөмжийн апп танд утас эсвэл таблетынхаа түгжээг тайлахгүйгээр зарим төхөөрөмжийг хянах боломжийг олгож магадгүй.\n\nТа хүссэн үедээ Тохиргоонд өөрчлөлт хийж болно."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Төхөөрөмжүүдийг түгжигдсэн дэлгэцээс хянах уу?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Та утас эсвэл таблетынхаа түгжээг тайлахгүйгээр зарим төхөөрөмжийг хянах боломжтой.\n\nТаны төхөөрөмжийн апп энэ аргаар ямар төхөөрөмжүүдийг хянах боломжтойг тодорхойлно."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Та утас эсвэл таблетынхаа түгжээг тайлахгүйгээр зарим төхөөрөмжийг хянах боломжтой. Таны төхөөрөмжийн апп энэ аргаар ямар төхөөрөмжүүдийг хянах боломжтойг тодорхойлно."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Үгүй, баярлалаа"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Тийм"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"ПИН нь үсэг эсвэл дүрс тэмдэгт агуулдаг"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Хяналт нэмэх"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Хяналтыг өөрчлөх"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Апп нэмэх"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Аппыг хасах"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Гаралт нэмэх"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Бүлэг"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 төхөөрөмж сонгосон"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 43fed36..13111e2 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -144,10 +144,10 @@
     <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>
-    <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"चेहऱ्याने अनलॉक केले आहे. पुढे सुरू ठेवण्यासाठी दाबा."</string>
-    <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"चेहरा ओळखला आहे. पुढे सुरू ठेवण्यासाठी दाबा."</string>
-    <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"चेहरा ओळखला आहे. पुढे सुरू ठेवण्यासाठी अनलॉक करा आयकन दाबा."</string>
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"चेहऱ्याने अनलॉक केले. सुरू ठेवण्यासाठी अनलॉक करा आयकन प्रेस करा."</string>
+    <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"चेहऱ्याने अनलॉक केले आहे. पुढे सुरू ठेवण्यासाठी प्रेस करा."</string>
+    <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"चेहरा ओळखला आहे. पुढे सुरू ठेवण्यासाठी प्रेस करा."</string>
+    <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"चेहरा ओळखला आहे. पुढे सुरू ठेवण्यासाठी अनलॉक करा आयकन प्रेस करा."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"ऑथेंटिकेशन केलेले"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"पिन वापरा"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"पॅटर्न वापरा"</string>
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"तुम्‍ही पुढील प्रयत्‍नात चुकीचा पिन एंटर केल्यास, तुमची कार्य प्रोफाइल आणि तिचा डेटा हटवला जाईल."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"तुम्‍ही पुढील प्रयत्‍नात चुकीचा पासवर्ड एंटर केल्यास, तुमची कार्य प्रोफाइल आणि तिचा डेटा हटवला जाईल."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"फिंगरप्रिंट सेन्सरला स्पर्श करा"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"फिंगरप्रिंट आयकन"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"चेहरा ओळखू शकत नाही. त्याऐवजी फिंगरप्रिंट वापरा."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -324,12 +323,12 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"उघडण्यासाठी पुन्हा टॅप करा"</string>
     <string name="tap_again" msgid="1315420114387908655">"पुन्हा टॅप करा"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"उघडण्यासाठी वर स्वाइप करा"</string>
-    <string name="keyguard_unlock_press" msgid="9140109453735019209">"उघडण्यासाठी अनलॉक करा आयकन दाबा"</string>
+    <string name="keyguard_unlock_press" msgid="9140109453735019209">"उघडण्यासाठी अनलॉक करा आयकन प्रेस करा"</string>
     <string name="keyguard_face_successful_unlock_swipe" msgid="6180997591385846073">"चेहऱ्याने अनलॉक केले आहे. उघडण्यासाठी वर स्वाइप करा."</string>
-    <string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"चेहऱ्याने अनलॉक केले. उघडण्यासाठी अनलॉक करा आयकन दाबा."</string>
-    <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"चेहऱ्याने अनलॉक केले आहे. उघडण्यासाठी दाबा."</string>
-    <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"चेहरा ओळखला आहे. उघडण्यासाठी दाबा."</string>
-    <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"चेहरा ओळखला आहे. उघडण्यासाठी अनलॉक करा आयकन दाबा."</string>
+    <string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"चेहऱ्याने अनलॉक केले. उघडण्यासाठी अनलॉक करा आयकन प्रेस करा."</string>
+    <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"चेहऱ्याने अनलॉक केले आहे. उघडण्यासाठी प्रेस करा."</string>
+    <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"चेहरा ओळखला आहे. उघडण्यासाठी प्रेस करा."</string>
+    <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"चेहरा ओळखला आहे. उघडण्यासाठी अनलॉक करा आयकन प्रेस करा."</string>
     <string name="keyguard_face_successful_unlock" msgid="4203999851465708287">"चेहऱ्याने अनलॉक केले आहे"</string>
     <string name="keyguard_face_successful_unlock_alt1" msgid="5853906076353839628">"चेहरा ओळखला आहे"</string>
   <string-array name="udfps_accessibility_touch_hints">
@@ -401,7 +400,7 @@
     <string name="media_projection_action_text" msgid="3634906766918186440">"आता सुरू करा"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"सूचना नाहीत"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"नवीन सूचना नाहीत"</string>
-    <string name="unlock_to_see_notif_text" msgid="7439033907167561227">"जुन्या सूचना पहाण्यासाठी अनलॉक करा"</string>
+    <string name="unlock_to_see_notif_text" msgid="7439033907167561227">"जुन्या सूचना पाहण्यासाठी अनलॉक करा"</string>
     <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"हे डिव्हाइस तुमच्या पालकाने व्यवस्थापित केले आहे"</string>
     <string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"तुमच्‍या संस्‍थेकडे या डिव्हाइसची मालकी आहे आणि ती नेटवर्क ट्रॅफिकचे परीक्षण करू शकते"</string>
     <string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"हे डिव्हाइस <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> च्या मालकीचे आहे आणि ती नेटवर्क ट्रॅफिकचे परीक्षण करू शकते"</string>
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# नियंत्रण जोडले आहे.}other{# नियंत्रणे जोडली आहेत.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"काढून टाकले"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> जोडायचे आहे का?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"तुम्ही <xliff:g id="APPNAME">%s</xliff:g> जोडता, तेव्हा ते या पॅनलमध्ये नियंत्रणे आणि आशय जोडू शकते. येथे कोणती नियंत्रणे दाखवावीत ते तुम्ही काही अ‍ॅप्समध्ये निवडू शकता."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> हे येथे कोणती नियंत्रणे आणि आशय दाखवावा ते निवडू शकते."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> साठी नियंत्रणे काढून टाकायची आहेत का?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"आवडले"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"आवडले, स्थान <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"नावडले"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"इतर"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"डिव्हाइस नियंत्रणांमध्ये जोडा"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"जोडा"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"काढून टाका"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ने सुचवले आहे"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"डिव्हाइस लॉक आहे"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"लॉक स्क्रीनवरून डिव्हाइस दाखवायचे आणि नियंत्रित करायचे का?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"तुम्ही तुमच्या बाह्य डिव्हाइससाठी लॉक स्क्रीनवर नियंत्रणे जोडू शकता.\n\nतुमचे डिव्हाइस अ‍ॅप तुम्हाला तुमचा फोन किंवा टॅबलेट अनलॉक न करता काही डिव्हाइस नियंत्रित करण्याची अनुमती देऊ शकते.\n\nतुम्ही सेटिंग्ज मध्ये कधीही बदल करू शकता."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"लॉक स्क्रीनवरून डिव्हाइस नियंत्रित करायची का?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"तुमचा फोन किंवा टॅबलेट अनलॉक न करता तुम्ही काही डिव्हाइस नियंत्रित करू शकता.\n\nतुमचे डिव्हाइस अ‍ॅप अशा प्रकारे कोणते डिव्हाइस नियंत्रित केले जाऊ शकतात हे निर्धारित करते."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"तुमचा फोन किंवा टॅबलेट अनलॉक न करता तुम्ही काही डिव्हाइस नियंत्रित करू शकता. तुमचे डिव्हाइस अ‍ॅप हे अशा प्रकारे कोणती डिव्हाइस नियंत्रित केली जाऊ शकतात हे निर्धारित करते."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"नाही, नको"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"होय"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"पिनमध्ये अक्षरे किंवा चिन्हे आहेत"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"नियंत्रणे जोडा"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"नियंत्रणे संपादित करा"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"अ‍ॅप जोडा"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"ॲप काढून टाका"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"आउटपुट जोडा"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"गट"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"एक डिव्हाइस निवडले"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 5a6ee92..526c050 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Jika anda memasukkan PIN yang salah pada percubaan seterusnya, profil kerja anda dan data profil itu akan dipadamkan."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Jika anda memasukkan kata laluan yang salah pada percubaan seterusnya, profil kerja anda dan data profil itu akan dipadamkan."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Sentuh penderia cap jari"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikon cap jari"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Tidak mengenali wajah. Gunakan cap jari."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# kawalan ditambah.}other{# kawalan ditambah.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Dialih keluar"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Tambahkan <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Apabila anda menambahkan <xliff:g id="APPNAME">%s</xliff:g>, apl ini boleh menambahkan kawalan dan kandungan pada panel ini. Dalam sesetengah apl, anda boleh memilih kawalan yang muncul di sini."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g>boleh memilih kawalan dan kandungan yang dipaparkan di sini."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Alih keluar kawalan untuk <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Digemari"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Digemari, kedudukan <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Dinyahgemari"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Lain-lain"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Tambahkan pada kawalan peranti"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Tambah"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Alih keluar"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Dicadangkan oleh <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Peranti dikunci"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Tunjukkan dan kawal peranti daripada skrin kunci?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Anda boleh menambah kawalan untuk peranti luaran anda pada skrin kunci.\n\nApl peranti anda mungkin membenarkan anda mengawal sesetengah peranti tanpa membuka kunci telefon atau tablet anda.\n\nAnda boleh membuat perubahan pada bila-bila masa dalam Tetapan."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Kawal peranti daripada skrin kunci?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Anda boleh mengawal sesetengah peranti tanpa membuka kunci telefon atau tablet anda.\n\nApl peranti anda menentukan peranti yang boleh dikawal dengan cara ini."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Anda boleh mengawal sesetengah peranti tanpa membuka kunci telefon atau tablet anda. Apl peranti anda menentukan peranti yang boleh dikawal dengan cara ini."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Tidak perlu"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Ya"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN mengandungi huruf atau simbol"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Tambah kawalan"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Edit kawalan"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Tambahkan apl"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Alih keluar apl"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Tambah output"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Kumpulan"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 peranti dipilih"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 7fe0244..835376c 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"မှားယွင်းသည့် ပင်နံပါတ်ကို နောက်တစ်ကြိမ်ထည့်သွင်းပါက သင်၏အလုပ်ပရိုဖိုင်နှင့် ၎င်း၏ဒေတာများကို ဖျက်လိုက်ပါမည်။"</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"မှားယွင်းသည့် စကားဝှက်ကို နောက်တစ်ကြိမ်ထည့်သွင်းပါက သင်၏အလုပ်ပရိုဖိုင်နှင့် ၎င်း၏ ဒေတာများကို ဖျက်လိုက်ပါမည်။"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"လက်ဗွေအာရုံခံကိရိယာကို တို့ပါ"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"လက်ဗွေ သင်္ကေတ"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"မျက်နှာကို မမှတ်မိပါ။ လက်ဗွေကို အစားထိုးသုံးပါ။"</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{ထိန်းချုပ်ခလုတ် # ခု ထည့်ထားသည်။}other{ထိန်းချုပ်ခလုတ် # ခု ထည့်ထားသည်။}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"ဖယ်ရှားထားသည်"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> ထည့်မလား။"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"<xliff:g id="APPNAME">%s</xliff:g> ထည့်သောအခါ ၎င်းသည် ဤအကန့်တွင် သတ်မှတ်ချက်များနှင့် အကြောင်းအရာကို ထည့်နိုင်သည်။ အက်ပ်အချို့၌ မြင်ရမည့် သတ်မှတ်ချက်များကို ဤနေရာတွင် ရွေးနိုင်သည်။"</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> သည် ဤနေရာတွင်ပြသည့် သတ်မှတ်ချက်နှင့် အကြောင်းအရာများကို ရွေးနိုင်သည်။"</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> အတွက် သတ်မှတ်ချက်များ ဖယ်ရှားမလား။"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"အကြိုက်ဆုံးတွင် ထည့်ထားသည်"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"အကြိုက်ဆုံးတွင် ထည့်ထားသည်၊ အဆင့် <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"အကြိုက်ဆုံးမှ ဖယ်ရှားထားသည်"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"အခြား"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"စက်ထိန်းစနစ်သို့ ထည့်ရန်"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"ထည့်ရန်"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"ဖယ်ရှားရန်"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> က အကြံပြုထားသည်"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"စက်ကိုလော့ခ်ချထားသည်"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"လော့ခ်မျက်နှာပြင်တွင် စက်ပစ္စည်းများကြည့်ရှုပြီး ထိန်းချုပ်မလား။"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"လော့ခ်မျက်နှာပြင်တွင် ပြင်ပစက်များအတွက် ထိန်းချုပ်မှုများ ထည့်နိုင်သည်။\n\nသင့်စက်ပစ္စည်းအက်ပ်က အချို့စက်များကို ဖုန်း (သို့) တက်ဘလက် လော့ခ်ဖွင့်ရန်မလိုဘဲ သုံးခွင့်ပေးနိုင်သည်။\n\nဆက်တင်များ၌ အချိန်မရွေး ပြောင်းလဲပြင်ဆင်နိုင်သည်။"</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"လော့ခ်မျက်နှာပြင်တွင် စက်ပစ္စည်းများ ထိန်းချုပ်မလား။"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"အချို့စက်များကို ဖုန်း (သို့) တက်ဘလက် လော့ခ်ဖွင့်ရန်မလိုဘဲ ထိန်းချုပ်နိုင်သည်။\n\nဤနည်းလမ်းအတိုင်း ထိန်းချုပ်နိုင်မည့်စက်များကို သင့်စက်ပစ္စည်းအက်ပ်က ဆုံးဖြတ်သည်။"</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"အချို့စက်များကို ဖုန်း (သို့) တက်ဘလက် လော့ခ်ဖွင့်ရန်မလိုဘဲ ထိန်းချုပ်နိုင်သည်။ ဤနည်းလမ်းအတိုင်း ထိန်းချုပ်နိုင်မည့်စက်များကို သင့်စက်ပစ္စည်းအက်ပ်က ဆုံးဖြတ်သည်။"</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"မလိုပါ"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Yes"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"ပင်နံပါတ်တွင် စာလုံး သို့မဟုတ် သင်္ကေတများပါဝင်သည်"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"ထိန်းချုပ်မှုများ ထည့်ရန်"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"ထိန်းချုပ်မှုများ ပြင်ရန်"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"အက်ပ်ထည့်ရန်"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"အက်ပ်ဖယ်ရှားရန်"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"မီဒီယာအထွက်များ ထည့်ရန်"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"အုပ်စု"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"စက်ပစ္စည်း ၁ ခုကို ရွေးချယ်ထားသည်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 887cf9d..55bc598 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Hvis du skriver inn feil PIN-kode på neste forsøk, slettes jobbprofilen din og tilknyttede data."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Hvis du skriver inn feil passord på neste forsøk, slettes jobbprofilen din og tilknyttede data."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Trykk på fingeravtrykkssensoren"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikon for fingeravtrykk"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ansiktet gjenkjennes ikke. Bruk fingeravtrykk."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,9 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# kontroll er lagt til.}other{# kontroller er lagt til.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Fjernet"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Vil du legge til <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Når du legger til <xliff:g id="APPNAME">%s</xliff:g>, kan den legge til kontroller og innhold i dette panelet. I noen apper kan du velge hvilke kontroller som vises her."</string>
+    <!-- no translation found for controls_panel_authorization (7045551688535104194) -->
+    <skip />
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Vil du fjerne kontrollene for <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Favoritt"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Favoritt, posisjon <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Fjernet som favoritt"</string>
@@ -826,12 +827,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Annet"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Legg til i enhetsstyring"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Legg til"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Fjern"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Foreslått av <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Enheten er låst"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Vil du se og kontrollere enheter fra låseskjermen?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Du kan legge til kontroller for de eksterne enhetene dine på låseskjermen.\n\nEnhetsappen kan la deg kontrollere noen enheter uten å låse opp telefonen eller nettbrettet.\n\nDu kan når som helst endre innstillingene."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Vil du kontrollere enheter fra låseskjermen?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Du kan kontrollere enkelte enheter uten å låse opp telefonen eller nettbrettet.\n\nEnhetsappen fastslår hvilke enheter som kan kontrolleres på denne måten."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Du kan kontrollere visse enheter uten å låse opp telefonen eller nettbrettet. Enhetsappen avgjør hvilke enheter som kan kontrolleres på denne måten."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Nei takk"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Ja"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-koden inneholder bokstaver eller symboler"</string>
@@ -879,6 +881,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Legg til kontroller"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Endre kontroller"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Legg til app"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Fjern appen"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Legg til utenheter"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Gruppe"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 enhet er valgt"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index c37aef3..fc5a2ec 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"तपाईंले अर्को पटक पनि गलत PIN प्रविष्टि गर्नुभयो भने तपाईंको कार्य प्रोफाइल र त्यहाँको डेटा मेटाइने छ।"</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"तपाईंले अर्को पटक पनि गलत पासवर्ड प्रविष्टि गर्नुभयो भने तपाईंको कार्य प्रोफाइल र त्यहाँको डेटा मेटाइने छ।"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"फिंगरप्रिन्ट सेन्सरमा छुनुहोस्‌"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"फिंगरप्रिन्ट जनाउने आइकन"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"अनुहार पहिचान गर्न सकिएन। बरु फिंगरप्रिन्ट प्रयोग गर्नुहोस्।"</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# कन्ट्रोल हालियो।}other{# वटा कन्ट्रोल हालियो।}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"हटाइएको"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> हाल्ने हो?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"तपाईंले <xliff:g id="APPNAME">%s</xliff:g> हाल्नुभयो भने यसले यो प्यानलमा सेटिङ र सामग्री हाल्न सक्छ। तपाईं केही एपहरूमा यहाँ कुन कुन सेटिङ देखाउने भन्ने कुरा छनौट गर्न सक्नुहुन्छ।"</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> ले यहाँ कुन कुन कन्ट्रोल र सामग्री देखाउने भन्ने कुरा छनौट गर्न सक्छ।"</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> का सेटिङ हटाउने हो?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"मनपराइएको"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"मन पराइएका कुराहरूको <xliff:g id="NUMBER">%d</xliff:g> औँ स्थानमा"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"मन पर्ने कुराहरूको सूचीमा नराखिएको"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"अन्य"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"डिभाइस नियन्त्रण गर्ने विजेटहरूको सूचीमा थप्नुहोस्"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"थप्नुहोस्"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"हटाउनुहोस्"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ले सिफारिस गरेको"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"यन्त्र लक गरिएको छ"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"लक स्क्रिनमै डिभाइसहरू देखाउने र लक स्क्रिनबाटै ती डिभाइसहरू नियन्त्रण गर्ने हो?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"तपाईं आफ्ना बाह्य डिभाइसहरूका कन्ट्रोलहरू लक स्क्रिनमा हाल्न सक्नुहुन्छ।\n\nतपाईंको डिभाइसको एपले तपाईंलाई आफ्नो फोन वा ट्याब्लेट अनलक नगरिकनै केही डिभाइसहरू नियन्त्रण गर्ने अनुमति दिन सक्छ।\n\nतपाईं जुनसुकै बेला सेटिङमा गई यी कुराहरू बदल्न सक्नुहुन्छ।"</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"लक स्क्रिनबाटै डिभाइसहरू नियन्त्रण गर्ने हो?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"तपाईं आफ्नो फोन वा ट्याब्लेट अनलक नगरिकनै केही डिभाइसहरू नियन्त्रण गर्न सक्नुहुन्छ।\n\nतपाईंको डिभाइस एपले यस तरिकाले कुन कुन डिभाइस नियन्त्रण गर्न सकिन्छ भन्ने कुरा निर्धारण गर्छ।"</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"तपाईं आफ्नो फोन वा ट्याब्लेट अनलक नगरिकनै केही डिभाइसहरू नियन्त्रण गर्न सक्नुहुन्छ। तपाईंको डिभाइस एपले यस तरिकाले कुन कुन डिभाइस नियन्त्रण गर्न सकिन्छ भन्ने कुरा निर्धारण गर्छ।"</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"पर्दैन"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"अँ"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN मा अक्षर वा चिन्हहरू समाविष्ट हुन्छन्"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"कन्ट्रोल थप्नुहोस्"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"कन्ट्रोल सम्पादन गर्नुहोस्"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"एप हाल्नुहोस्"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"यो एप हटाउनुहोस्"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"आउटपुट यन्त्रहरू थप्नुहोस्"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"समूह"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"१ यन्त्र चयन गरियो"</string>
@@ -958,7 +960,7 @@
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"मोबाइल डेटा"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
     <string name="mobile_data_connection_active" msgid="944490013299018227">"इन्टरनेटमा कनेक्ट गरिएको छ"</string>
-    <string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"केही समयका लागि मोबाइल डेटामा कनेक्ट गरिएको छ"</string>
+    <string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"यसमा केही समयका लागि कनेक्ट गरिएको हो"</string>
     <string name="mobile_data_poor_connection" msgid="819617772268371434">"इन्टरनेट राम्री चलेको छैन"</string>
     <string name="mobile_data_off_summary" msgid="3663995422004150567">"मोबाइल डेटा स्वतः कनेक्ट हुँदैन"</string>
     <string name="mobile_data_no_connection" msgid="1713872434869947377">"इन्टरनेट छैन"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index ee055d7..2682ec8 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Als je bij de volgende poging een onjuiste pincode opgeeft, worden je werkprofiel en de bijbehorende gegevens verwijderd."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Als je bij de volgende poging een onjuist wachtwoord opgeeft, worden je werkprofiel en de bijbehorende gegevens verwijderd."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Raak de vingerafdruksensor aan"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Vingerafdrukpictogram"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Gezicht niet herkend. Gebruik je vingerafdruk."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# bedieningselement toegevoegd.}other{# bedieningselementen toegevoegd.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Verwijderd"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> toevoegen?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Als je <xliff:g id="APPNAME">%s</xliff:g> toevoegt, kan deze app bedieningselementen en content aan dit deelvenster toevoegen. In sommige apps kun je kiezen welke bedieningselementen hier worden getoond."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> kan kiezen welke bedieningselementen en content hier worden getoond."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Bedieningselementen voor <xliff:g id="APPNAME">%s</xliff:g> verwijderen?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Gemarkeerd als favoriet"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Gemarkeerd als favoriet, positie <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Verwijderd als favoriet"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Overig"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Toevoegen aan apparaatbediening"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Toevoegen"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Verwijderen"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Voorgesteld door <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Apparaat vergrendeld"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Apparaten tonen en bedienen via het vergrendelscherm?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Je kunt bedieningselementen voor je externe apparaten toevoegen aan het vergrendelscherm.\n\nMet je apparaat-app kun je misschien bepaalde apparaten bedienen zonder je telefoon of tablet te ontgrendelen.\n\nJe kunt op elk moment wijzigingen aanbrengen via Instellingen."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Apparaten bedienen via vergrendelscherm?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Je kunt bepaalde apparaten bedienen zonder je telefoon of tablet te ontgrendelen.\n\nJe apparaat-app bepaalt welke apparaten op deze manier kunnen worden bediend."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Je kunt bepaalde apparaten bedienen zonder je telefoon of tablet te ontgrendelen. Je apparaat-app bepaalt welke apparaten op deze manier kunnen worden bediend."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Nee, bedankt"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Ja"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Pincode bevat letters of symbolen"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Bedieningselementen toevoegen"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Bedieningselementen bewerken"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"App toevoegen"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"App verwijderen"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Uitvoer toevoegen"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Groep"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Eén apparaat geselecteerd"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 4252f49..cc69f84 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"ଆପଣ ପରବର୍ତ୍ତୀ ପ୍ରଚେଷ୍ଟାରେ ଏକ ଭୁଲ PIN ଲେଖିଲେ, ଆପଣଙ୍କ ୱାର୍କ ପ୍ରୋଫାଇଲ୍ ଏବଂ ଏହାର ଡାଟାକୁ ଡିଲିଟ୍ କରିଦିଆଯିବ।"</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"ଆପଣ ପରବର୍ତ୍ତୀ ପ୍ରଚେଷ୍ଟାରେ ଏକ ଭୁଲ ପାସୱାର୍ଡ ଲେଖିଲେ, ଆପଣଙ୍କ ୱାର୍କ ପ୍ରୋଫାଇଲ୍ ଓ ଏହାର ଡାଟାକୁ ଡିଲିଟ୍ କରିଦିଆଯିବ।"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ଟିପଚିହ୍ନ ସେନସର୍‌କୁ ଛୁଅଁନ୍ତୁ"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"ଟିପଚିହ୍ନ ଆଇକନ୍"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ଫେସ୍ ଚିହ୍ନଟ କରିହେବ ନାହିଁ। ଟିପଚିହ୍ନ ବ୍ୟବହାର କରନ୍ତୁ।"</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -400,8 +399,8 @@
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ବିକଳ୍ପ ଦ୍ୱାରା ବିଜ୍ଞପ୍ତି ପଜ୍‍ ହୋଇଛି"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"ବର୍ତ୍ତମାନ ଆରମ୍ଭ କରନ୍ତୁ"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"କୌଣସି ବିଜ୍ଞପ୍ତି ନାହିଁ"</string>
-    <string name="no_unseen_notif_text" msgid="395512586119868682">"କୌଣସି ନୂଆ ବିଜ୍ଞପ୍ତି ନାହିଁ"</string>
-    <string name="unlock_to_see_notif_text" msgid="7439033907167561227">"ପୁରୁଣା ବିଜ୍ଞପ୍ତି ଦେଖିବାକୁ ଅନଲକ କରନ୍ତୁ"</string>
+    <string name="no_unseen_notif_text" msgid="395512586119868682">"କୌଣସି ନୂଆ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ନାହିଁ"</string>
+    <string name="unlock_to_see_notif_text" msgid="7439033907167561227">"ପୁରୁଣା ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ଦେଖିବାକୁ ଅନଲକ କରନ୍ତୁ"</string>
     <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"ଏହି ଡିଭାଇସ୍ ଆପଣଙ୍କ ବାପାମାଙ୍କ ଦ୍ୱାରା ପରିଚାଳିତ"</string>
     <string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"ଏହି ଡିଭାଇସର ମାଲିକାନା ଆପଣଙ୍କ ସଂସ୍ଥା ପାଖରେ ଅଛି ଏବଂ ଏହା ନେଟୱାର୍କ ଟ୍ରାଫିକର ନିରୀକ୍ଷଣ କରିପାରେ"</string>
     <string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"ଏହି ଡିଭାଇସଟି <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>ର ଅଟେ ଏବଂ ଏହା ନେଟୱାର୍କ ଟ୍ରାଫିକକୁ ନିରୀକ୍ଷଣ କରିପାରେ"</string>
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{#ଟି ନିୟନ୍ତ୍ରଣ ଯୋଗ କରାଯାଇଛି।}other{#ଟି ନିୟନ୍ତ୍ରଣ ଯୋଗ କରାଯାଇଛି।}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"କାଢ଼ି ଦିଆଯାଇଛି"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g>କୁ ଯୋଗ କରିବେ?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"ଯେତେବେଳେ ଆପଣ <xliff:g id="APPNAME">%s</xliff:g>କୁ ଯୋଗ କରନ୍ତି, ସେତେବେଳେ ଏହି ପେନେଲରେ ଏହା ନିୟନ୍ତ୍ରଣ ଏବଂ ବିଷୟବସ୍ତୁ ଯୋଗ କରିପାରିବ। କିଛି ଆପ୍ସରେ, ଏଠାରେ କେଉଁ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ ଦେଖାଯିବ ତାହା ଆପଣ ବାଛିପାରିବେ।"</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"ଏଠାରେ କେଉଁ ନିୟନ୍ତ୍ରଣ ଏବଂ ବିଷୟବସ୍ତୁ ଦେଖାଯିବ ତାହା <xliff:g id="APPNAME">%s</xliff:g> ବାଛିପାରିବ।"</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> ପାଇଁ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକୁ କାଢ଼ି ଦେବେ?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"ପସନ୍ଦ କରାଯାଇଛି"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"ପସନ୍ଦ କରାଯାଇଛି, ସ୍ଥିତି <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"ନାପସନ୍ଦ କରାଯାଇଛି"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ଅନ୍ୟ"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"ଡିଭାଇସ୍ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକରେ ଯୋଗ କରନ୍ତୁ"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"ଯୋଗ କରନ୍ତୁ"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"କାଢ଼ି ଦିଅନ୍ତୁ"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ଦ୍ଵାରା ପ୍ରସ୍ତାବିତ"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"ଡିଭାଇସ୍ ଲକ୍ ହୋଇଯାଇଛି"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"ଲକ ସ୍କ୍ରିନରୁ ଡିଭାଇସଗୁଡ଼ିକୁ ଦେଖାଇବେ ଏବଂ ନିୟନ୍ତ୍ରଣ କରିବେ?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"ଆପଣ ଲକ ସ୍କ୍ରିନରେ ଆପଣଙ୍କ ଏକ୍ସଟର୍ନଲ ଡିଭାଇସଗୁଡ଼ିକ ପାଇଁ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ ଯୋଗ କରିପାରିବେ।\n\nଆପଣଙ୍କ ଫୋନ କିମ୍ବା ଟାବଲେଟକୁ ଅନଲକ ନକରି କିଛି ଡିଭାଇସକୁ ନିୟନ୍ତ୍ରଣ କରିବା ପାଇଁ ଆପଣଙ୍କ ଡିଭାଇସର ଆପ ଆପଣଙ୍କୁ ଅନୁମତି ଦେଇପାରେ।\n\nଆପଣ ଯେ କୌଣସି ସମୟରେ ସେଟିଂସରେ ପରିବର୍ତ୍ତନ କରିପାରିବେ।"</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"ଲକ ସ୍କ୍ରିନରୁ ଡିଭାଇସଗୁଡ଼ିକୁ ନିୟନ୍ତ୍ରଣ କରିବେ?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"ଆପଣ ଆପଣଙ୍କ ଫୋନ କିମ୍ବା ଟାବଲେଟକୁ ଅନଲକ ନକରି କିଛି ଡିଭାଇସକୁ ନିୟନ୍ତ୍ରଣ କରିପାରିବେ।\n\nଏହି ଉପାୟରେ କେଉଁ ଡିଭାଇସଗୁଡ଼ିକୁ ନିୟନ୍ତ୍ରଣ କରାଯାଇପାରିବ ତାହା ଆପଣଙ୍କ ଡିଭାଇସର ଆପ ସ୍ଥିର କରେ।"</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"ଆପଣ ଆପଣଙ୍କ ଫୋନ କିମ୍ବା ଟାବଲେଟକୁ ଅନଲକ ନକରି କିଛି ଡିଭାଇସକୁ ନିୟନ୍ତ୍ରଣ କରିପାରିବେ। ଏହି ଉପାୟରେ କେଉଁ ଡିଭାଇସଗୁଡ଼ିକୁ ନିୟନ୍ତ୍ରଣ କରାଯାଇପାରିବ ତାହା ଆପଣଙ୍କ ଡିଭାଇସ ଆପ ସ୍ଥିର କରେ।"</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"ନା, ଧନ୍ୟବାଦ"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"ହଁ"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PINରେ ଅକ୍ଷର କିମ୍ୱା ପ୍ରତୀକଗୁଡ଼ିକ ଥାଏ"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ ଯୋଗ କରନ୍ତୁ"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକୁ ଏଡିଟ କରନ୍ତୁ"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"ଆପ ଯୋଗ କରନ୍ତୁ"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"ଆପକୁ କାଢ଼ି ଦିଅନ୍ତୁ"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"ଆଉଟପୁଟ୍ ଯୋଗ କରନ୍ତୁ"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"ଗୋଷ୍ଠୀ"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1ଟି ଡିଭାଇସ୍ ଚୟନ କରାଯାଇଛି"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index ea8bd3d..d59f352 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"ਜੇ ਤੁਸੀਂ ਅਗਲੀ ਕੋਸ਼ਿਸ਼ ਵਿੱਚ ਕੋਈ ਗਲਤ ਪਿੰਨ ਦਾਖਲ ਕਰਦੇ ਹੋ, ਤਾਂ ਤੁਹਾਡਾ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਅਤੇ ਇਸ ਦਾ ਡਾਟਾ ਮਿਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ।"</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"ਜੇ ਤੁਸੀਂ ਅਗਲੀ ਕੋਸ਼ਿਸ਼ ਵਿੱਚ ਕੋਈ ਗਲਤ ਪਾਸਵਰਡ ਦਾਖਲ ਕਰਦੇ ਹੋ, ਤਾਂ ਤੁਹਾਡਾ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਅਤੇ ਇਸ ਦਾ ਡਾਟਾ ਮਿਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ।"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ ਨੂੰ ਸਪੱਰਸ਼ ਕਰੋ"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਦਾ ਪ੍ਰਤੀਕ"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ਚਿਹਰਾ ਨਹੀਂ ਪਛਾਣ ਸਕਦੇ। ਇਸਦੀ ਬਜਾਏ ਫਿੰਗਰਪ੍ਰਿੰਟ ਵਰਤੋ।"</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -400,7 +399,7 @@
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਵੱਲੋਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਰੋਕਿਆ ਗਿਆ"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"ਹੁਣੇ ਸ਼ੁਰੂ ਕਰੋ"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"ਕੋਈ ਸੂਚਨਾਵਾਂ ਨਹੀਂ"</string>
-    <string name="no_unseen_notif_text" msgid="395512586119868682">"ਕੋਈ ਨਵੀਂ ਸੂਚਨਾ ਨਹੀਂ"</string>
+    <string name="no_unseen_notif_text" msgid="395512586119868682">"ਕੋਈ ਨਵੀਂ ਸੂਚਨਾ ਨਹੀਂ ਹੈ"</string>
     <string name="unlock_to_see_notif_text" msgid="7439033907167561227">"ਪੁਰਾਣੀਆਂ ਸੂਚਨਾਵਾਂ ਦੇਖਣ ਲਈ ਅਣਲਾਕ ਕਰੋ"</string>
     <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"ਇਸ ਡੀਵਾਈਸ ਦਾ ਪ੍ਰਬੰਧਨ ਤੁਹਾਡੇ ਮਾਂ-ਪਿਓ ਵੱਲੋਂ ਕੀਤਾ ਜਾਂਦਾ ਹੈ"</string>
     <string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"ਤੁਹਾਡੀ ਸੰਸਥਾ ਕੋਲ ਇਸ ਡੀਵਾਈਸ ਦੀ ਮਲਕੀਅਤ ਹੈ ਅਤੇ ਇਹ ਨੈੱਟਵਰਕ ਟਰੈਫ਼ਿਕ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦੀ ਹੈ"</string>
@@ -808,7 +807,9 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ।}one{# ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ।}other{# ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕੀਤੇ ਗਏ।}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"ਹਟਾਇਆ ਗਿਆ"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"ਕੀ <xliff:g id="APPNAME">%s</xliff:g> ਸ਼ਾਮਲ ਕਰਨਾ ਹੈ?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"ਜਦੋਂ ਤੁਸੀਂ <xliff:g id="APPNAME">%s</xliff:g> ਸ਼ਾਮਲ ਕਰਦੇ ਹੋ, ਤਾਂ ਇਹ ਇਸ ਪੈਨਲ ਵਿੱਚ ਕੰਟਰੋਲਾਂ ਅਤੇ ਸਮੱਗਰੀ ਨੂੰ ਸ਼ਾਮਲ ਕਰ ਸਕਦੀ ਹੈ। ਕੁਝ ਐਪਾਂ ਲਈ, ਤੁਸੀਂ ਇਹ ਚੁਣ ਸਕਦੇ ਹੋ ਕਿ ਇੱਥੇ ਕਿਹੜੇ ਕੰਟਰੋਲ ਦਿਸਣ।"</string>
+    <!-- no translation found for controls_panel_authorization (7045551688535104194) -->
+    <skip />
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"ਕੀ <xliff:g id="APPNAME">%s</xliff:g> ਲਈ ਕੰਟਰੋਲਾਂ ਨੂੰ ਹਟਾਉਣਾ ਹੈ?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"ਮਨਪਸੰਦ ਵਿੱਚ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"ਮਨਪਸੰਦ ਵਿੱਚ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ, ਸਥਾਨ <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"ਮਨਪਸੰਦ ਵਿੱਚੋਂ ਹਟਾਇਆ ਗਿਆ"</string>
@@ -826,12 +827,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ਹੋਰ"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"ਡੀਵਾਈਸ ਕੰਟਰੋਲਾਂ ਵਿੱਚ ਸ਼ਾਮਲ ਕਰੋ"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"ਸ਼ਾਮਲ ਕਰੋ"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"ਹਟਾਓ"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ਵੱਲੋਂ ਸੁਝਾਇਆ ਗਿਆ"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"ਡੀਵਾਈਸ ਲਾਕ ਹੈ"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"ਕੀ ਲਾਕ ਸਕ੍ਰੀਨ ਤੋਂ ਡੀਵਾਈਸਾਂ ਨੂੰ ਦੇਖਣਾ ਅਤੇ ਕੰਟਰੋਲ ਕਰਨਾ ਹੈ?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"ਤੁਸੀਂ ਲਾਕ ਸਕ੍ਰੀਨ \'ਤੇ ਆਪਣੇ ਬਾਹਰੀ ਡੀਵਾਈਸਾਂ ਲਈ ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕਰ ਸਕਦੇ ਹੋ।\n\nਤੁਹਾਡੇ ਡੀਵਾਈਸ \'ਤੇ ਮੌਜੂਦ ਐਪ ਤੁਹਾਨੂੰ ਤੁਹਾਡੇ ਫ਼ੋਨ ਜਾਂ ਟੈਬਲੈੱਟ ਨੂੰ ਅਣਲਾਕ ਕੀਤੇ ਬਿਨਾਂ ਕੁਝ ਡੀਵਾਈਸਾਂ ਨੂੰ ਕੰਟਰੋਲ ਕਰਨ ਦੇ ਸਕਦੀ ਹੈ।\n\nਤੁਸੀਂ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਜਾ ਕੇ ਕਿਸੇ ਵੇਲੇ ਵੀ ਤਬਦੀਲੀਆਂ ਕਰ ਸਕਦੇ ਹੋ।"</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"ਕੀ ਲਾਕ ਸਕ੍ਰੀਨ ਤੋਂ ਡੀਵਾਈਸਾਂ ਨੂੰ ਕੰਟਰੋਲ ਕਰਨਾ ਹੈ?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"ਤੁਸੀਂ ਆਪਣੇ ਫ਼ੋਨ ਜਾਂ ਟੈਬਲੈੱਟ ਨੂੰ ਅਣਲਾਕ ਕੀਤੇ ਬਿਨਾਂ ਕੁਝ ਡੀਵਾਈਸਾਂ ਨੂੰ ਕੰਟਰੋਲ ਕਰ ਸਕਦੇ ਹੋ।\n\nਤੁਹਾਡੇ ਡੀਵਾਈਸ \'ਤੇ ਮੌਜੂਦ ਐਪ ਇਹ ਨਿਰਧਾਰਿਤ ਕਰਦੀ ਹੈ ਕਿ ਇਸ ਤਰੀਕੇ ਨਾਲ ਕਿਹੜੇ ਡੀਵਾਈਸਾਂ ਨੂੰ ਕੰਟਰੋਲ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ।"</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"ਤੁਸੀਂ ਆਪਣੇ ਫ਼ੋਨ ਜਾਂ ਟੈਬਲੈੱਟ ਨੂੰ ਅਣਲਾਕ ਕੀਤੇ ਬਿਨਾਂ ਕੁਝ ਡੀਵਾਈਸਾਂ ਨੂੰ ਕੰਟਰੋਲ ਕਰ ਸਕਦੇ ਹੋ। ਤੁਹਾਡੇ ਡੀਵਾਈਸ \'ਤੇ ਮੌਜੂਦ ਐਪ ਇਹ ਨਿਰਧਾਰਿਤ ਕਰਦੀ ਹੈ ਕਿ ਇਸ ਤਰੀਕੇ ਨਾਲ ਕਿਹੜੇ ਡੀਵਾਈਸਾਂ ਨੂੰ ਕੰਟਰੋਲ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ।"</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"ਨਹੀਂ ਧੰਨਵਾਦ"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"ਹਾਂ"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"ਪਿੰਨ ਵਿੱਚ ਅੱਖਰ ਜਾਂ ਚਿੰਨ੍ਹ ਸ਼ਾਮਲ ਹਨ"</string>
@@ -879,6 +881,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕਰੋ"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"ਕੰਟਰੋਲਾਂ ਦਾ ਸੰਪਾਦਨ ਕਰੋ"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"ਐਪ ਸ਼ਾਮਲ ਕਰੋ"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"ਐਪ ਹਟਾਓ"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"ਆਊਟਪੁੱਟ ਸ਼ਾਮਲ ਕਰੋ"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"ਗਰੁੱਪ"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 ਡੀਵਾਈਸ ਨੂੰ ਚੁਣਿਆ ਗਿਆ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index aa117db..ec4cecb 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Jeśli następnym razem podasz nieprawidłowy kod PIN, profil służbowy oraz powiązane z nim dane zostaną usunięte."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Jeśli następnym razem podasz nieprawidłowe hasło, profil służbowy oraz powiązane z nim dane zostaną usunięte."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Dotknij czytnika linii papilarnych"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikona odcisku palca"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nie rozpoznaję twarzy. Użyj odcisku palca."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Dodano # element sterujący.}few{Dodano # elementy sterujące.}many{Dodano # elementów sterujących.}other{Dodano # elementu sterującego.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Usunięto"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Dodać aplikację <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Gdy dodasz aplikację <xliff:g id="APPNAME">%s</xliff:g>, będzie ona mogła dodawać elementy sterujące i treści do tego panelu. W niektórych aplikacjach można wybrać elementy sterujące, które się tu pojawią."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"Aplikacja <xliff:g id="APPNAME">%s</xliff:g> może wybrać elementy sterujące i treści, które się tu pojawią."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Usunąć elementy sterujące aplikacji <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Dodano do ulubionych"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Dodano do ulubionych, pozycja <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Usunięto z ulubionych"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Inne"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Dodaj do sterowania urządzeniami"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Dodaj"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Usuń"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Sugestia: <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Urządzenie zablokowane"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Pokazywać urządzenia i umożliwiać sterowanie nimi na ekranie blokady?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Możesz dodać do ekranu blokady elementy sterujące dotyczące urządzeń zewnętrznych.\n\nMożesz mieć możliwość sterowania niektórymi urządzeniami za pomocą aplikacji na telefonie lub tablecie bez odblokowywania tych urządzeń.\n\nW dowolnej chwili możesz wprowadzić zmiany w Ustawieniach."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Sterować urządzeniami na ekranie blokady?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Możesz sterować niektórymi urządzeniami bez odblokowywania telefonu lub tabletu.\n\nTo, którymi urządzeniami możesz sterować w ten sposób, określa aplikacja na urządzeniu."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Możesz sterować niektórymi urządzeniami bez odblokowywania telefonu lub tabletu. Aplikacja urządzenia określa, którymi urządzeniami możesz sterować w ten sposób."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Nie, dziękuję"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Tak"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Kod PIN zawiera litery lub symbole"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Dodaj elementy sterujące"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Edytuj elementy sterujące"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Dodaj aplikację"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Usuń aplikację"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Dodaj urządzenia wyjściowe"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Grupa"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Wybrano 1 urządzenie"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 5b3efde..f950f36 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Se você informar um PIN incorreto na próxima tentativa, seu perfil de trabalho e os dados dele serão excluídos."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Se você informar uma senha incorreta na próxima tentativa, seu perfil de trabalho e os dados dele serão excluídos."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Toque no sensor de impressão digital"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ícone de impressão digital"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Não foi possível reconhecer o rosto Use a impressão digital."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -401,7 +400,7 @@
     <string name="media_projection_action_text" msgid="3634906766918186440">"Iniciar agora"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Sem notificações"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Nenhuma notificação nova"</string>
-    <string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Desbloqueie para conferir as notificações antigas"</string>
+    <string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Desbloqueie p/ acessar notificações antigas"</string>
     <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Este dispositivo é gerenciado pelo seu familiar responsável"</string>
     <string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Sua organização é dona deste dispositivo e pode monitorar o tráfego de rede"</string>
     <string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"A organização <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> é dona deste dispositivo e pode monitorar o tráfego de rede"</string>
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# controle adicionado.}one{# controle adicionado.}many{# de controles adicionados.}other{# controles adicionados.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Removido"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Adicionar o app <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Quando você adiciona o app <xliff:g id="APPNAME">%s</xliff:g>, ele pode incluir controles e conteúdo neste painel. Em alguns casos, é possível escolher quais controles aparecem aqui."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> pode escolher quais controles e conteúdos aparecem aqui."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Remover controles do app <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Adicionado como favorito"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Adicionado como favorito (posição <xliff:g id="NUMBER">%d</xliff:g>)"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Removido dos favoritos"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Outro"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Adicionar aos controles do dispositivo"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Adicionar"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Remover"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Sugerido por <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Dispositivo bloq."</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Mostrar e controlar dispositivos na tela de bloqueio?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Você pode adicionar à tela de bloqueio controles para dispositivos externos.\n\nO app do dispositivo pode permitir que você controle alguns dispositivos sem desbloquear o smartphone ou tablet.\n\nÉ possível fazer mudanças a qualquer momento nas Configurações."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Controlar dispositivos na tela de bloqueio?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"É possível controle alguns dispositivos sem desbloquear o smartphone ou tablet.\n\nO app do dispositivo determina quais dispositivos podem ser controlados dessa maneira."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"É possível controlar alguns dispositivos sem desbloquear o smartphone ou tablet. O app determina quais dispositivos podem ser controlados dessa maneira."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Agora não"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Sim"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"O PIN contém letras ou símbolos"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Adicionar controles"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Editar controles"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Adicionar app"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Remover o app"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Adicionar saídas"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Grupo"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 dispositivo selecionado"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index eb314ba..78f179d 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -150,8 +150,8 @@
     <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Rosto reconhecido. Prima ícone de desbloqueio para continuar"</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autenticado"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Usar PIN"</string>
-    <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Utilizar padrão"</string>
-    <string name="biometric_dialog_use_password" msgid="3445033859393474779">"Utilizar palavra-passe"</string>
+    <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Usar padrão"</string>
+    <string name="biometric_dialog_use_password" msgid="3445033859393474779">"Usar palavra-passe"</string>
     <string name="biometric_dialog_wrong_pin" msgid="1878539073972762803">"PIN incorreto."</string>
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Padrão incorreto."</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Palavra-passe incorreta."</string>
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Se introduzir um PIN incorreto na tentativa seguinte, o seu perfil de trabalho e os respetivos dados serão eliminados."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Se introduzir uma palavra-passe incorreta na tentativa seguinte, o seu perfil de trabalho e os respetivos dados serão eliminados."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Toque no sensor de impressões digitais."</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ícone de impressão digital"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Impos. reconh. rosto. Utilize a impressão digital."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -696,7 +695,7 @@
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Ecrã de bloqueio"</string>
     <string name="thermal_shutdown_title" msgid="2702966892682930264">"Telem. deslig. devido ao calor"</string>
     <string name="thermal_shutdown_message" msgid="6142269839066172984">"O seu telemóvel já está a funcionar normalmente.\nToque para obter mais informações."</string>
-    <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"O telemóvel estava muito quente, por isso desligou-se para arrefecer. Agora funciona normalmente.\n\nO telemóvel pode sobreaquecer se:\n	• Utilizar aplicações que utilizam mais recursos (jogos, vídeo ou aplicações de navegação)\n	• Transferir ou carregar ficheiros grandes\n	• Utilizar em altas temperaturas"</string>
+    <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"O telemóvel estava muito quente, por isso desligou-se para arrefecer. Agora funciona normalmente.\n\nO telemóvel pode sobreaquecer se:\n	• Usar aplicações que utilizam mais recursos (jogos, vídeo ou aplicações de navegação)\n	• Transferir ou carregar ficheiros grandes\n	• Usar em altas temperaturas"</string>
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Veja os passos de manutenção"</string>
     <string name="high_temp_title" msgid="2218333576838496100">"O telemóvel está a aquecer"</string>
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Algumas funcionalidades são limitadas enquanto o telemóvel arrefece.\nToque para obter mais informações."</string>
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# controlo adicionado.}many{# controlos adicionados.}other{# controlos adicionados.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Removido"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Adicionar <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Quando adicionar a app <xliff:g id="APPNAME">%s</xliff:g>, esta pode adicionar controlos e conteúdos a este painel. Em algumas apps, pode escolher que controlos são apresentados aqui."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"A app <xliff:g id="APPNAME">%s</xliff:g> pode escolher que controlos e conteúdos são apresentados aqui."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Remover controlos para a app <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Adicionado aos favoritos"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Adicionados aos favoritos, posição <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Removido dos favoritos"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Outro"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Adicione aos controlos de dispositivos"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Adicionar"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Remover"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Sugerido por <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Dispositivo bloq."</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Mostrar e controlar dispositivos a partir do ecrã de bloqueio?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Pode adicionar controlos para os seus dispositivos externos ao ecrã de bloqueio.\n\nA app do dispositivo pode permitir controlar alguns dispositivos sem desbloquear o seu telemóvel ou tablet.\n\nPode fazer alterações em qualquer altura nas Definições."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Controlar dispositivos a partir do ecrã de bloqueio?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Pode controlar alguns dispositivos sem desbloquear o seu telemóvel ou tablet.\n\nA app do dispositivo determina que dispositivos podem ser controlados desta forma."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Pode controlar alguns dispositivos sem desbloquear o seu telemóvel ou tablet. A app do dispositivo determina que dispositivos podem ser controlados desta forma."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Não"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Sim"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"O PIN contém letras ou símbolos."</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Adicionar controlos"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Editar controlos"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Adicionar app"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Remover app"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Adicione saídas"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Grupo"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 dispositivo selecionado"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 5b3efde..f950f36 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Se você informar um PIN incorreto na próxima tentativa, seu perfil de trabalho e os dados dele serão excluídos."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Se você informar uma senha incorreta na próxima tentativa, seu perfil de trabalho e os dados dele serão excluídos."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Toque no sensor de impressão digital"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ícone de impressão digital"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Não foi possível reconhecer o rosto Use a impressão digital."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -401,7 +400,7 @@
     <string name="media_projection_action_text" msgid="3634906766918186440">"Iniciar agora"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Sem notificações"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Nenhuma notificação nova"</string>
-    <string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Desbloqueie para conferir as notificações antigas"</string>
+    <string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Desbloqueie p/ acessar notificações antigas"</string>
     <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Este dispositivo é gerenciado pelo seu familiar responsável"</string>
     <string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Sua organização é dona deste dispositivo e pode monitorar o tráfego de rede"</string>
     <string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"A organização <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> é dona deste dispositivo e pode monitorar o tráfego de rede"</string>
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# controle adicionado.}one{# controle adicionado.}many{# de controles adicionados.}other{# controles adicionados.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Removido"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Adicionar o app <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Quando você adiciona o app <xliff:g id="APPNAME">%s</xliff:g>, ele pode incluir controles e conteúdo neste painel. Em alguns casos, é possível escolher quais controles aparecem aqui."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> pode escolher quais controles e conteúdos aparecem aqui."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Remover controles do app <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Adicionado como favorito"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Adicionado como favorito (posição <xliff:g id="NUMBER">%d</xliff:g>)"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Removido dos favoritos"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Outro"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Adicionar aos controles do dispositivo"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Adicionar"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Remover"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Sugerido por <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Dispositivo bloq."</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Mostrar e controlar dispositivos na tela de bloqueio?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Você pode adicionar à tela de bloqueio controles para dispositivos externos.\n\nO app do dispositivo pode permitir que você controle alguns dispositivos sem desbloquear o smartphone ou tablet.\n\nÉ possível fazer mudanças a qualquer momento nas Configurações."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Controlar dispositivos na tela de bloqueio?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"É possível controle alguns dispositivos sem desbloquear o smartphone ou tablet.\n\nO app do dispositivo determina quais dispositivos podem ser controlados dessa maneira."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"É possível controlar alguns dispositivos sem desbloquear o smartphone ou tablet. O app determina quais dispositivos podem ser controlados dessa maneira."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Agora não"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Sim"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"O PIN contém letras ou símbolos"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Adicionar controles"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Editar controles"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Adicionar app"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Remover o app"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Adicionar saídas"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Grupo"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 dispositivo selecionado"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index aced6bd..b8146da 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Dacă la următoarea încercare introduci un cod PIN incorect, profilul de serviciu și datele sale vor fi șterse."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Dacă la următoarea încercare introduci o parolă incorectă, profilul de serviciu și datele sale vor fi șterse."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Atinge senzorul de amprente"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Pictograma amprentă"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Chipul nu a fost recunoscut. Folosește amprenta."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{S-a adăugat # comandă.}few{S-au adăugat # comenzi.}other{S-au adăugat # de comenzi.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Eliminată"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Adaugi <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Când adaugi <xliff:g id="APPNAME">%s</xliff:g>, aplicația poate să adauge comenzi și conținut pe acest panou. În anumite aplicații, poți să alegi comenzile care se afișează aici."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> poate să aleagă comenzile și conținutul care se afișează aici."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Elimini comenzile pentru <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Marcată ca preferată"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Marcată ca preferată, poziția <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"S-a anulat marcarea ca preferată"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Altul"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Adaugă la comenzile dispozitivelor"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Adaugă"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Exclude"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Sugerat de <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Dispozitiv blocat"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Afișezi și controlezi dispozitivele de pe ecranul de blocare?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Poți adăuga comenzi pentru dispozitivele externe pe ecranul de blocare.\n\nAplicația de pe dispozitiv îți poate permite să controlezi unele dispozitive fără să deblochezi telefonul.\n\nPoți face modificări oricând în setări."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Controlezi dispozitivele de pe ecranul de blocare?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Poți controla unele dispozitive fără să deblochezi telefonul sau tableta.\n\nAplicația de pe dispozitiv stabilește dispozitivele care pot fi controlate astfel."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Poți controla unele dispozitive fără să deblochezi telefonul sau tableta. Aplicația de dispozitiv stabilește dispozitivele care pot fi controlate astfel."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Nu, mulțumesc"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Da"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Codul PIN conține litere sau simboluri"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Adaugă comenzi"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Editează comenzile"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Adaugă o aplicație"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Elimină aplicația"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Adaugă ieșiri"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Grup"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"S-a selectat un dispozitiv"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index f6459bb..1f4ffea 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Если вы неправильно введете PIN-код ещё раз, ваш рабочий профиль и его данные будут удалены."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Если вы неправильно введете пароль ещё раз, ваш рабочий профиль и его данные будут удалены."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Прикоснитесь к сканеру отпечатков пальцев."</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Значок отпечатка пальца"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Не удалось распознать лицо. Используйте отпечаток."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Добавлен # элемент управления.}one{Добавлен # элемент управления.}few{Добавлено # элемента управления.}many{Добавлено # элементов управления.}other{Добавлено # элемента управления.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Удалено"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Добавить приложение \"<xliff:g id="APPNAME">%s</xliff:g>\"?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Приложение \"<xliff:g id="APPNAME">%s</xliff:g>\" может добавить на эту панель элементы управления и контент. Некоторые приложения позволяют выбирать, какие элементы будут здесь показаны."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"Приложение \"<xliff:g id="APPNAME">%s</xliff:g>\" может выбирать, какой контент и настройки будут здесь показываться."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Удалить приложение \"<xliff:g id="APPNAME">%s</xliff:g>\" с панели управления устройствами?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Добавлено в избранное"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Добавлено в избранное на позицию <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Не добавлено в избранное"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Другое"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Добавьте виджеты управления устройствами"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Добавить"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Удалить"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Предложено приложением \"<xliff:g id="APP">%s</xliff:g>\""</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Устройство заблокировано"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Разрешить показывать устройства и управлять ими на заблокированном экране?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Вы можете добавить элементы управления внешними устройствами на заблокированный экран.\n\nПриложение на вашем устройстве может разрешать управление некоторыми устройствами с заблокированного экрана.\n\nИзменить параметры можно в любое время в настройках."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Управлять устройствами на заблокированном экране?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Вы можете управлять некоторыми устройствами с заблокированного телефона или планшета.\n\nКакими именно устройствами можно управлять, зависит от приложения на вашем устройстве."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Некоторыми устройствами можно управлять без разблокировки экрана на телефоне или планшете. Их точный перечень зависит от приложения на вашем устройстве."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Не сейчас"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Да"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-код содержит буквы или символы"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Добавить виджеты"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Изменить виджеты"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Добавить приложение"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Удалить приложение"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Добавление устройств вывода"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Группа"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Выбрано 1 устройство"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index e4838f9..f721788 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"ඔබ ඊළඟ උත්සාහයේදී වැරදි PIN එකක් ඇතුළු කළහොත්, ඔබේ කාර්යාල පැතිකඩ සහ එහි දත්ත මකනු ඇත."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"ඔබ ඊළඟ උත්සාහයේදී වැරදි මුරපදයක් ඇතුළු කළහොත්, ඔබේ කාර්යාල පැතිකඩ සහ එහි දත්ත මකනු ඇත."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ඇඟිලි සලකුණු සංවේදකය ස්පර්ශ කරන්න"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"ඇඟිලි සලකුණු නිරූපකය"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"මුහුණ හැඳිනිය නොහැක. ඒ වෙනුවට ඇඟිලි සලකුණ භාවිත ක."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,9 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# පාලනයක් එක් කර ඇත.}one{පාලන #ක් එක් කර ඇත.}other{පාලන #ක් එක් කර ඇත.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"ඉවත් කළා"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> එක් කරන්න ද?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"ඔබ <xliff:g id="APPNAME">%s</xliff:g> එක් කළ විට, එයට මෙම පැනලයට පාලන සහ අන්තර්ගතය එක් කළ හැක. සමහර යෙදුම්වල, ඔබට මෙහි පෙන්වන්නේ කුමන පාලන ද යන්න තෝරා ගැනීමට හැක."</string>
+    <!-- no translation found for controls_panel_authorization (7045551688535104194) -->
+    <skip />
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> සඳහා පාලන ඉවත් කරන්න ද?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"ප්‍රියතම කළා"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"ප්‍රියතම කළා, තත්ත්ව <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"ප්‍රියතම වෙතින් ඉවත් කළා"</string>
@@ -826,12 +827,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"වෙනත්"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"උපාංග පාලන වෙත එක් කරන්න"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"එක් කරන්න"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"ඉවත් කරන්න"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"යෝජනා කළේ <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"උපාංගය අගුලු දමා ඇත"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"අගුලු තිරයෙන් උපාංග පෙන්වීම සහ පාලනය සිදු කරන්නද?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"ඔබට ඔබගේ බාහිර උපාංග සඳහා පාලන අගුලු තිරයට එක් කළ හැකිය.\n\nඔබගේ උපාංග යෙදුම ඔබගේ දුරකථනය හෝ ටැබ්ලටය අගුලු හැරීමෙන් තොරව සමහර උපාංග පාලනය කිරීමට ඉඩ ලබා දේ.\n\nඔබට සැකසීම් තුළ ඕනෑම වේලාවක වෙනස් කිරීම් සිදු කළ හැකිය."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"අගුලු තිරයෙන් උපාංග පාලනය කරන්නද?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"ඔබගේ දුරකථනය හෝ ටැබ්ලටය අගුලු හැරීමෙන් තොරව ඔබට සමහර උපාංග පාලනය කළ හැකිය.\n\nඔබගේ උපාංග යෙදුම මේ ආකාරයෙන් පාලනය කළ හැකි උපාංග තීරණය කරයි."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"ඔබේ දුරකථනය හෝ ටැබ්ලටය අගුලු හැරීමෙන් තොරව ඔබට සමහර උපාංග පාලන කළ හැක. ඔබේ උපාංග යෙදුම මේ ආකාරයෙන් පාලන කළ හැකි උපාංග තීරණ කරයි."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"එපා ස්තුතියි"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"ඔව්"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN හි අකුරු හෝ සංකේත අඩංගු වේ"</string>
@@ -879,6 +881,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"පාලන එක් කරන්න"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"පාලන සංස්කරණය කරන්න"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"යෙදුම එක් කරන්න"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"යෙදුම ඉවත් කරන්න"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"ප්‍රතිදාන එක් කරන්න"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"සමූහය"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"උපාංග 1ක් තෝරන ලදී"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index db3b765..f226259 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ak pri ďalšom pokuse zadáte nesprávny PIN, váš pracovný profil a jeho dáta budú odstránené."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Ak pri ďalšom pokuse zadáte nesprávne heslo, váš pracovný profil a jeho dáta budú odstránené."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Dotknite sa senzora odtlačkov prstov"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikona odtlačku prsta"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Tvár sa nedá rozpoznať. Použite odtlačok prsta."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -401,7 +400,7 @@
     <string name="media_projection_action_text" msgid="3634906766918186440">"Spustiť"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Žiadne upozornenia"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Žiadne nové upozornenia"</string>
-    <string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Odomknutím si zobrazte staršie upozor."</string>
+    <string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Odomknutím zobrazíte staršie upozornenia"</string>
     <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Toto zariadenie spravuje tvoj rodič"</string>
     <string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Vaša organizácia spravuje toto zariadenie a môže sledovať sieťovú premávku"</string>
     <string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> vlastní toto zariadenie a môže sledovať sieťovú premávku"</string>
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Bol pridaný # ovládací prvok.}few{Boli pridané # ovládacie prvky.}many{# controls added.}other{Bolo pridaných # ovládacích prvkov.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Odstránené"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Chcete pridať aplikáciu <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Keď pridáte aplikáciu <xliff:g id="APPNAME">%s</xliff:g>, bude môcť pridať ovládanie a obsah na tento panel. V prípade niektorých aplikácií môžete vybrať, ktoré ovládacie prvky sa tu majú zobraziť."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> môže vybrať, ktoré ovládacie prvky a obsah sa tu majú zobrazovať."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Chcete odstrániť ovládanie aplikácie <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Pridané medzi obľúbené"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Pridané medzi obľúbené, pozícia <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Odstránené z obľúbených"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Iné"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Pridanie do ovládania zariadení"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Pridať"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Odstrániť"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Navrhuje <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Uzamknuté zariadenie"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Chcete zobrazovať a ovládať zariadenia na uzamknutej obrazovke?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Na uzamknutú obrazovku si môžete pridať ovládanie externých zariadení.\n\nAplikácia zariadenia vám môže umožniť ovládať niektoré zariadenia bez odomknutia telefónu či tabletu.\n\nZmeny môžete vykonať kedykoľvek v Nastaveniach."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Chcete ovládať zariadenia na uzamknutej obrazovke?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Niektoré zariadenia môžete ovládať bez odomknutia telefónu či tabletu.\n\nAplikácia zariadenia určuje, ktoré zariadenia sa dajú týmto spôsobom ovládať."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Niektoré zariadenia môžete ovládať bez odomknutia telefónu či tabletu. Aplikácia zariadenia určuje, ktoré zariadenia sa dajú týmto spôsobom ovládať."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Nie, vďaka"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Áno"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN obsahuje písmená či symboly"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Pridať ovládače"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Upraviť ovládače"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Pridať aplikáciu"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Odstrániť aplikáciu"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Pridanie výstupov"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Skupina"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 vybrané zariadenie"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 1d9c77c..3d04092 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Če pri naslednjem poskusu vnesete napačno kodo PIN, bodo delovni profil in podatki v njem izbrisani."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Če pri naslednjem poskusu vnesete napačno geslo, bodo delovni profil in podatki v njem izbrisani."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Dotaknite se tipala prstnih odtisov"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikona prstnih odtisov"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Obraza ni mogoče prepoznati. Uporabite prstni odtis."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# kontrolnik je dodan.}one{# kontrolnik je dodan.}two{# kontrolnika sta dodana.}few{# kontrolniki so dodani.}other{# kontrolnikov je dodanih.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Odstranjeno"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Želite dodati aplikacijo <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Ko dodate aplikacijo <xliff:g id="APPNAME">%s</xliff:g>, lahko ta doda kontrolnike in vsebino v to podokno. V nekaterih aplikacijah lahko izberete, kateri kontrolniki so prikazani tukaj."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"Aplikacija <xliff:g id="APPNAME">%s</xliff:g> lahko izbere, kateri kontrolniki in vsebine so prikazani tukaj."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Želite odstraniti kontrolnike za aplikacijo <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Dodano med priljubljene"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Dodano med priljubljene, položaj <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Odstranjeno iz priljubljenih"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Drugo"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Dodajanje med kontrolnike naprave"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Dodaj"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Odstrani"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Predlagala aplikacija <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Naprava je zaklenjena"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Želite prikazati in upravljati naprave na zaklenjenem zaslonu?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Kontrolnike za zunanje naprave lahko dodate na zaklenjen zaslon.\n\nAplikacija v napravi vam bo morda omogočala upravljanje nekaterih naprav brez odklepanja telefona ali tabličnega računalnika.\n\nTe spremembe lahko kadar koli izvedete v nastavitvah."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Želite upravljati naprave na zaklenjenem zaslonu?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Nekatere naprave lahko upravljate brez odklepanja telefona ali tabličnega računalnika.\n\nAplikacija v napravi določa, katere naprave je mogoče upravljati na ta način."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Nekatere naprave lahko upravljate brez odklepanja telefona ali tabličnega računalnika. Aplikacija v napravi določa, katere naprave je mogoče upravljati na ta način."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Ne, hvala"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Da"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Koda PIN vsebuje črke ali simbole"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Dodajte kontrolnike"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Uredite kontrolnike"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Dodaj aplikacijo"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Odstrani aplikacijo"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Dodajanje izhodov"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Skupina"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Izbrana je ena naprava"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 5524812..a348385 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Nëse fut një kod PIN të pasaktë në tentativën tjetër, profili yt i punës dhe të dhënat e tij do të fshihen."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Nëse fut një fjalëkalim të pasaktë në tentativën tjetër, profili yt i punës dhe të dhënat e tij do të fshihen."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Prek sensorin e gjurmës së gishtit"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikona e gjurmës së gishtit"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nuk mund ta dallojë fytyrën. Përdor më mirë gjurmën e gishtit."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{U shtua # kontroll.}other{U shtuan # kontrolle.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"E hequr"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Të shtohet <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Kur shton <xliff:g id="APPNAME">%s</xliff:g>, ai mund t\'i shtojë kontrolle dhe përmbajtje këtij paneli. Në disa aplikacione, mund të zgjedhësh se cilat kontrolle shfaqen këtu."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> mund të zgjedhë se cilat kontrolle dhe përmbajtje shfaqen këtu."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Të hiqen kontrollet për <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"E shtuar te të preferuarat"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"E shtuar te të preferuarat, pozicioni <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"E hequr nga të preferuarat"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Tjetër"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Shto te kontrollet e pajisjes"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Shto"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Hiq"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Sugjeruar nga <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Pajisja është e kyçur"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Të shfaqen dhe të kontrollohen pajisjet nga ekrani i kyçjes?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Mund të shtosh kontrolle për pajisjet e tua të jashtme në ekranin e kyçjes.\n\nAplikacioni në pajisjen tënde mund të të lejojë të kontrollosh disa pajisje pa shkyçur telefonin apo tabletin.\n\nMund të bësh ndryshime në çdo kohë te \"Cilësimet\"."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Të kontrollohen pajisjet nga ekrani i kyçjes?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Mund të kontrollosh disa pajisje pa shkyçur telefonin apo tabletin.\n\nAplikacioni në pajisjen tënde përcakton se cilat pajisje mund të kontrollohen në këtë mënyrë."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Mund të kontrollosh disa pajisje pa shkyçur telefonin apo tabletin tënd. Aplikacioni për pajisjen tënde përcakton se cilat pajisje mund të kontrollohen në këtë mënyrë."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Jo, faleminderit"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Po"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Kodi PIN përmban shkronja ose simbole"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Shto kontrollet"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Modifiko kontrollet"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Shto një aplikacion"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Hiqe aplikacionin"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Shto daljet"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Grupi"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 pajisje e zgjedhur"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index f9b3dd6..fef43eb 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ако унесете нетачан PIN при следећем покушају, избрисаћемо пословни профил и његове податке."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Ако унесете нетачну лозинку при следећем покушају, избрисаћемо пословни профил и његове податке."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Додирните сензор за отисак прста"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Икона отиска прста"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Лице није препознато. Користите отисак прста."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -401,7 +400,7 @@
     <string name="media_projection_action_text" msgid="3634906766918186440">"Започни"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Нема обавештења"</string>
     <string name="no_unseen_notif_text" msgid="395512586119868682">"Нема нових обавештења"</string>
-    <string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Откључајте да видите старија обавештења"</string>
+    <string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Откључајте за старија обавештења"</string>
     <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Овим уређајем управља родитељ"</string>
     <string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Организација је власник уређаја и може да надгледа мрежни саобраћај"</string>
     <string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> је власник овог уређаја и може да надгледа мрежни саобраћај"</string>
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# контрола је додата.}one{# контрола је додата.}few{# контроле су додате.}other{# контрола је додато.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Уклоњено"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Желите ли да додате <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Када додате апликацију <xliff:g id="APPNAME">%s</xliff:g>, она може да додаје контроле и садржај у ово окно. У неким апликацијама можете да изаберете које ће се контроле овде приказивати."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> може да одабере које контроле и садржај се приказују овде."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Желите да уклоните контроле за <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Означено је као омиљено"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Означено је као омиљено, <xliff:g id="NUMBER">%d</xliff:g>. позиција"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Уклоњено је из омиљених"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Друго"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Додајте у контроле уређаја"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Додај"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Уклони"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Предлаже <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Уређај је закључан"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Желите ли да приказујете и контролишете уређаје са закључаног екрана?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Можете да додате контроле за спољне уређаје на закључани екран.\n\nАпликација на уређају може да вам омогући да контролишете неке уређаје без откључавања телефона или таблета.\n\nТо можете да промените кад год желите у Подешавањима."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Желите ли да контролишете уређаје са закључаног екрана?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Неке уређаје можете да контролишете без откључавања телефона или таблета.\n\nАпликација на уређају одређује који уређаји могу да се контролишу на овај начин."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Неке уређаје можете да контролишете без откључавања телефона или таблета. Апликација на уређају одређује који уређаји могу да се контролишу на овај начин."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Не, хвала"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Да"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN садржи слова или симболе"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Додај контроле"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Измени контроле"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Додај апликацију"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Уклони апликацију"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Додајте излазе"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Група"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Изабран је 1 уређај"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 3ef8f35..3d1ed13 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Jobbprofilen och dess data raderas om du anger fel pinkod vid nästa försök."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Din jobbprofil och dess data raderas om du anger fel lösenord vid nästa försök."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Tryck på fingeravtryckssensorn"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikon för fingeravtryck"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ansiktet kändes inte igen. Använd fingeravtryck."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# kontroll har lagts till.}other{# kontroller har lagts till.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Har tagits bort"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Vill du lägga till <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"När du lägger till <xliff:g id="APPNAME">%s</xliff:g> kan den lägga till kontroller och innehåll i den här panelen. I vissa appar kan du styra vilka kontroller som visas här."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> kan välja vilka kontroller och vilket innehåll som visas här."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Vill du ta bort inställningarna för <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Har lagts till som favorit"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Har lagts till som favorit, plats <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Har tagits bort från favoriter"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Övrigt"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Lägg till i enhetsstyrning"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Lägg till"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Ta bort"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Förslag från <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Enheten är låst"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Vill du se och styra enheter på låsskärmen?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Du kan lägga till reglage att styra externa enheter med på låsskärmen.\n\nVissa enheter kan gå att styra med appen på enheten utan att du behöver låsa upp telefonen eller surfplattan.\n\nDu kan när som helst ändra detta i inställningarna."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Vill du styra enheter på låsskärmen?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Du kan styra vissa enheter utan att låsa upp telefonen eller surfplattan.\n\nVilka enheter som går att styra på det här sättet beror på appen på enheten."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Du kan styra vissa enheter utan att låsa upp telefonen eller surfplattan. Vilka enheter som går att styra på det här sättet beror på appen på enheten."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Nej tack"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Ja"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Pinkoden innehåller bokstäver eller symboler"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Lägg till snabbkontroller"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Redigera snabbkontroller"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Lägg till app"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Ta bort app"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Lägg till utgångar"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Grupp"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 enhet har valts"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 46ffaa5..b3d71a5 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ukiweka PIN isiyo sahihi utakapojaribu tena, wasifu wako wa kazini utafutwa pamoja na data yake."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Ukiweka nenosiri lisilo sahihi utakapojaribu tena, wasifu wako wa kazini utafutwa pamoja na data yake."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Gusa kitambua alama ya kidole"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Aikoni ya alama ya kidole"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Imeshindwa kutambua uso. Tumia alama ya kidole."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Umeweka kidhibiti #.}other{Umeweka vidhibiti #.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Kimeondolewa"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Ungependa kuweka <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Unapoweka <xliff:g id="APPNAME">%s</xliff:g>, inaweza kuweka vidhibiti na maudhui kwenye kidirisha hiki. Katika baadhi ya programu, unaweza kuchagua ni vidhibiti vipi vionekane hapa."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> inaweza kuchagua ni vidhibiti na maudhui yapi yatakayoonekana hapa."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Ungependa kuondoa vidhibiti vya <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Kimewekwa kwenye vipendwa"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Kimewekwa kwenye vipendwa, nafasi ya <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Kimeondolewa kwenye vipendwa"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Nyingine"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Weka kwenye vidhibiti vya vifaa"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Weka"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Ondoa"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Kimependekezwa na <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Kifaa kimefungwa"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Ungependa kuonyesha na udhibiti vifaa kwenye skrini iliyofungwa?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Unaweza kuweka vidhibiti kwa ajili ya vifaa vyako vya nje kwenye skrini iliyofungwa.\n\nProgramu ya kifaa chako huenda ikakuruhusu udhibiti baadhi ya vifaa bila kufungua simu au kompyuta kibao yako.\n\nUnaweza kufanya mabadiliko muda wowote kwenye Mipangilio."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Ungependa kudhibiti vifaa kwenye skrini iliyofungwa?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Unaweza kudhibiti baadhi ya vifaa bila kufungua simu au kompyuta kibao yako.\n\nProgramu ya kifaa chako hubainisha ni vifaa vipi vinaweza kudhibitiwa kwa njia hii."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Unaweza kudhibiti baadhi ya vifaa bila kufungua simu au kompyuta kibao yako. Programu ya kifaa chako hubainisha ni vifaa vipi vinaweza kudhibitiwa kwa njia hii."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Hapana"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Ndiyo"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN ina herufi au alama"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Weka vidhibiti"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Badilisha vidhibiti"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Weka programu"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Ondoa programu"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Weka vifaa vya kutoa sauti"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Kikundi"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Umechagua kifaa 1"</string>
diff --git a/packages/SystemUI/res/values-sw720dp-h1000dp/dimens.xml b/packages/SystemUI/res/values-sw720dp-h1000dp/dimens.xml
index b98165f..ca62d28 100644
--- a/packages/SystemUI/res/values-sw720dp-h1000dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp-h1000dp/dimens.xml
@@ -21,6 +21,6 @@
     <!-- Space between status view and notification shelf -->
     <dimen name="keyguard_status_view_bottom_margin">70dp</dimen>
     <dimen name="keyguard_clock_top_margin">80dp</dimen>
-    <dimen name="bouncer_user_switcher_view_mode_user_switcher_bottom_margin">186dp</dimen>
-    <dimen name="bouncer_user_switcher_view_mode_view_flipper_bottom_margin">110dp</dimen>
+    <dimen name="bouncer_user_switcher_view_mode_user_switcher_bottom_margin">155dp</dimen>
+    <dimen name="bouncer_user_switcher_view_mode_view_flipper_bottom_margin">85dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index f623ff1..53ecc5d 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"அடுத்த முறை தவறான பின்னை உள்ளிட்டால் உங்கள் பணிக் கணக்கும் அதன் தரவும் நீக்கப்படும்."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"அடுத்த முறை தவறான கடவுச்சொல்லை உள்ளிட்டால் உங்கள் பணிக் கணக்கும் அதன் தரவும் நீக்கப்படும்."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"கைரேகை சென்சாரைத் தொடவும்"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"கைரேகை ஐகான்"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"முகத்தை அடையாளம் காண முடியவில்லை. கைரேகையைப் பயன்படுத்தவும்."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -197,8 +196,7 @@
     <skip />
     <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"அறிவிப்பு விவரம்."</string>
     <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"உடனடி அமைப்பு."</string>
-    <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) -->
-    <skip />
+    <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"விரைவு அமைப்புகளும் அறிவிப்பு விவரமும்."</string>
     <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"லாக் ஸ்கிரீன்."</string>
     <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"பணி லாக் ஸ்கிரீன்"</string>
     <string name="accessibility_desc_close" msgid="8293708213442107755">"மூடு"</string>
@@ -809,7 +807,9 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# கட்டுப்பாடு சேர்க்கப்பட்டது.}other{# கட்டுப்பாடுகள் சேர்க்கப்பட்டன.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"அகற்றப்பட்டது"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> ஆப்ஸைச் சேர்க்கவா?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"இந்தப் பேனலில் <xliff:g id="APPNAME">%s</xliff:g> ஆப்ஸைச் சேர்க்கும்போது கட்டுப்பாடுகளையும் உள்ளடக்கத்தையும் அது சேர்க்கலாம். இருப்பினும், சில ஆப்ஸில் எந்தெந்தக் கட்டுப்பாடுகள் இங்கே காட்டப்பட வேண்டும் என்பதை நீங்களே தேர்வுசெய்யலாம்."</string>
+    <!-- no translation found for controls_panel_authorization (7045551688535104194) -->
+    <skip />
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> ஆப்ஸுக்கான கட்டுப்பாடுகளை அகற்றவா?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"பிடித்தவற்றில் சேர்க்கப்பட்டது"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"பிடித்தவற்றில் சேர்க்கப்பட்டது, நிலை <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"பிடித்தவற்றிலிருந்து நீக்கப்பட்டது"</string>
@@ -827,12 +827,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"பிற"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"சாதனக் கட்டுப்பாடுகளில் சேர்த்தல்"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"சேர்"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"அகற்று"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ஆப்ஸால் பரிந்துரைக்கப்பட்டது"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"சாதனம் பூட்டப்பட்டது"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"பூட்டுத் திரையிலிருந்தே சாதனங்களைப் பார்க்கவும் கட்டுப்படுத்தவும் அனுமதிக்கவா?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"வெளிப்புறச் சாதனங்களுக்கான கட்டுப்பாடுகளை உங்கள் பூட்டுத் திரையில் சேர்க்கலாம்.\n\nஉங்கள் மொபைலையோ டேப்லெட்டையோ அன்லாக் செய்யாமலேயே சில சாதனங்களைக் கட்டுப்படுத்த சாதன ஆப்ஸ் உங்களை அனுமதிக்கக்கூடும்.\n\nஅமைப்புகளுக்குச் சென்று எப்போது வேண்டுமானாலும் மாற்றங்களைச் செய்யலாம்."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"பூட்டுத் திரையிலிருந்தே சாதனங்களைக் கட்டுப்படுத்தவா?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"உங்கள் மொபைலையோ டேப்லெட்டையோ அன்லாக் செய்யாமலேயே சில சாதனங்களை நீங்கள் கட்டுப்படுத்தலாம்.\n\nஎந்தெந்தச் சாதனங்களை இவ்வாறு கட்டுப்படுத்தலாம் என்பதை உங்கள் சாதன ஆப்ஸ் தீர்மானிக்கும்."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"உங்கள் மொபைலையோ டேப்லெட்டையோ அன்லாக் செய்யாமலேயே சில சாதனங்களை நீங்கள் கட்டுப்படுத்தலாம். எந்தெந்தச் சாதனங்களை இவ்வாறு கட்டுப்படுத்தலாம் என்பதை உங்கள் சாதன ஆப்ஸ் தீர்மானிக்கும்."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"வேண்டாம்"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"ஆம்"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"பின்னில் எழுத்துகள் அல்லது குறிகள் உள்ளன"</string>
@@ -880,6 +881,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"கட்டுப்பாடுகளைச் சேர்த்தல்"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"கட்டுப்பாடுகளை மாற்றுதல்"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"ஆப்ஸைச் சேர்"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"ஆப்ஸை அகற்று"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"அவுட்புட்களைச் சேர்த்தல்"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"குழு"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 சாதனம் தேர்ந்தெடுக்கப்பட்டுள்ளது"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index a07cad6..45b73c0 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"మీరు ఒకవేళ తర్వాతి ప్రయత్నంలో తప్పు పిన్‌ను ఎంటర్ చేస్తే, మీ కార్యాలయ ప్రొఫైల్, అలాగే దాని డేటా తొలగించబడతాయి."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"మీరు ఒకవేళ తర్వాతి ప్రయత్నంలో తప్పు పాస్‌వర్డ్‌ను ఎంటర్ చేస్తే, మీ కార్యాలయ ప్రొఫైల్, అలాగే దాని డేటా తొలగించబడతాయి."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"వేలిముద్ర సెన్సార్‌ను తాకండి"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"వేలిముద్ర చిహ్నం"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ముఖం గుర్తించలేము. బదులుగా వేలిముద్ర ఉపయోగించండి."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# కంట్రోల్ జోడించబడింది.}other{# కంట్రోల్స్ జోడించబడ్డాయి.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"తీసివేయబడింది"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g>ను జోడించాలా?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"మీరు <xliff:g id="APPNAME">%s</xliff:g>ను జోడించినప్పుడు, ఇది ఈ ప్యానెల్‌కు కంట్రోల్స్‌ని, కంటెంట్‌ను జోడించగలదు. కొన్ని యాప్‌లలో, ఇక్కడ ఏయే కంట్రోల్స్ కనిపించాలో మీరు ఎంచుకోవచ్చు."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> ఇక్కడ ఏ కంట్రోల్స్, కంటెంట్ కనిపించాలో ఎంచుకోగలదు."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> కోసం కంట్రోల్స్‌ను తీసివేయాలా?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"ఇష్టమైనదిగా గుర్తు పెట్టబడింది"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"<xliff:g id="NUMBER">%d</xliff:g>వ స్థానంలో ఇష్టమైనదిగా గుర్తు పెట్టబడింది"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"ఇష్టమైనదిగా పెట్టిన గుర్తు తీసివేయబడింది"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ఇతరం"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"పరికరం నియంత్రణలకు జోడించడం"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"జోడించండి"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"తీసివేయండి"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ద్వారా సూచించబడింది"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"పరికరంలాక్ చేయబడింది"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"లాక్ స్క్రీన్ నుండి పరికరాలను చూపించాలా, కంట్రోల్ చేయాలా?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"మీరు లాక్ స్క్రీన్‌కు మీ బాహ్య పరికరాల కోసం కంట్రోల్స్‌ను జోడించవచ్చు.\n\nమీ ఫోన్ లేదా టాబ్లెట్‌ను అన్‌లాక్ చేయకుండానే కొన్ని పరికరాలను కంట్రోల్ చేయడానికి మీ పరికర యాప్ మిమ్మల్ని అనుమతించవచ్చు.\n\nమీరు సెట్టింగ్‌లలో ఎప్పుడైనా మార్పులు చేయవచ్చు."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"లాక్ స్క్రీన్ నుండి పరికరాలను కంట్రోల్ చేయాలా?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"మీరు మీ ఫోన్ లేదా టాబ్లెట్‌ను అన్‌లాక్ చేయకుండానే కొన్ని పరికరాలను కంట్రోల్ చేయవచ్చు.\n\nమీ పరికర యాప్ \'ఈ విధంగా ఏ పరికరాలను కంట్రోల్ చేయవచ్చు\' అని నిర్ణయిస్తుంది."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"మీరు మీ ఫోన్ లేదా టాబ్లెట్‌ను అన్‌లాక్ చేయకుండానే కొన్ని పరికరాలను కంట్రోల్ చేయవచ్చు. ఈ విధంగా ఏ పరికరాలను కంట్రోల్ చేయవచ్చో మీ డివైజ్ యాప్ నిర్ణయిస్తుంది."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"వద్దు, ధన్యవాదాలు"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"అవును"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"పిన్ అక్షరాలను లేదా చిహ్నాలను కలిగి ఉంది"</string>
@@ -873,12 +874,13 @@
     <string name="controls_error_removed" msgid="6675638069846014366">"కనుగొనబడలేదు"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"కంట్రోల్ అందుబాటులో లేదు"</string>
     <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g>ను యాక్సెస్ చేయడం సాధ్యపడలేదు. <xliff:g id="APPLICATION">%2$s</xliff:g> యాప్‌ను చెక్ చేసి, కంట్రోల్ ఇప్పటికీ అందుబాటులో ఉందని, యాప్ సెట్టింగ్‌లు మారలేదని నిర్ధారించుకోండి."</string>
-    <string name="controls_open_app" msgid="483650971094300141">"యాప్‌ను తెరువు"</string>
+    <string name="controls_open_app" msgid="483650971094300141">"యాప్‌‌ను తెరవండి"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"స్టేటస్ లోడ్ చేయడం సాధ్యపడలేదు"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"ఎర్రర్, మళ్లీ ప్రయత్నించండి"</string>
     <string name="controls_menu_add" msgid="4447246119229920050">"కంట్రోల్స్‌ను జోడించండి"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"కంట్రోల్స్‌ను ఎడిట్ చేయండి"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"యాప్‌ను జోడించండి"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"యాప్‌ను తీసివేయండి"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"అవుట్‌పుట్‌లను జోడించండి"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"గ్రూప్"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 పరికరం ఎంచుకోబడింది"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 3367887..c523d97 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -19,7 +19,7 @@
 
 <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">"อินเทอร์เฟซผู้ใช้ของระบบ"</string>
+    <string name="app_label" msgid="4811759950673118541">"UI ของระบบ"</string>
     <string name="battery_low_title" msgid="5319680173344341779">"เปิดโหมดประหยัดแบตเตอรี่ใช่ไหม"</string>
     <string name="battery_low_description" msgid="3282977755476423966">"คุณมีแบตเตอรี่เหลืออยู่ <xliff:g id="PERCENTAGE">%s</xliff:g> โหมดประหยัดแบตเตอรี่จะเปิดธีมมืด จำกัดกิจกรรมในเบื้องหลัง และหน่วงเวลาการแจ้งเตือน"</string>
     <string name="battery_low_intro" msgid="5148725009653088790">"โหมดประหยัดแบตเตอรี่จะเปิดธีมมืด จำกัดกิจกรรมในเบื้องหลัง และหน่วงเวลาการแจ้งเตือน"</string>
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"หากคุณป้อน PIN ไม่ถูกต้องในความพยายามครั้งถัดไป ระบบจะลบโปรไฟล์งานและข้อมูลในโปรไฟล์"</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"หากคุณป้อนรหัสผ่านไม่ถูกต้องในความพยายามครั้งถัดไป ระบบจะลบโปรไฟล์งานและข้อมูลในโปรไฟล์"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"แตะเซ็นเซอร์ลายนิ้วมือ"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"ไอคอนลายนิ้วมือ"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ไม่รู้จักใบหน้า ใช้ลายนิ้วมือแทน"</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{เพิ่มตัวควบคุม # ตัวแล้ว}other{เพิ่มตัวควบคุม # ตัวแล้ว}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"นำออกแล้ว"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"เพิ่ม <xliff:g id="APPNAME">%s</xliff:g> ไหม"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"เมื่อเพิ่ม <xliff:g id="APPNAME">%s</xliff:g> คุณจะเพิ่มการควบคุมและเนื้อหาไปยังแผงนี้ได้ ในบางแอป คุณเลือกได้ว่าต้องการให้การควบคุมใดปรากฏขึ้นที่นี่"</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> สามารถเลือกตัวควบคุมและเนื้อหาที่จะปรากฏขึ้นที่นี่"</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"นำการควบคุมสำหรับ <xliff:g id="APPNAME">%s</xliff:g> ออกไหม"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"ตั้งเป็นรายการโปรดแล้ว"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"ตั้งเป็นรายการโปรดแล้ว โดยอยู่ลำดับที่ <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"นำออกจากรายการโปรดแล้ว"</string>
@@ -826,14 +826,15 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"อื่นๆ"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"เพิ่มไปยังระบบควบคุมอุปกรณ์"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"เพิ่ม"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"นำออก"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"แนะนำโดย <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"อุปกรณ์ถูกล็อก"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"แสดงและควบคุมอุปกรณ์จากหน้าจอล็อกไหม"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"คุณเพิ่มการควบคุมอุปกรณ์ภายนอกลงในหน้าจอล็อกได้\n\nแอปของอุปกรณ์อาจอนุญาตให้คุณควบคุมอุปกรณ์บางอย่างได้โดยไม่ต้องปลดล็อกโทรศัพท์หรือแท็บเล็ต\n\nคุณเปลี่ยนแปลงได้ทุกเมื่อในการตั้งค่า"</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"ควบคุมอุปกรณ์จากหน้าจอล็อกไหม"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"คุณควบคุมอุปกรณ์บางอย่างได้โดยไม่ต้องปลดล็อกโทรศัพท์หรือแท็บเล็ต\n\nแอปของอุปกรณ์จะระบุอุปกรณ์ที่สามารถควบคุมด้วยวิธีนี้ได้"</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"คุณควบคุมอุปกรณ์บางอย่างได้โดยไม่ต้องปลดล็อกโทรศัพท์หรือแท็บเล็ต แอปจัดการอุปกรณ์จะระบุอุปกรณ์ที่สามารถควบคุมด้วยวิธีนี้ได้"</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"ไม่เป็นไร"</string>
-    <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"มี"</string>
+    <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"ใช่"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN ประกอบด้วยตัวอักษรหรือสัญลักษณ์"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"ยืนยัน <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN ไม่ถูกต้อง"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"เพิ่มตัวควบคุม"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"แก้ไขตัวควบคุม"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"เพิ่มแอป"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"นำแอปออก"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"เพิ่มเอาต์พุต"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"กลุ่ม"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"เลือกอุปกรณ์ไว้ 1 รายการ"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 0c8bd82..93f8177 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Kung maling PIN ang mailalagay mo sa susunod na pagsubok, made-delete ang iyong profile sa trabaho at ang data nito."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Kung maling password ang mailalagay mo sa susunod na pagsubok, made-delete ang iyong profile sa trabaho at ang data nito."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Pindutin ang fingerprint sensor"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Icon ng fingerprint"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Hindi makilala ang mukha. Gumamit ng fingerprint."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Nagdagdag ng # kontrol.}one{Nagdagdag ng # kontrol.}other{Nagdagdag ng # na kontrol.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Inalis"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Idagdag ang <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Kapag idinagdag mo ang <xliff:g id="APPNAME">%s</xliff:g>, puwede itong magdagdag ng mga kontrol at content sa panel na ito. Sa ilang app, puwede mong piliin kung aling mga kontrol ang lalabas dito."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"Mapipili ng <xliff:g id="APPNAME">%s</xliff:g> kung aling mga kontrol at content ang lalabas dito."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Alisin ang mga kontrol para sa <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Ginawang paborito"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Ginawang paborito, posisyon <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Inalis sa paborito"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Iba pa"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Idagdag sa mga kontrol ng device"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Idagdag"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Alisin"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Iminungkahi ng <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Naka-lock ang device"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Ipakita at kontrolin ang mga device mula sa lock screen?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Puwede kang magdagdag ng mga kontrol para sa iyong mga external device sa lock screen.\n\nPosibleng payagan ka ng app ng iyong device na kontrolin ang ilang device nang hindi ina-unlock ang telepono o tablet mo.\n\nPuwede kang magsagawa ng mga pagbabago anumang oras sa Mga Setting."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Kontrolin ang mga device mula sa lock screen?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Puwede mong kontrolin ang ilang device nang hindi ina-unlock ang iyong telepono o tablet.\n\nNakadepende sa app ng iyong device kung aling mga device ang puwedeng kontrolin sa ganitong paraan."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Puwede mong kontrolin ang ilang device nang hindi ina-unlock ang iyong telepono o tablet. Nakadepende sa app ng iyong device kung aling mga device ang puwedeng kontrolin sa ganitong paraan."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Huwag na lang"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Oo"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"May mga titik o simbolo ang PIN"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Magdagdag ng mga kontrol"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Mag-edit ng mga kontrol"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Magdagdag ng app"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Alisin ang app"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Magdagdag ng mga output"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Grupo"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 device ang napili"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 86d38da..7982ada 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Bir sonraki denemenizde yanlış PIN girerseniz iş profiliniz ve verileri silinir."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Bir sonraki denemenizde yanlış şifre girerseniz iş profiliniz ve verileri silinir."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Parmak izi sensörüne dokunun"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Parmak izi simgesi"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Yüz tanınamadı. Bunun yerine parmak izi kullanın."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,9 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# kontrol eklendi.}other{# kontrol eklendi.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Kaldırıldı"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> eklensin mi?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"<xliff:g id="APPNAME">%s</xliff:g> uygulamasını eklerseniz bu panele kontrol ve içerik ekleyebilir. Bazı uygulamalarda, burada hangi kontrollerin görüneceğini seçebilirsiniz."</string>
+    <!-- no translation found for controls_panel_authorization (7045551688535104194) -->
+    <skip />
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> için denetimler kaldırılsın mı?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Favoriler listesine eklendi"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Favorilere eklendi, konum: <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Favorilerden kaldırıldı"</string>
@@ -826,12 +827,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Diğer"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Cihaz denetimlerine ekle"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Ekle"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Kaldır"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> tarafından önerildi"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Cihaz kilitlendi"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Cihazlar kilit ekranında gösterilip buradan kontrol edilsin mi?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Kilit ekranına harici cihazlarınız için kontroller ekleyebilirsiniz.\n\nCihaz uygulamanız, bazı cihazları telefonunuzun veya tabletinizin kilidini açmadan kontrol etmenize izin verebilir.\n\nAyarlar\'da istediğiniz zaman değişiklik yapabilirsiniz."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Cihazlar kilit ekranından kontrol edilsin mi?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Bazı cihazları telefonunuzun veya tabletinizin kilidini açmadan kontrol edebilirsiniz.\n\nHangi cihazların bu şekilde kontrol edilebileceğini cihaz uygulamanız belirler."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Bazı cihazları telefonunuzun veya tabletinizin kilidini açmadan kontrol edebilirsiniz.Hangi cihazların bu şekilde kontrol edilebileceğini cihaz uygulamanız belirler."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Hayır, teşekkürler"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Evet"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN, harf veya simge içerir"</string>
@@ -879,6 +881,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Denetim ekle"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Denetimleri düzenle"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Uygulama ekle"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Uygulamayı kaldır"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Çıkışlar ekleyin"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Grup"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 cihaz seçildi"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index f544fcd..ffe5c83 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Якщо наступного разу ви введете неправильний PIN-код, ваш робочий профіль і його дані буде видалено."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Якщо наступного разу ви введете неправильний пароль, ваш робочий профіль і його дані буде видалено."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Торкніться сканера відбитків пальців"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Значок відбитка пальця"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Обличчя не розпізнано. Скористайтеся відбитком пальця."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -234,7 +233,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Джерело сигналу"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Слухові апарати"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Увімкнення…"</string>
-    <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Автоматичне обертання"</string>
+    <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Автообертання"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Автоматично обертати екран"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Геодані"</string>
     <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Заставка"</string>
@@ -808,7 +807,9 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Додано # елемент керування.}one{Додано # елемент керування.}few{Додано # елементи керування.}many{Додано # елементів керування.}other{Додано # елемента керування.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Вилучено"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Долучити додаток <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Якщо ви долучите додаток <xliff:g id="APPNAME">%s</xliff:g>, він зможе розміщувати елементи керування й контент на цій панелі. У деяких додатках можна вибрати, які елементи керування тут відображатимуться."</string>
+    <!-- no translation found for controls_panel_authorization (7045551688535104194) -->
+    <skip />
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Вилучити елементи керування для додатка <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Додано у вибране"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Додано у вибране, позиція <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Видалено з вибраного"</string>
@@ -826,12 +827,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Інше"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Додати до елементів керування пристроями"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Додати"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Вилучити"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Запропоновано додатком <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Пристрій заблоковано"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Переглядати пристрої та керувати ними на заблокованому екрані?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Елементи керування зовнішніми пристроями можна додавати на заблокований екран.\n\nЗа допомогою спеціального додатка ви можете керувати деякими пристроями, не розблоковуючи телефон або планшет.\n\nВи можете будь-коли вносити зміни в налаштуваннях."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Керувати пристроями на заблокованому екрані?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Ви можете керувати деякими пристроями, не розблоковуючи телефон або планшет.\n\nЯкими пристроями можна керувати в такий спосіб, визначає додаток на пристрої."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Ви можете керувати деякими пристроями, не розблоковуючи телефон або планшет. Якими пристроями можна керувати в такий спосіб, визначає додаток пристрою."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Ні, дякую"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Так"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-код містить літери чи символи"</string>
@@ -879,6 +881,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Додати елементи керування"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Змінити елементи керування"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Долучити додаток"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Вилучити додаток"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Додати пристрої виводу"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Група"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Вибрано 1 пристрій"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 0cc29aa..793d733 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"‏اگر آپ نے اگلی کوشش میں غلط PIN درج کیا تو آپ کی دفتری پروفائل اور اس کا ڈیٹا حذف کر دیا جائے گا۔"</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"اگر آپ نے اگلی کوشش میں غلط پاس ورڈ درج کیا تو آپ کی دفتری پروفائل اور اس کا ڈیٹا حذف کر دیا جائے گا۔"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"فنگر پرنٹ سینسر پر ٹچ کریں"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"فنگر پرنٹ آئیکن"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"چہرے کی شناخت نہیں ہو سکی۔ اس کے بجائے فنگر پرنٹ استعمال کریں۔"</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# کنٹرول کو شامل کیا گیا۔}other{# کنٹرولز کو شامل کیا گیا۔}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"ہٹا دیا گیا"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> کو شامل کریں؟"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"جب آپ <xliff:g id="APPNAME">%s</xliff:g> کو شامل کرتے ہیں، تو یہ اس پینل میں کنٹرولز اور مواد کو شامل کر سکتا ہے۔ کچھ ایپس میں، آپ یہ منتخب کر سکتے ہیں کہ کون سے کنٹرولز یہاں ظاہر ہوں۔"</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> انتخاب کر سکتی ہے کہ یہاں کون سے کنٹرولز اور مواد دکھایا جائے۔"</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> کے کنٹرولز کو ہٹا دیں؟"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"پسند کردہ"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"پسند کردہ، پوزیشن <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"ناپسند کردہ"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"دیگر"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"آلہ کے کنٹرولز میں شامل کریں"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"شامل کریں"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"ہٹائیں"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> کی طرف سے تجویز کردہ"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"آلہ مقفل کر دیا گیا"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"لاک اسکرین سے آلات دکھائیں اور کنٹرول کریں؟"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"آپ اپنے بیرونی آلات کے لیے لاک اسکرین پر کنٹرولز شامل کر سکتے ہیں۔\n\nآپ کے آلے کی ایپ آپ کو اپنے فون یا ٹیبلیٹ کو غیر مقفل کیے بغیر کچھ آلات کو کنٹرول کرنے کی اجازت دے سکتی ہے۔\n\nآپ ترتیبات میں کسی بھی وقت تبدیلیاں کر سکتے ہیں۔"</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"لاک اسکرین سے آلات کو کنٹرول کریں؟"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"آپ اپنے فون یا ٹیبلیٹ کو غیر مقفل کیے بغیر کچھ آلات کو کنٹرول کر سکتے ہیں۔\n\nآپ کے آلے کی ایپ اس بات کا تعین کرتی ہے کہ اس طرح کن آلات کو کنٹرول کیا جا سکتا ہے۔"</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"آپ اپنے فون یا ٹیبلیٹ کو غیر مقفل کیے بغیر کچھ آلات کو کنٹرول کر سکتے ہیں۔ آپ کے آلے کی ایپ اس بات کا تعین کرتی ہے کہ اس طرح کن آلات کو کنٹرول کیا جا سکتا ہے۔"</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"نہیں شکریہ"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"ہاں"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"‏PIN میں حروف یا علامات شامل ہیں"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"کنٹرولز شامل کریں"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"کنٹرولز میں ترمیم کریں"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"ایپ شامل کریں"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"ایپ ہٹائیں"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"آؤٹ پٹس شامل کریں"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"گروپ"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 آلہ منتخب کیا گیا"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 836fea2..6eba5b2 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Agar PIN kodni xato kiritsangiz, ish profili va undagi maʼlumotlar oʻchirib tashlanadi."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Agar parolni xato kiritsangiz, ish profili va undagi maʼlumotlar oʻchirib tashlanadi."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Barmoq izi skaneriga tegining"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Barmoq izi belgisi"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Bu yuz notanish. Barmoq izi orqali urining."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# ta boshqaruv elementi kiritildi.}other{# ta boshqaruv elementi kiritildi.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Olib tashlandi"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> qoʻshilsinmi?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"<xliff:g id="APPNAME">%s</xliff:g> bu panelga boshqaruv elementlari va kontent qoʻshishi mumkin. Ayrim ilovalarda bu yerda qaysi elementlar chiqishini tanlashingiz mumkin."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> bu yerda qaysi kontent va sozlamalar chiqishini tanlay oladi."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> qurilma boshqaruv panelidan olib tashlansinmi?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Saralanganlarga kiritilgan"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Saralanganlarga kiritilgan, <xliff:g id="NUMBER">%d</xliff:g>-joy"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Saralanganlardan olib tashlangan"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Boshqa"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Qurilma boshqaruv elementlariga kiritish"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Kiritish"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Olib tashlash"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> taklif etgan"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Qurilma qulflandi"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Qurilmalar qulflangan ekranda koʻrsatilsinmi va boshqarilsinmi?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Tashqi qurilmalaringiz uchun ekran qulfiga boshqaruvlarni qoʻshishingiz mumkin.\n\nQurilma ilovasi ayrim qurilmalarni telefon yoki planshet qulfini ochmasdan boshqarish imkonini beradi.\n\nIstalgan vaqtda Sozlamalar orqali oʻzgartirish mumkin."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Qurilmalar ekran qulfidan boshqarilsinmi?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Ayrim qurilmalarni telefon yoki planshet ekran qulfini ochmasdan boshqarish mumkin.\n\nQurilmangiz ilovasi qaysi qurilmalarni shu tarzda boshqarish mumkinligini aniqlaydi."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Ayrim qurilmalarni telefon yoki planshet ekran qulfini ochmasdan boshqarish mumkin. Qurilmangiz ilovasi qaysi qurilmalarni shu tarzda boshqarish mumkinligini aniqlaydi."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Yopish"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Ha"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Harflar yoki maxsus belgilardan iborat PIN kod"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Element kiritish"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Elementlarni tahrirlash"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Ilova kiritish"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Ilovani olib tashlash"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Chiquvchi qurilmani kiritish"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Guruh"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 ta qurilma tanlandi"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index ec893ed..5cd6afe 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Nếu bạn nhập mã PIN không chính xác vào lần thử tiếp theo, thì hồ sơ công việc của bạn và dữ liệu của hồ sơ công việc sẽ bị xóa."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Nếu bạn nhập mật khẩu không chính xác vào lần thử tiếp theo, thì hồ sơ công việc của bạn và dữ liệu của hồ sơ công việc sẽ bị xóa."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Chạm vào cảm biến vân tay"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Biểu tượng vân tay"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Không thể nhận dạng khuôn mặt. Hãy dùng vân tay."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Đã thêm # chế độ điều khiển.}other{Đã thêm # chế độ điều khiển.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Đã xóa"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Thêm <xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Khi bạn thêm <xliff:g id="APPNAME">%s</xliff:g>, ứng dụng có thể bổ sung các chế độ điều khiển và nội dung vào bảng điều khiển này. Trong một số ứng dụng, bạn có thể chọn chế độ điều khiển nào sẽ hiển thị tại đây."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> có thể chọn các nút điều khiển và nội dung hiện ở đây."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Xoá chế độ cài đặt cho <xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Được yêu thích"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Được yêu thích, vị trí số <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Không được yêu thích"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Khác"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Thêm vào mục điều khiển thiết bị"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Thêm"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Xoá"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Do <xliff:g id="APP">%s</xliff:g> đề xuất"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Đã khóa thiết bị"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Bạn muốn hiện và điều khiển các thiết bị từ màn hình khoá?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Bạn có thể thêm các chế độ điều khiển cho những thiết bị bên ngoài vào màn hình khoá.\n\nỨng dụng thiết bị có thể cho phép bạn điều khiển một số thiết bị mà không cần mở khoá điện thoại hoặc máy tính bảng.\n\nBạn có thể thay đổi chế độ cài đặt này bất cứ lúc nào trong phần Cài đặt."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Bạn muốn điều khiển các thiết bị từ màn hình khoá?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Bạn có thể điều khiển một số thiết bị mà không cần mở khoá điện thoại hoặc máy tính bảng.\n\nỨng dụng thiết bị sẽ xác định thiết bị mà bạn có thể điều khiển bằng cách này."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Bạn có thể điều khiển một số thiết bị mà không cần mở khoá điện thoại hoặc máy tính bảng. Ứng dụng thiết lập và quản lý thiết bị phụ sẽ xác định thiết bị mà bạn có thể điều khiển bằng cách này."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Không, cảm ơn"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Có"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Mã PIN chứa các ký tự hoặc ký hiệu"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Thêm các tùy chọn điều khiển"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Chỉnh sửa tùy chọn điều khiển"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Thêm ứng dụng"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Xoá ứng dụng"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Thêm thiết bị đầu ra"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Nhóm"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"Đã chọn 1 thiết bị"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 7edc6ce..14b4667 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"如果您下次输入的 PIN 码仍然有误,您的工作资料及其相关数据将会被删除。"</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"如果您下次输入的密码仍然有误,您的工作资料及其相关数据将会被删除。"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"请触摸指纹传感器"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"指纹图标"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"无法识别人脸。请改用指纹。"</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{已添加 # 个控件。}other{已添加 # 个控件。}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"已移除"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"添加“<xliff:g id="APPNAME">%s</xliff:g>”?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"当您添加“<xliff:g id="APPNAME">%s</xliff:g>”后,它可以将控件和内容添加到此面板。在某些应用中,您可以选择在此处显示哪些控件。"</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"“<xliff:g id="APPNAME">%s</xliff:g>”可以选择在此处显示哪些控件和内容。"</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"移除<xliff:g id="APPNAME">%s</xliff:g>的控件?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"已收藏"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"已收藏,位置:<xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"已取消收藏"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"其他"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"添加到设备控制器"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"添加"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"移除"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"来自<xliff:g id="APP">%s</xliff:g>的建议"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"设备已锁定"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"要从锁定屏幕上显示和控制设备吗?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"您可以在锁定屏幕上添加用于控制外部设备的控件。\n\n您的设备应用可能会允许您在不解锁手机或平板电脑的情况下控制某些设备。\n\n您可以随时在“设置”中进行更改。"</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"要从锁定屏幕上控制设备吗?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"您可以在不解锁手机或平板电脑的情况下控制某些设备。\n\n您的设备应用将决定哪些设备可以通过这种方式进行控制。"</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"您可以在不解锁手机或平板电脑的情况下控制某些设备。您的设备配套应用将决定哪些设备可以通过这种方式进行控制。"</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"不用了"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"是"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN 码由字母或符号组成"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"添加控制器"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"修改控制器"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"添加应用"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"移除应用"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"添加输出设备"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"群组"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"已选择 1 个设备"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index a84a3f9..491a0e9 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"如果您下次輸入錯誤的 PIN,系統將會刪除工作設定檔和相關資料。"</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"如果您下次輸入錯誤的密碼,系統將會刪除工作設定檔和相關資料。"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"請輕觸指紋感應器"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"指紋圖示"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"無法辨識面孔,請改用指紋完成驗證。"</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,9 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{已新增 # 個控制項。}other{已新增 # 個控制項。}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"已移除"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"要新增「<xliff:g id="APPNAME">%s</xliff:g>」嗎?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"如果您新增「<xliff:g id="APPNAME">%s</xliff:g>」,應用程式可將控制項和內容新增至此面板。部份應用程式可讓您選擇要在這裡顯示的控制項。"</string>
+    <!-- no translation found for controls_panel_authorization (7045551688535104194) -->
+    <skip />
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"要移除「<xliff:g id="APPNAME">%s</xliff:g>」的控制項嗎?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"已加入收藏"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"已加入至收藏位置 <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"已取消收藏"</string>
@@ -826,12 +827,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"其他"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"加到裝置控制"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"新增"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"移除"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"由「<xliff:g id="APP">%s</xliff:g>」提供的建議"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"裝置已上鎖"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"要從上鎖畫面查看及控制裝置嗎?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"您可以在上鎖畫面新增外部裝置的控制項。\n\n裝置應用程式可能會讓您在不解鎖手機或平板電腦的情況下控制部分裝置。\n\n您可隨時在「設定」中作出變更。"</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"要在上鎖畫面控制裝置嗎?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"您可以在不解鎖手機或平板電腦的情況下控制部分裝置。\n\n裝置應用程式決定哪些裝置可透過此方式控制。"</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"您可以在不解鎖手機或平板電腦的情況下控制部分裝置。裝置應用程式決定哪些裝置可透過此方式控制。"</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"不用了,謝謝"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"是"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN 含有字母或符號"</string>
@@ -879,6 +881,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"新增控制項"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"編輯控制項"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"新增應用程式"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"移除應用程式"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"新增輸出裝置"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"群組"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"已選取 1 部裝置"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index bb6e2d5..58f0111 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"如果下次輸入的 PIN 碼仍不正確,系統將刪除你的工作資料夾和相關資料。"</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"如果下次輸入的密碼仍不正確,系統將刪除你的工作資料夾和相關資料。"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"請輕觸指紋感應器"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"指紋圖示"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"無法辨識臉孔,請改用指紋完成驗證。"</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,9 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{已新增 # 個控制項。}other{已新增 # 個控制項。}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"已移除"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"要新增「<xliff:g id="APPNAME">%s</xliff:g>」嗎?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"當你新增「<xliff:g id="APPNAME">%s</xliff:g>」時,應用程式也可將控制選項及內容新增到這個面板。某些應用程式可讓你選擇要顯示在這裡的控制選項。"</string>
+    <!-- no translation found for controls_panel_authorization (7045551688535104194) -->
+    <skip />
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"要移除「<xliff:g id="APPNAME">%s</xliff:g>」的控制嗎?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"已加入收藏"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"已加入收藏,位置 <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"從收藏中移除"</string>
@@ -826,12 +827,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"其他"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"新增至裝置控制項"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"新增"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"移除"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"來自「<xliff:g id="APP">%s</xliff:g>」的建議"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"裝置已鎖定"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"要在螢幕鎖定畫面上查看及控制裝置嗎?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"你可以在螢幕鎖定畫面上新增外部裝置的控制選項。\n\n你或許可透過裝置應用程式控制某些裝置,而不必解鎖手機或平板電腦。\n\n你隨時可以前往「設定」進行變更。"</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"要在螢幕鎖定畫面上控制裝置嗎?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"你可以直接控制某些裝置,不必解鎖手機或平板電腦。\n\n裝置應用程式會判斷可透過這種方式控制的應用程式。"</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"你可以直接控制某些裝置,不必解鎖手機或平板電腦。裝置應用程式會判斷可透過這種方式控制的裝置。"</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"不用了,謝謝"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"是"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN 碼含有字母或符號"</string>
@@ -879,6 +881,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"新增控制項"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"編輯控制項"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"新增應用程式"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"移除應用程式"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"新增輸出裝置"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"群組"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"已選取 1 部裝置"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 77dfa88..281e57e 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -168,7 +168,6 @@
     <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Uma ufaka iphinikhodi engalungile kumzamo olandelayo, iphrofayela yakho yomsebenzi nedatha yayo izosuswa."</string>
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Uma ufake iphasiwedi engalungile kumzamo olandelayo, iphrofayela yakho yomsebenzi nedatha yayo izosuswa."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Thinta inzwa yesigxivizo zeminwe"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Isithonjana sezigxivizo zeminwe"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ayibazi ubuso. Sebenzisa izigxivizo zeminwe kunalokho."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
@@ -808,7 +807,8 @@
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{ulawulo olu-# olwengeziwe.}one{ukulawulwa okungu-# okwengeziwe.}other{ukulawulwa okungu-# okwengeziwe.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Isusiwe"</string>
     <string name="controls_panel_authorization_title" msgid="267429338785864842">"Engeza i-<xliff:g id="APPNAME">%s</xliff:g>?"</string>
-    <string name="controls_panel_authorization" msgid="4540047176861801815">"Uma wengeza i-<xliff:g id="APPNAME">%s</xliff:g>, ingangeza izilawuli nokuqukethwe kuleli phaneli. Kwamanye ama-app, ungakhetha ukuthi yiziphi izilawuli eziboniswa lapha."</string>
+    <string name="controls_panel_authorization" msgid="7045551688535104194">"I-<xliff:g id="APPNAME">%s</xliff:g> ingakhetha ukuthi yiziphi izilawuli nokuqukethwe okuboniswa lapha."</string>
+    <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Susa izilawuli ze-<xliff:g id="APPNAME">%s</xliff:g>?"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Kwenziwe intandokazi"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Kwenziwe intandokazi, isimo esiyi-<xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Akwenziwanga intandokazi"</string>
@@ -826,12 +826,13 @@
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Okunye"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Engeza kuzilawuli zezinsiza"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Engeza"</string>
+    <string name="controls_dialog_remove" msgid="3775288002711561936">"Susa"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Kuphakanyiswe ngu-<xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Idivayisi ikhiyiwe"</string>
     <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Bonisa futhi ulawule amadivayisi ekukhiyeni isikrini?"</string>
     <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Ungakwazi ukwengeza izilawuli zamadivayisi wakho angaphandle ekukhiyeni isikrini.\n\nI-app yakho yedivayisi ingakuvumela ukuthi ulawule amanye amadivayisi ngaphandle kokuvula ifoni noma ithebulethi yakho.\n\nUngenza izinguquko nganoma yisiphi isikhathi Kumasethingi."</string>
     <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Lawula amadivayisi ekukhiyeni isikrini?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Ungalawula amanye amadivayisi ngaphandle kokuvula ifoni noma ithebulethi yakho.\n\nI-app yakho yedivayisi inquma ukuthi imaphi amadivayisi angalawulwa ngale ndlela."</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Ungalawula amanye amadivayisi ngaphandle kokuvula ifoni noma ithebulethi yakho. I-app yakho yedivayisi inquma ukuthi imaphi amadivayisi angalawulwa ngale ndlela."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Cha ngiyabonga"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Yebo"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Iphinikhodi iqukethe amaletha namasimbui"</string>
@@ -879,6 +880,7 @@
     <string name="controls_menu_add" msgid="4447246119229920050">"Engeza Izilawuli"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Hlela izilawuli"</string>
     <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Engeza i-app"</string>
+    <string name="controls_menu_remove" msgid="3006525275966023468">"Susa i-app"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Engeza okukhiphayo"</string>
     <string name="media_output_dialog_group" msgid="5571251347877452212">"Iqembu"</string>
     <string name="media_output_dialog_single_device" msgid="3102758980643351058">"idivayisi ekhethiwe e-1"</string>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index ca4217f..9d00a27 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -161,6 +161,7 @@
 
     <color name="GM2_red_300">#F28B82</color>
     <color name="GM2_red_500">#EA4335</color>
+    <color name="GM2_red_600">#B3261E</color>
     <color name="GM2_red_700">#C5221F</color>
 
     <color name="GM2_blue_300">#8AB4F8</color>
@@ -207,6 +208,11 @@
     <color name="control_thumbnail_shadow_color">@*android:color/black</color>
     <color name="controls_task_view_bg">#CC191C1D</color>
 
+    <!-- Keyboard backlight indicator-->
+    <color name="backlight_indicator_step_filled">#F6E388</color>
+    <color name="backlight_indicator_step_empty">#494740</color>
+    <color name="backlight_indicator_background">#32302A</color>
+
     <!-- Docked misalignment message -->
     <color name="misalignment_text_color">#F28B82</color>
 
@@ -224,6 +230,9 @@
 
     <color name="people_tile_background">@color/material_dynamic_secondary95</color>
 
+    <!-- Chipbar -->
+    <color name="chipbar_text_and_icon_color">@android:color/system_accent2_900</color>
+
     <!-- Internet Dialog -->
     <!-- Material next state on color-->
     <color name="settingslib_state_on_color">@color/settingslib_state_on</color>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 3f84ddb..f545dae0 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -774,7 +774,7 @@
     <!-- Duration in milliseconds of the dream in complications fade-in animation. -->
     <integer name="config_dreamOverlayInComplicationsDurationMs">250</integer>
     <!-- Duration in milliseconds of the y-translation animation when entering a dream -->
-    <integer name="config_dreamOverlayInTranslationYDurationMs">917</integer>
+    <integer name="config_dreamOverlayInTranslationYDurationMs">1167</integer>
 
     <!-- Delay in milliseconds before switching to the dock user and dreaming if a secondary user is
     active when the device is locked and docked. 0 indicates disabled. Default is 1 minute. -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 9ce3f38..9145982 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -196,9 +196,6 @@
     <!-- Increased height of a small notification in the status bar -->
     <dimen name="notification_min_height_increased">146dp</dimen>
 
-    <!-- Increased height of a collapsed media notification in the status bar -->
-    <dimen name="notification_min_height_media">160dp</dimen>
-
     <!-- Height of a small notification in the status bar which was used before android N -->
     <dimen name="notification_min_height_legacy">64dp</dimen>
 
@@ -1105,6 +1102,7 @@
 
     <!-- Size of Smartspace media recommendations cards in the QSPanel carousel -->
     <dimen name="qs_media_rec_icon_top_margin">16dp</dimen>
+    <dimen name="qs_media_rec_album_icon_size">16dp</dimen>
     <dimen name="qs_media_rec_album_size">88dp</dimen>
     <dimen name="qs_media_rec_album_width">110dp</dimen>
     <dimen name="qs_media_rec_album_height_expanded">108dp</dimen>
@@ -1114,14 +1112,15 @@
     <dimen name="qs_media_rec_album_title_bottom_margin">22dp</dimen>
     <dimen name="qs_media_rec_album_subtitle_height">12dp</dimen>
 
-    <!-- Media tap-to-transfer chip for sender device -->
-    <dimen name="media_ttt_chip_outer_padding">16dp</dimen>
-    <dimen name="media_ttt_text_size">16sp</dimen>
-    <dimen name="media_ttt_app_icon_size">24dp</dimen>
-    <dimen name="media_ttt_status_icon_size">20dp</dimen>
-    <dimen name="media_ttt_undo_button_vertical_padding">8dp</dimen>
-    <dimen name="media_ttt_undo_button_vertical_negative_margin">-8dp</dimen>
-    <dimen name="media_ttt_last_item_start_margin">12dp</dimen>
+    <!-- Chipbar -->
+    <!-- (Used for media tap-to-transfer chip for sender device and active unlock) -->
+    <dimen name="chipbar_outer_padding">16dp</dimen>
+    <dimen name="chipbar_text_size">16sp</dimen>
+    <dimen name="chipbar_start_icon_size">24dp</dimen>
+    <dimen name="chipbar_end_icon_size">20dp</dimen>
+    <dimen name="chipbar_end_button_vertical_padding">8dp</dimen>
+    <dimen name="chipbar_end_button_vertical_negative_margin">-8dp</dimen>
+    <dimen name="chipbar_end_item_start_margin">12dp</dimen>
 
     <!-- Media tap-to-transfer chip for receiver device -->
     <dimen name="media_ttt_icon_size_receiver">112dp</dimen>
@@ -1587,9 +1586,12 @@
     <!-- Dream overlay complications related dimensions -->
     <!-- The blur radius applied to the dream overlay when entering and exiting dreams -->
     <dimen name="dream_overlay_anim_blur_radius">50dp</dimen>
+    <dimen name="dream_overlay_bottom_affordance_height">64dp</dimen>
+    <dimen name="dream_overlay_bottom_affordance_width">64dp</dimen>
+    <dimen name="dream_overlay_bottom_affordance_radius">32dp</dimen>
+    <dimen name="dream_overlay_bottom_affordance_padding">14dp</dimen>
     <dimen name="dream_overlay_complication_clock_time_text_size">86dp</dimen>
     <dimen name="dream_overlay_complication_clock_time_translation_y">28dp</dimen>
-    <dimen name="dream_overlay_complication_home_controls_padding">28dp</dimen>
     <dimen name="dream_overlay_complication_clock_subtitle_text_size">24sp</dimen>
     <dimen name="dream_overlay_complication_preview_text_size">36sp</dimen>
     <dimen name="dream_overlay_complication_preview_icon_padding">28dp</dimen>
@@ -1630,11 +1632,11 @@
         .2
     </item>
 
-    <!-- The margins applied to the dream overlay container -->
-    <dimen name="dream_overlay_container_margin_start">0dp</dimen>
-    <dimen name="dream_overlay_container_margin_end">0dp</dimen>
-    <dimen name="dream_overlay_container_margin_top">0dp</dimen>
-    <dimen name="dream_overlay_container_margin_bottom">0dp</dimen>
+    <!-- The padding applied to the dream overlay container -->
+    <dimen name="dream_overlay_container_padding_start">0dp</dimen>
+    <dimen name="dream_overlay_container_padding_end">0dp</dimen>
+    <dimen name="dream_overlay_container_padding_top">0dp</dimen>
+    <dimen name="dream_overlay_container_padding_bottom">0dp</dimen>
 
     <!-- The margin applied between complications -->
     <dimen name="dream_overlay_complication_margin">0dp</dimen>
@@ -1656,6 +1658,19 @@
     <dimen name="media_output_broadcast_info_summary_height">20dp</dimen>
     <dimen name="media_output_broadcast_info_edit">18dp</dimen>
 
+    <!-- Keyboard backlight indicator-->
+    <dimen name="backlight_indicator_root_corner_radius">48dp</dimen>
+    <dimen name="backlight_indicator_root_vertical_padding">8dp</dimen>
+    <dimen name="backlight_indicator_root_horizontal_padding">4dp</dimen>
+    <dimen name="backlight_indicator_icon_width">22dp</dimen>
+    <dimen name="backlight_indicator_icon_height">11dp</dimen>
+    <dimen name="backlight_indicator_icon_left_margin">2dp</dimen>
+    <dimen name="backlight_indicator_step_width">52dp</dimen>
+    <dimen name="backlight_indicator_step_height">40dp</dimen>
+    <dimen name="backlight_indicator_step_horizontal_margin">4dp</dimen>
+    <dimen name="backlight_indicator_step_small_radius">4dp</dimen>
+    <dimen name="backlight_indicator_step_large_radius">48dp</dimen>
+
     <!-- Broadcast dialog -->
     <dimen name="broadcast_dialog_title_img_margin_top">18dp</dimen>
     <dimen name="broadcast_dialog_title_text_size">24sp</dimen>
@@ -1704,4 +1719,9 @@
     it is long-pressed.
     -->
     <dimen name="keyguard_long_press_settings_popup_vertical_offset">96dp</dimen>
+
+
+    <!-- Bouncer user switcher margins -->
+    <dimen name="bouncer_user_switcher_view_mode_user_switcher_bottom_margin">0dp</dimen>
+    <dimen name="bouncer_user_switcher_view_mode_view_flipper_bottom_margin">0dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 8be5998..81241c9 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2258,7 +2258,7 @@
 
     <!-- Shows in a dialog presented to the user to authorize this app to display a Device controls
          panel (embedded activity) instead of controls rendered by SystemUI [CHAR LIMIT=NONE] -->
-    <string name="controls_panel_authorization">When you add <xliff:g id="appName" example="My app">%s</xliff:g>, it can add controls and content to this panel. In some apps, you can choose which controls show up here.</string>
+    <string name="controls_panel_authorization"><xliff:g id="appName" example="My app">%s</xliff:g> can choose which controls and content show here.</string>
 
     <!-- Shows in a dialog presented to the user to authorize this app removal from a Device
          controls panel [CHAR LIMIT=NONE] -->
@@ -2318,7 +2318,7 @@
     <!-- Title of the dialog to control certain devices from lock screen without auth [CHAR LIMIT=NONE] -->
     <string name="controls_settings_trivial_controls_dialog_title">Control devices from lock screen?</string>
     <!-- Message of the dialog to control certain devices from lock screen without auth [CHAR LIMIT=NONE] -->
-    <string name="controls_settings_trivial_controls_dialog_message">You can control some devices without unlocking your phone or tablet.\n\nYour device app determines which devices can be controlled in this way.</string>
+    <string name="controls_settings_trivial_controls_dialog_message">You can control some devices without unlocking your phone or tablet. Your device app determines which devices can be controlled in this way.</string>
     <!-- Neutral button title of the controls dialog [CHAR LIMIT=NONE] -->
     <string name="controls_settings_dialog_neutral_button">No thanks</string>
     <!-- Positive button title of the controls dialog  [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 58b0234..1da1a29 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -699,6 +699,8 @@
 
     <style name="MediaPlayer.Recommendation.AlbumContainer.Updated">
         <item name="android:layout_width">@dimen/qs_media_rec_album_width</item>
+        <item name="android:minWidth">@dimen/qs_media_rec_album_width</item>
+        <item name="android:minHeight">@dimen/qs_media_rec_album_height_collapsed</item>
         <item name="android:background">@drawable/qs_media_light_source</item>
         <item name="android:layout_marginTop">@dimen/qs_media_info_spacing</item>
     </style>
diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt
index 738b37c..2d47356 100644
--- a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt
+++ b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt
@@ -39,14 +39,14 @@
 import platform.test.screenshot.matchers.BitmapMatcher
 
 /** A rule for View screenshot diff unit tests. */
-class ViewScreenshotTestRule(
+open class ViewScreenshotTestRule(
     emulationSpec: DeviceEmulationSpec,
     private val matcher: BitmapMatcher = UnitTestBitmapMatcher,
     assetsPathRelativeToBuildRoot: String
 ) : TestRule {
     private val colorsRule = MaterialYouColorsRule()
     private val deviceEmulationRule = DeviceEmulationRule(emulationSpec)
-    private val screenshotRule =
+    protected val screenshotRule =
         ScreenshotTestRule(
             SystemUIGoldenImagePathManager(
                 getEmulatedDevicePathConfig(emulationSpec),
@@ -64,15 +64,10 @@
         return delegateRule.apply(base, description)
     }
 
-    /**
-     * Compare the content of the view provided by [viewProvider] with the golden image identified
-     * by [goldenIdentifier] in the context of [emulationSpec].
-     */
-    fun screenshotTest(
-        goldenIdentifier: String,
+    protected fun takeScreenshot(
         mode: Mode = Mode.WrapContent,
         viewProvider: (ComponentActivity) -> View,
-    ) {
+    ): Bitmap {
         activityRule.scenario.onActivity { activity ->
             // Make sure that the activity draws full screen and fits the whole display instead of
             // the system bars.
@@ -99,7 +94,19 @@
             contentView = content.getChildAt(0)
         }
 
-        val bitmap = contentView?.toBitmap() ?: error("contentView is null")
+        return contentView?.toBitmap() ?: error("contentView is null")
+    }
+
+    /**
+     * Compare the content of the view provided by [viewProvider] with the golden image identified
+     * by [goldenIdentifier] in the context of [emulationSpec].
+     */
+    fun screenshotTest(
+        goldenIdentifier: String,
+        mode: Mode = Mode.WrapContent,
+        viewProvider: (ComponentActivity) -> View,
+    ) {
+        val bitmap = takeScreenshot(mode, viewProvider)
         screenshotRule.assertBitmapAgainstGolden(
             bitmap,
             goldenIdentifier,
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimator.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimator.kt
index 3efdc5a..4931b25 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimator.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimator.kt
@@ -192,4 +192,4 @@
     )
 }
 
-private const val TRANSLATION_PERCENTAGE = 0.3f
+private const val TRANSLATION_PERCENTAGE = 0.08f
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/PreviewPositionHelper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/PreviewPositionHelper.java
index 8690b36..0c2341f 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/PreviewPositionHelper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/PreviewPositionHelper.java
@@ -33,8 +33,6 @@
      */
     public static final int STAGE_POSITION_BOTTOM_OR_RIGHT = 1;
 
-    // Contains the portion of the thumbnail that is unclipped when fullscreen progress = 1.
-    private final RectF mClippedInsets = new RectF();
     private final Matrix mMatrix = new Matrix();
     private boolean mIsOrientationChanged;
     private SplitBounds mSplitBounds;
@@ -70,33 +68,6 @@
         int thumbnailRotation = thumbnailData.rotation;
         int deltaRotate = getRotationDelta(currentRotation, thumbnailRotation);
         RectF thumbnailClipHint = new RectF();
-
-        float scaledTaskbarSize;
-        float canvasScreenRatio;
-        if (mSplitBounds != null) {
-            if (mSplitBounds.appsStackedVertically) {
-                if (mDesiredStagePosition == STAGE_POSITION_TOP_OR_LEFT) {
-                    // Top app isn't cropped at all by taskbar
-                    canvasScreenRatio = 0;
-                } else {
-                    // Same as fullscreen ratio
-                    canvasScreenRatio = (float) canvasWidth / screenWidthPx;
-                }
-            } else {
-                // For landscape, scale the width
-                float taskPercent = mDesiredStagePosition == STAGE_POSITION_TOP_OR_LEFT
-                        ? mSplitBounds.leftTaskPercent
-                        : (1 - (mSplitBounds.leftTaskPercent + mSplitBounds.dividerWidthPercent));
-                // Scale landscape width to that of actual screen
-                float fullscreenTaskWidth = screenWidthPx * taskPercent;
-                canvasScreenRatio = canvasWidth / fullscreenTaskWidth;
-            }
-        } else {
-            canvasScreenRatio = (float) canvasWidth / screenWidthPx;
-        }
-        scaledTaskbarSize = taskbarSize * canvasScreenRatio;
-        thumbnailClipHint.bottom = isLargeScreen ? scaledTaskbarSize : 0;
-
         float scale = thumbnailData.scale;
         final float thumbnailScale;
 
@@ -116,10 +87,8 @@
 
             float surfaceWidth = thumbnailBounds.width() / scale;
             float surfaceHeight = thumbnailBounds.height() / scale;
-            float availableWidth = surfaceWidth
-                    - (thumbnailClipHint.left + thumbnailClipHint.right);
-            float availableHeight = surfaceHeight
-                    - (thumbnailClipHint.top + thumbnailClipHint.bottom);
+            float availableWidth = surfaceWidth;
+            float availableHeight = surfaceHeight;
 
             float canvasAspect = canvasWidth / (float) canvasHeight;
             float availableAspect = isRotated
@@ -210,8 +179,6 @@
             setThumbnailRotation(deltaRotate, thumbnailBounds);
         }
 
-        mClippedInsets.set(0, 0, 0, scaledTaskbarSize);
-
         mMatrix.postScale(thumbnailScale, thumbnailScale);
         mIsOrientationChanged = isOrientationDifferent;
     }
@@ -250,8 +217,4 @@
         }
         mMatrix.postTranslate(translateX, translateY);
     }
-
-    public RectF getClippedInsets() {
-        return mClippedInsets;
-    }
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionSampler.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionSampler.kt
index 9a581aa..482158e 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionSampler.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionSampler.kt
@@ -91,6 +91,22 @@
         val sampledRegion = calculateSampledRegion(sampledView)
         val regions = ArrayList<RectF>()
         val sampledRegionWithOffset = convertBounds(sampledRegion)
+
+        if (
+            sampledRegionWithOffset.left < 0.0 ||
+                sampledRegionWithOffset.right > 1.0 ||
+                sampledRegionWithOffset.top < 0.0 ||
+                sampledRegionWithOffset.bottom > 1.0
+        ) {
+            android.util.Log.e(
+                "RegionSampler",
+                "view out of bounds: $sampledRegion | " +
+                    "screen width: ${displaySize.x}, screen height: ${displaySize.y}",
+                Exception()
+            )
+            return
+        }
+
         regions.add(sampledRegionWithOffset)
 
         wallpaperManager?.removeOnColorsChangedListener(this)
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java
index 359da13..53fab69 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java
@@ -29,8 +29,11 @@
 import android.annotation.DrawableRes;
 import android.annotation.SuppressLint;
 import android.app.StatusBarManager;
+import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
@@ -86,15 +89,16 @@
     private RotationButton mRotationButton;
 
     private boolean mIsRecentsAnimationRunning;
+    private boolean mDocked;
     private boolean mHomeRotationEnabled;
     private int mLastRotationSuggestion;
     private boolean mPendingRotationSuggestion;
     private boolean mHoveringRotationSuggestion;
     private final AccessibilityManager mAccessibilityManager;
     private final TaskStackListenerImpl mTaskStackListener;
-    private Consumer<Integer> mRotWatcherListener;
 
     private boolean mListenersRegistered = false;
+    private boolean mRotationWatcherRegistered = false;
     private boolean mIsNavigationBarShowing;
     @SuppressLint("InlinedApi")
     private @WindowInsetsController.Behavior
@@ -123,6 +127,12 @@
             () -> mPendingRotationSuggestion = false;
     private Animator mRotateHideAnimator;
 
+    private final BroadcastReceiver mDockedReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            updateDockedState(intent);
+        }
+    };
 
     private final IRotationWatcher.Stub mRotationWatcher = new IRotationWatcher.Stub() {
         @Override
@@ -130,21 +140,7 @@
             // We need this to be scheduled as early as possible to beat the redrawing of
             // window in response to the orientation change.
             mMainThreadHandler.postAtFrontOfQueue(() -> {
-                // If the screen rotation changes while locked, potentially update lock to flow with
-                // new screen rotation and hide any showing suggestions.
-                boolean rotationLocked = isRotationLocked();
-                // The isVisible check makes the rotation button disappear when we are not locked
-                // (e.g. for tabletop auto-rotate).
-                if (rotationLocked || mRotationButton.isVisible()) {
-                    if (shouldOverrideUserLockPrefs(rotation) && rotationLocked) {
-                        setRotationLockedAtAngle(rotation);
-                    }
-                    setRotateSuggestionButtonState(false /* visible */, true /* forced */);
-                }
-
-                if (mRotWatcherListener != null) {
-                    mRotWatcherListener.accept(rotation);
-                }
+                onRotationWatcherChanged(rotation);
             });
         }
     };
@@ -195,8 +191,11 @@
         return mContext;
     }
 
+    /**
+     * Called during Taskbar initialization.
+     */
     public void init() {
-        registerListeners();
+        registerListeners(true /* registerRotationWatcher */);
         if (mContext.getDisplay().getDisplayId() != DEFAULT_DISPLAY) {
             // Currently there is no accelerometer sensor on non-default display, disable fixed
             // rotation for non-default display
@@ -204,25 +203,35 @@
         }
     }
 
+    /**
+     * Called during Taskbar uninitialization.
+     */
     public void onDestroy() {
         unregisterListeners();
     }
 
-    public void registerListeners() {
+    public void registerListeners(boolean registerRotationWatcher) {
         if (mListenersRegistered || getContext().getPackageManager().hasSystemFeature(FEATURE_PC)) {
             return;
         }
 
         mListenersRegistered = true;
-        try {
-            WindowManagerGlobal.getWindowManagerService()
-                    .watchRotation(mRotationWatcher, DEFAULT_DISPLAY);
-        } catch (IllegalArgumentException e) {
-            mListenersRegistered = false;
-            Log.w(TAG, "RegisterListeners for the display failed");
-        } catch (RemoteException e) {
-            Log.e(TAG, "RegisterListeners caught a RemoteException", e);
-            return;
+
+        updateDockedState(mContext.registerReceiver(mDockedReceiver,
+                new IntentFilter(Intent.ACTION_DOCK_EVENT)));
+
+        if (registerRotationWatcher) {
+            try {
+                WindowManagerGlobal.getWindowManagerService()
+                        .watchRotation(mRotationWatcher, DEFAULT_DISPLAY);
+                mRotationWatcherRegistered = true;
+            } catch (IllegalArgumentException e) {
+                mListenersRegistered = false;
+                Log.w(TAG, "RegisterListeners for the display failed", e);
+            } catch (RemoteException e) {
+                Log.e(TAG, "RegisterListeners caught a RemoteException", e);
+                return;
+            }
         }
 
         TaskStackChangeListeners.getInstance().registerTaskStackListener(mTaskStackListener);
@@ -234,20 +243,21 @@
         }
 
         mListenersRegistered = false;
-        try {
-            WindowManagerGlobal.getWindowManagerService().removeRotationWatcher(mRotationWatcher);
-        } catch (RemoteException e) {
-            Log.e(TAG, "UnregisterListeners caught a RemoteException", e);
-            return;
+
+        mContext.unregisterReceiver(mDockedReceiver);
+        if (mRotationWatcherRegistered) {
+            try {
+                WindowManagerGlobal.getWindowManagerService().removeRotationWatcher(
+                        mRotationWatcher);
+            } catch (RemoteException e) {
+                Log.e(TAG, "UnregisterListeners caught a RemoteException", e);
+                return;
+            }
         }
 
         TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mTaskStackListener);
     }
 
-    public void setRotationCallback(Consumer<Integer> watcher) {
-        mRotWatcherListener = watcher;
-    }
-
     public void setRotationLockedAtAngle(int rotationSuggestion) {
         RotationPolicy.setRotationLockAtAngle(mContext, /* enabled= */ isRotationLocked(),
                 /* rotation= */ rotationSuggestion);
@@ -345,6 +355,15 @@
         updateRotationButtonStateInOverview();
     }
 
+    private void updateDockedState(Intent intent) {
+        if (intent == null) {
+            return;
+        }
+
+        mDocked = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED)
+                != Intent.EXTRA_DOCK_STATE_UNDOCKED;
+    }
+
     private void updateRotationButtonStateInOverview() {
         if (mIsRecentsAnimationRunning && !mHomeRotationEnabled) {
             setRotateSuggestionButtonState(false, true /* hideImmediately */);
@@ -401,6 +420,30 @@
         }
     }
 
+    /**
+     * Called when the rotation watcher rotation changes, either from the watcher registered
+     * internally in this class, or a signal propagated from NavBarHelper.
+     */
+    public void onRotationWatcherChanged(int rotation) {
+        if (!mListenersRegistered) {
+            // Ignore if not registered
+            return;
+        }
+
+        // If the screen rotation changes while locked, potentially update lock to flow with
+        // new screen rotation and hide any showing suggestions.
+        boolean rotationLocked = isRotationLocked();
+        // The isVisible check makes the rotation button disappear when we are not locked
+        // (e.g. for tabletop auto-rotate).
+        if (rotationLocked || mRotationButton.isVisible()) {
+            // Do not allow a change in rotation to set user rotation when docked.
+            if (shouldOverrideUserLockPrefs(rotation) && rotationLocked && !mDocked) {
+                setRotationLockedAtAngle(rotation);
+            }
+            setRotateSuggestionButtonState(false /* visible */, true /* forced */);
+        }
+    }
+
     public void onDisable2FlagChanged(int state2) {
         final boolean rotateSuggestionsDisabled = hasDisable2RotateSuggestionFlag(state2);
         if (rotateSuggestionsDisabled) onRotationSuggestionsDisabled();
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 6bfaf5e..b2add4f 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -18,7 +18,6 @@
 
 import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
 import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
-import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
 import static android.app.ActivityTaskManager.getService;
 
 import android.annotation.NonNull;
@@ -45,6 +44,7 @@
 import android.os.SystemClock;
 import android.provider.Settings;
 import android.util.Log;
+import android.view.Display;
 import android.view.IRecentsAnimationController;
 import android.view.IRecentsAnimationRunner;
 import android.view.RemoteAnimationTarget;
@@ -112,6 +112,13 @@
     }
 
     /**
+     * @see #getRunningTasks(boolean , int)
+     */
+    public ActivityManager.RunningTaskInfo[] getRunningTasks(boolean filterOnlyVisibleRecents) {
+        return getRunningTasks(filterOnlyVisibleRecents, Display.INVALID_DISPLAY);
+    }
+
+    /**
      * We ask for {@link #NUM_RECENT_ACTIVITIES_REQUEST} activities because when in split screen,
      * we'll get back 2 activities for each split app and one for launcher. Launcher might be more
      * "recently" used than one of the split apps so if we only request 2 tasks, then we might miss
@@ -120,10 +127,12 @@
      * @return an array of up to {@link #NUM_RECENT_ACTIVITIES_REQUEST} running tasks
      *         filtering only for tasks that can be visible in the recent tasks list.
      */
-    public ActivityManager.RunningTaskInfo[] getRunningTasks(boolean filterOnlyVisibleRecents) {
+    public ActivityManager.RunningTaskInfo[] getRunningTasks(boolean filterOnlyVisibleRecents,
+            int displayId) {
         // Note: The set of running tasks from the system is ordered by recency
         List<ActivityManager.RunningTaskInfo> tasks =
-                mAtm.getTasks(NUM_RECENT_ACTIVITIES_REQUEST, filterOnlyVisibleRecents);
+                mAtm.getTasks(NUM_RECENT_ACTIVITIES_REQUEST,
+                        filterOnlyVisibleRecents, /* keepInExtras= */ false, displayId);
         return tasks.toArray(new RunningTaskInfo[tasks.size()]);
     }
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index 65dedc6..2e22bfb 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -115,6 +115,26 @@
     public static final int SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE = 1 << 26;
     // Device dreaming state
     public static final int SYSUI_STATE_DEVICE_DREAMING = 1 << 27;
+    // Whether the screen is currently on. Note that the screen is considered on while turning on,
+    // but not while turning off.
+    public static final int SYSUI_STATE_SCREEN_ON = 1 << 28;
+    // Whether the screen is currently transitioning into the state indicated by
+    // SYSUI_STATE_SCREEN_ON.
+    public static final int SYSUI_STATE_SCREEN_TRANSITION = 1 << 29;
+
+    // Mask for SystemUiStateFlags to isolate SYSUI_STATE_SCREEN_ON and
+    // SYSUI_STATE_SCREEN_TRANSITION, to match SCREEN_STATE_*
+    public static final int SYSUI_STATE_SCREEN_STATE_MASK =
+            SYSUI_STATE_SCREEN_ON | SYSUI_STATE_SCREEN_TRANSITION;
+    // Screen is off.
+    public static final int SCREEN_STATE_OFF = 0;
+    // Screen is on.
+    public static final int SCREEN_STATE_ON = SYSUI_STATE_SCREEN_ON;
+    // Screen is still on, but transitioning to turn off.
+    public static final int SCREEN_STATE_TURNING_OFF = SYSUI_STATE_SCREEN_TRANSITION;
+    // Screen was off and is now turning on.
+    public static final int SCREEN_STATE_TURNING_ON =
+            SYSUI_STATE_SCREEN_TRANSITION | SYSUI_STATE_SCREEN_ON;
 
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({SYSUI_STATE_SCREEN_PINNING,
@@ -144,45 +164,105 @@
             SYSUI_STATE_IMMERSIVE_MODE,
             SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING,
             SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE,
-            SYSUI_STATE_DEVICE_DREAMING
+            SYSUI_STATE_DEVICE_DREAMING,
+            SYSUI_STATE_SCREEN_ON,
+            SYSUI_STATE_SCREEN_TRANSITION,
     })
     public @interface SystemUiStateFlags {}
 
     public static String getSystemUiStateString(int flags) {
         StringJoiner str = new StringJoiner("|");
-        str.add((flags & SYSUI_STATE_SCREEN_PINNING) != 0 ? "screen_pinned" : "");
-        str.add((flags & SYSUI_STATE_OVERVIEW_DISABLED) != 0 ? "overview_disabled" : "");
-        str.add((flags & SYSUI_STATE_HOME_DISABLED) != 0 ? "home_disabled" : "");
-        str.add((flags & SYSUI_STATE_SEARCH_DISABLED) != 0 ? "search_disabled" : "");
-        str.add((flags & SYSUI_STATE_NAV_BAR_HIDDEN) != 0 ? "navbar_hidden" : "");
-        str.add((flags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) != 0 ? "notif_visible" : "");
-        str.add((flags & SYSUI_STATE_QUICK_SETTINGS_EXPANDED) != 0 ? "qs_visible" : "");
-        str.add((flags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING) != 0 ? "keygrd_visible" : "");
-        str.add((flags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED) != 0
-                ? "keygrd_occluded" : "");
-        str.add((flags & SYSUI_STATE_BOUNCER_SHOWING) != 0 ? "bouncer_visible" : "");
-        str.add((flags & SYSUI_STATE_DIALOG_SHOWING) != 0 ? "dialog_showing" : "");
-        str.add((flags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0 ? "a11y_click" : "");
-        str.add((flags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0 ? "a11y_long_click" : "");
-        str.add((flags & SYSUI_STATE_TRACING_ENABLED) != 0 ? "tracing" : "");
-        str.add((flags & SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED) != 0
-                ? "asst_gesture_constrain" : "");
-        str.add((flags & SYSUI_STATE_BUBBLES_EXPANDED) != 0 ? "bubbles_expanded" : "");
-        str.add((flags & SYSUI_STATE_ONE_HANDED_ACTIVE) != 0 ? "one_handed_active" : "");
-        str.add((flags & SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY) != 0
-                ? "allow_gesture" : "");
-        str.add((flags & SYSUI_STATE_IME_SHOWING) != 0 ? "ime_visible" : "");
-        str.add((flags & SYSUI_STATE_MAGNIFICATION_OVERLAP) != 0 ? "magnification_overlap" : "");
-        str.add((flags & SYSUI_STATE_IME_SWITCHER_SHOWING) != 0 ? "ime_switcher_showing" : "");
-        str.add((flags & SYSUI_STATE_DEVICE_DOZING) != 0 ? "device_dozing" : "");
-        str.add((flags & SYSUI_STATE_BACK_DISABLED) != 0 ? "back_disabled" : "");
-        str.add((flags & SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED) != 0
-                ? "bubbles_mange_menu_expanded" : "");
-        str.add((flags & SYSUI_STATE_IMMERSIVE_MODE) != 0 ? "immersive_mode" : "");
-        str.add((flags & SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING) != 0 ? "vis_win_showing" : "");
-        str.add((flags & SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE) != 0
-                ? "freeform_active_in_desktop_mode" : "");
-        str.add((flags & SYSUI_STATE_DEVICE_DREAMING) != 0 ? "device_dreaming" : "");
+        if ((flags & SYSUI_STATE_SCREEN_PINNING) != 0) {
+            str.add("screen_pinned");
+        }
+        if ((flags & SYSUI_STATE_OVERVIEW_DISABLED) != 0) {
+            str.add("overview_disabled");
+        }
+        if ((flags & SYSUI_STATE_HOME_DISABLED) != 0) {
+            str.add("home_disabled");
+        }
+        if ((flags & SYSUI_STATE_SEARCH_DISABLED) != 0) {
+            str.add("search_disabled");
+        }
+        if ((flags & SYSUI_STATE_NAV_BAR_HIDDEN) != 0) {
+            str.add("navbar_hidden");
+        }
+        if ((flags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) != 0) {
+            str.add("notif_visible");
+        }
+        if ((flags & SYSUI_STATE_QUICK_SETTINGS_EXPANDED) != 0) {
+            str.add("qs_visible");
+        }
+        if ((flags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING) != 0) {
+            str.add("keygrd_visible");
+        }
+        if ((flags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED) != 0) {
+            str.add("keygrd_occluded");
+        }
+        if ((flags & SYSUI_STATE_BOUNCER_SHOWING) != 0) {
+            str.add("bouncer_visible");
+        }
+        if ((flags & SYSUI_STATE_DIALOG_SHOWING) != 0) {
+            str.add("dialog_showing");
+        }
+        if ((flags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0) {
+            str.add("a11y_click");
+        }
+        if ((flags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0) {
+            str.add("a11y_long_click");
+        }
+        if ((flags & SYSUI_STATE_TRACING_ENABLED) != 0) {
+            str.add("tracing");
+        }
+        if ((flags & SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED) != 0) {
+            str.add("asst_gesture_constrain");
+        }
+        if ((flags & SYSUI_STATE_BUBBLES_EXPANDED) != 0) {
+            str.add("bubbles_expanded");
+        }
+        if ((flags & SYSUI_STATE_ONE_HANDED_ACTIVE) != 0) {
+            str.add("one_handed_active");
+        }
+        if ((flags & SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY) != 0) {
+            str.add("allow_gesture");
+        }
+        if ((flags & SYSUI_STATE_IME_SHOWING) != 0) {
+            str.add("ime_visible");
+        }
+        if ((flags & SYSUI_STATE_MAGNIFICATION_OVERLAP) != 0) {
+            str.add("magnification_overlap");
+        }
+        if ((flags & SYSUI_STATE_IME_SWITCHER_SHOWING) != 0) {
+            str.add("ime_switcher_showing");
+        }
+        if ((flags & SYSUI_STATE_DEVICE_DOZING) != 0) {
+            str.add("device_dozing");
+        }
+        if ((flags & SYSUI_STATE_BACK_DISABLED) != 0) {
+            str.add("back_disabled");
+        }
+        if ((flags & SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED) != 0) {
+            str.add("bubbles_mange_menu_expanded");
+        }
+        if ((flags & SYSUI_STATE_IMMERSIVE_MODE) != 0) {
+            str.add("immersive_mode");
+        }
+        if ((flags & SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING) != 0) {
+            str.add("vis_win_showing");
+        }
+        if ((flags & SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE) != 0) {
+            str.add("freeform_active_in_desktop_mode");
+        }
+        if ((flags & SYSUI_STATE_DEVICE_DREAMING) != 0) {
+            str.add("device_dreaming");
+        }
+        if ((flags & SYSUI_STATE_SCREEN_TRANSITION) != 0) {
+            str.add("screen_transition");
+        }
+        if ((flags & SYSUI_STATE_SCREEN_ON) != 0) {
+            str.add("screen_on");
+        }
+
         return str.toString();
     }
 
diff --git a/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt b/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt
index 8323d09..f005bab 100644
--- a/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt
+++ b/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt
@@ -23,6 +23,8 @@
 import dagger.Binds
 import dagger.Module
 import dagger.Provides
+import dagger.multibindings.IntoSet
+import javax.inject.Named
 
 @Module(includes = [
     FeatureFlagsDebugStartableModule::class,
@@ -35,7 +37,8 @@
     abstract fun bindsFeatureFlagDebug(impl: FeatureFlagsDebug): FeatureFlags
 
     @Binds
-    abstract fun bindsRestarter(debugRestarter: FeatureFlagsDebugRestarter): Restarter
+    @IntoSet
+    abstract fun bindsScreenIdleCondition(impl: ScreenIdleCondition): ConditionalRestarter.Condition
 
     @Module
     companion object {
@@ -44,5 +47,10 @@
         fun provideFlagManager(context: Context, @Main handler: Handler): FlagManager {
             return FlagManager(context, handler)
         }
+
+        @JvmStatic
+        @Provides
+        @Named(ConditionalRestarter.RESTART_DELAY)
+        fun provideRestartDelaySec(): Long = 1
     }
 }
diff --git a/packages/SystemUI/src-release/com/android/systemui/flags/FlagsModule.kt b/packages/SystemUI/src-release/com/android/systemui/flags/FlagsModule.kt
index 87beff7..927d4604b 100644
--- a/packages/SystemUI/src-release/com/android/systemui/flags/FlagsModule.kt
+++ b/packages/SystemUI/src-release/com/android/systemui/flags/FlagsModule.kt
@@ -18,6 +18,9 @@
 
 import dagger.Binds
 import dagger.Module
+import dagger.Provides
+import dagger.multibindings.IntoSet
+import javax.inject.Named
 
 @Module(includes = [
     FeatureFlagsReleaseStartableModule::class,
@@ -29,5 +32,18 @@
     abstract fun bindsFeatureFlagRelease(impl: FeatureFlagsRelease): FeatureFlags
 
     @Binds
-    abstract fun bindsRestarter(debugRestarter: FeatureFlagsReleaseRestarter): Restarter
+    @IntoSet
+    abstract fun bindsScreenIdleCondition(impl: ScreenIdleCondition): ConditionalRestarter.Condition
+
+    @Binds
+    @IntoSet
+    abstract fun bindsPluggedInCondition(impl: PluggedInCondition): ConditionalRestarter.Condition
+
+    @Module
+    companion object {
+        @JvmStatic
+        @Provides
+        @Named(ConditionalRestarter.RESTART_DELAY)
+        fun provideRestartDelaySec(): Long = 30
+    }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index 92ee373..3b9060a 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -21,6 +21,7 @@
 import android.content.Intent
 import android.content.IntentFilter
 import android.content.res.Resources
+import android.graphics.Rect
 import android.text.format.DateFormat
 import android.util.TypedValue
 import android.view.View
@@ -119,10 +120,6 @@
 
     private val mLayoutChangedListener =
         object : View.OnLayoutChangeListener {
-            private var currentSmallClockView: View? = null
-            private var currentLargeClockView: View? = null
-            private var currentSmallClockLocation = IntArray(2)
-            private var currentLargeClockLocation = IntArray(2)
 
             override fun onLayoutChange(
                 view: View?,
@@ -135,6 +132,8 @@
                 oldRight: Int,
                 oldBottom: Int
             ) {
+                view?.removeOnLayoutChangeListener(this)
+
                 val parent = (view?.parent) as FrameLayout
 
                 // don't pass in negative bounds when clocks are in transition state
@@ -142,31 +141,12 @@
                     return
                 }
 
-                // SMALL CLOCK
-                if (parent.id == R.id.lockscreen_clock_view) {
-                    // view bounds have changed due to clock size changing (i.e. different character
-                    // widths)
-                    // AND/OR the view has been translated when transitioning between small and
-                    // large clock
-                    if (
-                        view != currentSmallClockView ||
-                            !view.locationOnScreen.contentEquals(currentSmallClockLocation)
-                    ) {
-                        currentSmallClockView = view
-                        currentSmallClockLocation = view.locationOnScreen
-                        updateRegionSampler(view)
-                    }
-                }
-                // LARGE CLOCK
-                else if (parent.id == R.id.lockscreen_clock_view_large) {
-                    if (
-                        view != currentLargeClockView ||
-                            !view.locationOnScreen.contentEquals(currentLargeClockLocation)
-                    ) {
-                        currentLargeClockView = view
-                        currentLargeClockLocation = view.locationOnScreen
-                        updateRegionSampler(view)
-                    }
+                val currentViewRect = Rect(left, top, right, bottom)
+                val oldViewRect = Rect(oldLeft, oldTop, oldRight, oldBottom)
+
+                if (currentViewRect.width() != oldViewRect.width() ||
+                    currentViewRect.height() != oldViewRect.height()) {
+                    updateRegionSampler(view)
                 }
             }
         }
@@ -279,7 +259,7 @@
                 largeTimeListener?.update(shouldTimeListenerRun)
             }
 
-            override fun onTimeFormatChanged(timeFormat: String) {
+            override fun onTimeFormatChanged(timeFormat: String?) {
                 clock?.events?.onTimeFormatChanged(DateFormat.is24HourFormat(context))
             }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
index baaef19..f8cb38d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
@@ -44,7 +44,7 @@
 public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKeyInputView>
         extends KeyguardInputViewController<T> {
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
-    private final LockPatternUtils mLockPatternUtils;
+    protected final LockPatternUtils mLockPatternUtils;
     private final LatencyTracker mLatencyTracker;
     private final FalsingCollector mFalsingCollector;
     private final EmergencyButtonController mEmergencyButtonController;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index b85b2b8..ba21780 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -22,6 +22,7 @@
 import static com.android.keyguard.KeyguardClockSwitch.LARGE;
 import static com.android.keyguard.KeyguardClockSwitch.SMALL;
 
+import android.annotation.Nullable;
 import android.database.ContentObserver;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -458,6 +459,7 @@
         mView.setClock(clock, mStatusBarStateController.getState());
     }
 
+    @Nullable
     private ClockController getClock() {
         return mClockEventController.getClock();
     }
@@ -510,8 +512,10 @@
     }
 
     /** Gets the animations for the current clock. */
+    @Nullable
     public ClockAnimations getClockAnimations() {
-        return getClock().getAnimations();
+        ClockController clock = getClock();
+        return clock == null ? null : clock.getAnimations();
     }
 }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt
index fe8b8c9..c98e9b4 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt
@@ -40,7 +40,7 @@
     var keyguardGoingAway: Boolean = false,
     var listeningForFaceAssistant: Boolean = false,
     var occludingAppRequestingFaceAuth: Boolean = false,
-    val postureAllowsListening: Boolean = false,
+    var postureAllowsListening: Boolean = false,
     var primaryUser: Boolean = false,
     var secureCameraLaunched: Boolean = false,
     var supportsDetect: Boolean = false,
@@ -70,6 +70,7 @@
             listeningForFaceAssistant.toString(),
             occludingAppRequestingFaceAuth.toString(),
             primaryUser.toString(),
+            postureAllowsListening.toString(),
             secureCameraLaunched.toString(),
             supportsDetect.toString(),
             switchingUser.toString(),
@@ -109,6 +110,7 @@
                 listeningForFaceAssistant = model.listeningForFaceAssistant
                 occludingAppRequestingFaceAuth = model.occludingAppRequestingFaceAuth
                 primaryUser = model.primaryUser
+                postureAllowsListening = model.postureAllowsListening
                 secureCameraLaunched = model.secureCameraLaunched
                 supportsDetect = model.supportsDetect
                 switchingUser = model.switchingUser
@@ -152,6 +154,7 @@
                 "listeningForFaceAssistant",
                 "occludingAppRequestingFaceAuth",
                 "primaryUser",
+                "postureAllowsListening",
                 "secureCameraLaunched",
                 "supportsDetect",
                 "switchingUser",
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
index 0e5f8c1..553453d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
@@ -18,13 +18,9 @@
 
 import android.content.Context;
 import android.content.res.TypedArray;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.SystemClock;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.TypedValue;
-import android.view.View;
 import android.view.ViewGroup;
 import android.widget.TextView;
 
@@ -33,22 +29,10 @@
 import com.android.internal.policy.SystemBarUtils;
 import com.android.systemui.R;
 
-import java.lang.ref.WeakReference;
-
 /***
  * Manages a number of views inside of the given layout. See below for a list of widgets.
  */
 public abstract class KeyguardMessageArea extends TextView implements SecurityMessageDisplay {
-    /** Handler token posted with accessibility announcement runnables. */
-    private static final Object ANNOUNCE_TOKEN = new Object();
-
-    /**
-     * Delay before speaking an accessibility announcement. Used to prevent
-     * lift-to-type from interrupting itself.
-     */
-    private static final long ANNOUNCEMENT_DELAY = 250;
-
-    private final Handler mHandler;
 
     private CharSequence mMessage;
     private boolean mIsVisible;
@@ -65,7 +49,6 @@
         super(context, attrs);
         setLayerType(LAYER_TYPE_HARDWARE, null); // work around nested unclipped SaveLayer bug
 
-        mHandler = new Handler(Looper.myLooper());
         onThemeChanged();
     }
 
@@ -127,9 +110,6 @@
     private void securityMessageChanged(CharSequence message) {
         mMessage = message;
         update();
-        mHandler.removeCallbacksAndMessages(ANNOUNCE_TOKEN);
-        mHandler.postAtTime(new AnnounceRunnable(this, getText()), ANNOUNCE_TOKEN,
-                (SystemClock.uptimeMillis() + ANNOUNCEMENT_DELAY));
     }
 
     private void clearMessage() {
@@ -156,25 +136,4 @@
 
     /** Set the text color */
     protected abstract void updateTextColor();
-
-    /**
-     * Runnable used to delay accessibility announcements.
-     */
-    private static class AnnounceRunnable implements Runnable {
-        private final WeakReference<View> mHost;
-        private final CharSequence mTextToAnnounce;
-
-        AnnounceRunnable(View host, CharSequence textToAnnounce) {
-            mHost = new WeakReference<View>(host);
-            mTextToAnnounce = textToAnnounce;
-        }
-
-        @Override
-        public void run() {
-            final View host = mHost.get();
-            if (host != null) {
-                host.announceForAccessibility(mTextToAnnounce);
-            }
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
index 6a92162..c1896fc 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
@@ -18,11 +18,17 @@
 
 import android.content.res.ColorStateList;
 import android.content.res.Configuration;
+import android.text.TextUtils;
+import android.view.View;
+
+import androidx.annotation.VisibleForTesting;
 
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
 import com.android.systemui.util.ViewController;
 
+import java.lang.ref.WeakReference;
+
 import javax.inject.Inject;
 
 /**
@@ -31,8 +37,14 @@
  */
 public class KeyguardMessageAreaController<T extends KeyguardMessageArea>
         extends ViewController<T> {
+    /**
+     * Delay before speaking an accessibility announcement. Used to prevent
+     * lift-to-type from interrupting itself.
+     */
+    private static final long ANNOUNCEMENT_DELAY = 250;
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     private final ConfigurationController mConfigurationController;
+    private final AnnounceRunnable mAnnounceRunnable;
 
     private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
         public void onFinishedGoingToSleep(int why) {
@@ -68,6 +80,7 @@
 
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mConfigurationController = configurationController;
+        mAnnounceRunnable = new AnnounceRunnable(mView);
     }
 
     @Override
@@ -100,6 +113,12 @@
      */
     public void setMessage(CharSequence s, boolean animate) {
         mView.setMessage(s, animate);
+        CharSequence msg = mView.getText();
+        if (!TextUtils.isEmpty(msg)) {
+            mView.removeCallbacks(mAnnounceRunnable);
+            mAnnounceRunnable.setTextToAnnounce(msg);
+            mView.postDelayed(mAnnounceRunnable, ANNOUNCEMENT_DELAY);
+        }
     }
 
     public void setMessage(int resId) {
@@ -134,4 +153,30 @@
                     view, mKeyguardUpdateMonitor, mConfigurationController);
         }
     }
+
+    /**
+     * Runnable used to delay accessibility announcements.
+     */
+    @VisibleForTesting
+    public static class AnnounceRunnable implements Runnable {
+        private final WeakReference<View> mHost;
+        private CharSequence mTextToAnnounce;
+
+        AnnounceRunnable(View host) {
+            mHost = new WeakReference<>(host);
+        }
+
+        /** Sets the text to announce. */
+        public void setTextToAnnounce(CharSequence textToAnnounce) {
+            mTextToAnnounce = textToAnnounce;
+        }
+
+        @Override
+        public void run() {
+            final View host = mHost.get();
+            if (host != null) {
+                host.announceForAccessibility(mTextToAnnounce);
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
index 67e3400..0394754 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
@@ -217,9 +217,11 @@
     private void animate(float progress) {
         Interpolator standardDecelerate = Interpolators.STANDARD_DECELERATE;
         Interpolator legacyDecelerate = Interpolators.LEGACY_DECELERATE;
+        float standardProgress = standardDecelerate.getInterpolation(progress);
 
         mBouncerMessageView.setTranslationY(
-                mYTrans - mYTrans * standardDecelerate.getInterpolation(progress));
+                mYTrans - mYTrans * standardProgress);
+        mBouncerMessageView.setAlpha(standardProgress);
 
         for (int i = 0; i < mViews.length; i++) {
             View[] row = mViews[i];
@@ -236,7 +238,7 @@
                 view.setAlpha(scaledProgress);
                 int yDistance = mYTrans + mYTransOffset * i;
                 view.setTranslationY(
-                        yDistance - (yDistance * standardDecelerate.getInterpolation(progress)));
+                        yDistance - (yDistance * standardProgress));
                 if (view instanceof NumPadAnimationListener) {
                     ((NumPadAnimationListener) view).setProgress(scaledProgress);
                 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
index 8011efd..75fd888 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
@@ -71,13 +71,17 @@
     protected void onViewAttached() {
         super.onViewAttached();
 
-        for (NumPadKey button: mView.getButtons()) {
+        boolean showAnimations = !mLockPatternUtils
+                .isPinEnhancedPrivacyEnabled(KeyguardUpdateMonitor.getCurrentUser());
+        mPasswordEntry.setShowPassword(showAnimations);
+        for (NumPadKey button : mView.getButtons()) {
             button.setOnTouchListener((v, event) -> {
                 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
                     mFalsingCollector.avoidGesture();
                 }
                 return false;
             });
+            button.setAnimationEnabled(showAnimations);
         }
         mPasswordEntry.setOnKeyListener(mOnKeyListener);
         mPasswordEntry.setUserActivityListener(this::onUserInput);
@@ -102,12 +106,9 @@
         View okButton = mView.findViewById(R.id.key_enter);
         if (okButton != null) {
             okButton.setOnTouchListener(mActionButtonTouchListener);
-            okButton.setOnClickListener(new View.OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    if (mPasswordEntry.isEnabled()) {
-                        verifyPasswordAndUnlock();
-                    }
+            okButton.setOnClickListener(v -> {
+                if (mPasswordEntry.isEnabled()) {
+                    verifyPasswordAndUnlock();
                 }
             });
             okButton.setOnHoverListener(mLiftToActivateListener);
@@ -118,7 +119,7 @@
     protected void onViewDetached() {
         super.onViewDetached();
 
-        for (NumPadKey button: mView.getButtons()) {
+        for (NumPadKey button : mView.getButtons()) {
             button.setOnTouchListener(null);
         }
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 66d5d09..ba5a8c9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -39,6 +39,7 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.app.Activity;
@@ -1067,10 +1068,14 @@
 
             int yTranslation = mResources.getDimensionPixelSize(R.dimen.disappear_y_translation);
 
+            AnimatorSet anims = new AnimatorSet();
             ObjectAnimator yAnim = ObjectAnimator.ofFloat(mView, View.TRANSLATION_Y, yTranslation);
-            yAnim.setInterpolator(Interpolators.STANDARD_ACCELERATE);
-            yAnim.setDuration(500);
-            yAnim.start();
+            ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(mUserSwitcherViewGroup, View.ALPHA,
+                    0f);
+
+            anims.setInterpolator(Interpolators.STANDARD_ACCELERATE);
+            anims.playTogether(alphaAnim, yAnim);
+            anims.start();
         }
 
         private void setupUserSwitcher() {
@@ -1220,8 +1225,7 @@
                 constraintSet.connect(rightElement, LEFT, leftElement, RIGHT);
                 constraintSet.connect(rightElement, RIGHT, PARENT_ID, RIGHT);
                 constraintSet.connect(mUserSwitcherViewGroup.getId(), TOP, PARENT_ID, TOP);
-                constraintSet.connect(mUserSwitcherViewGroup.getId(), BOTTOM, PARENT_ID, BOTTOM,
-                        yTrans);
+                constraintSet.connect(mUserSwitcherViewGroup.getId(), BOTTOM, PARENT_ID, BOTTOM);
                 constraintSet.connect(mViewFlipper.getId(), TOP, PARENT_ID, TOP);
                 constraintSet.connect(mViewFlipper.getId(), BOTTOM, PARENT_ID, BOTTOM);
                 constraintSet.setHorizontalChainStyle(mUserSwitcherViewGroup.getId(), CHAIN_SPREAD);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index c32b853..061bab8 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -127,6 +127,7 @@
     private View.OnKeyListener mOnKeyListener = (v, keyCode, event) -> interceptMediaKey(event);
     private ActivityStarter.OnDismissAction mDismissAction;
     private Runnable mCancelAction;
+    private boolean mWillRunDismissFromKeyguard;
 
     private int mLastOrientation = Configuration.ORIENTATION_UNDEFINED;
 
@@ -259,11 +260,21 @@
          */
         @Override
         public void finish(boolean strongAuth, int targetUserId) {
+            if (mFeatureFlags.isEnabled(Flags.PREVENT_BYPASS_KEYGUARD)
+                    && !mKeyguardStateController.canDismissLockScreen() && !strongAuth) {
+                Log.e(TAG,
+                        "Tried to dismiss keyguard when lockscreen is not dismissible and user "
+                                + "was not authenticated with a primary security method "
+                                + "(pin/password/pattern).");
+                return;
+            }
             // If there's a pending runnable because the user interacted with a widget
             // and we're leaving keyguard, then run it.
             boolean deferKeyguardDone = false;
+            mWillRunDismissFromKeyguard = false;
             if (mDismissAction != null) {
                 deferKeyguardDone = mDismissAction.onDismiss();
+                mWillRunDismissFromKeyguard = mDismissAction.willRunAnimationOnKeyguard();
                 mDismissAction = null;
                 mCancelAction = null;
             }
@@ -526,6 +537,13 @@
     }
 
     /**
+     * @return will the dismissal run from the keyguard layout (instead of from bouncer)
+     */
+    public boolean willRunDismissFromKeyguard() {
+        return mWillRunDismissFromKeyguard;
+    }
+
+    /**
      * Remove any dismiss action or cancel action that was set.
      */
     public void cancelDismissAction() {
@@ -1055,23 +1073,28 @@
     }
 
     private void reloadColors() {
-        reinflateViewFlipper();
-        mView.reloadColors();
+        reinflateViewFlipper(() -> mView.reloadColors());
     }
 
     /** Handles density or font scale changes. */
     private void onDensityOrFontScaleChanged() {
-        reinflateViewFlipper();
-        mView.onDensityOrFontScaleChanged();
+        reinflateViewFlipper(() -> mView.onDensityOrFontScaleChanged());
     }
 
     /**
      * Reinflate the view flipper child view.
      */
-    public void reinflateViewFlipper() {
+    public void reinflateViewFlipper(
+            KeyguardSecurityViewFlipperController.OnViewInflatedListener onViewInflatedListener) {
         mSecurityViewFlipperController.clearViews();
-        mSecurityViewFlipperController.getSecurityView(mCurrentSecurityMode,
-                mKeyguardSecurityCallback);
+        if (mFeatureFlags.isEnabled(Flags.ASYNC_INFLATE_BOUNCER)) {
+            mSecurityViewFlipperController.asynchronouslyInflateView(mCurrentSecurityMode,
+                    mKeyguardSecurityCallback, onViewInflatedListener);
+        } else {
+            mSecurityViewFlipperController.getSecurityView(mCurrentSecurityMode,
+                    mKeyguardSecurityCallback);
+            onViewInflatedListener.onViewInflated();
+        }
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
index 39b567f..68e1dd7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
@@ -19,11 +19,16 @@
 import android.util.Log;
 import android.view.LayoutInflater;
 
+import androidx.annotation.Nullable;
+import androidx.asynclayoutinflater.view.AsyncLayoutInflater;
+
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.keyguard.KeyguardInputViewController.Factory;
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
 import com.android.keyguard.dagger.KeyguardBouncerScope;
 import com.android.systemui.R;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.util.ViewController;
 
 import java.util.ArrayList;
@@ -44,18 +49,24 @@
     private final List<KeyguardInputViewController<KeyguardInputView>> mChildren =
             new ArrayList<>();
     private final LayoutInflater mLayoutInflater;
+    private final AsyncLayoutInflater mAsyncLayoutInflater;
     private final EmergencyButtonController.Factory mEmergencyButtonControllerFactory;
     private final Factory mKeyguardSecurityViewControllerFactory;
+    private final FeatureFlags mFeatureFlags;
 
     @Inject
     protected KeyguardSecurityViewFlipperController(KeyguardSecurityViewFlipper view,
             LayoutInflater layoutInflater,
+            AsyncLayoutInflater asyncLayoutInflater,
             KeyguardInputViewController.Factory keyguardSecurityViewControllerFactory,
-            EmergencyButtonController.Factory emergencyButtonControllerFactory) {
+            EmergencyButtonController.Factory emergencyButtonControllerFactory,
+            FeatureFlags featureFlags) {
         super(view);
         mKeyguardSecurityViewControllerFactory = keyguardSecurityViewControllerFactory;
         mLayoutInflater = layoutInflater;
         mEmergencyButtonControllerFactory = emergencyButtonControllerFactory;
+        mAsyncLayoutInflater = asyncLayoutInflater;
+        mFeatureFlags = featureFlags;
     }
 
     @Override
@@ -92,13 +103,12 @@
             }
         }
 
-        if (childController == null
+        if (!mFeatureFlags.isEnabled(Flags.ASYNC_INFLATE_BOUNCER) && childController == null
                 && securityMode != SecurityMode.None && securityMode != SecurityMode.Invalid) {
-
             int layoutId = getLayoutIdFor(securityMode);
             KeyguardInputView view = null;
             if (layoutId != 0) {
-                if (DEBUG) Log.v(TAG, "inflating id = " + layoutId);
+                if (DEBUG) Log.v(TAG, "inflating on main thread id = " + layoutId);
                 view = (KeyguardInputView) mLayoutInflater.inflate(
                         layoutId, mView, false);
                 mView.addView(view);
@@ -119,6 +129,36 @@
         return childController;
     }
 
+    /**
+     * Asynchronously inflate view and then add it to view flipper on the main thread when complete.
+     *
+     * OnInflateFinishedListener will be called on the main thread.
+     *
+     * @param securityMode
+     * @param keyguardSecurityCallback
+     */
+    public void asynchronouslyInflateView(SecurityMode securityMode,
+            KeyguardSecurityCallback keyguardSecurityCallback,
+            @Nullable OnViewInflatedListener onViewInflatedListener) {
+        int layoutId = getLayoutIdFor(securityMode);
+        if (layoutId != 0) {
+            if (DEBUG) Log.v(TAG, "inflating on bg thread id = " + layoutId);
+            mAsyncLayoutInflater.inflate(layoutId, mView,
+                    (view, resId, parent) -> {
+                        mView.addView(view);
+                        KeyguardInputViewController<KeyguardInputView> childController =
+                                mKeyguardSecurityViewControllerFactory.create(
+                                        (KeyguardInputView) view, securityMode,
+                                        keyguardSecurityCallback);
+                        childController.init();
+                        mChildren.add(childController);
+                        if (onViewInflatedListener != null) {
+                            onViewInflatedListener.onViewInflated();
+                        }
+                    });
+        }
+    }
+
     private int getLayoutIdFor(SecurityMode securityMode) {
         switch (securityMode) {
             case Pattern: return R.layout.keyguard_pattern_view;
@@ -162,4 +202,10 @@
             return 0;
         }
     }
+
+    /** Listener to when view has finished inflation. */
+    public interface OnViewInflatedListener {
+        /** Notifies that view has been inflated */
+        void onViewInflated();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index be01377..e154695 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -68,6 +68,7 @@
 import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_STRONG_AUTH_CHANGED;
 import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_USER_SWITCHING;
 import static com.android.systemui.DejankUtils.whitelistIpcs;
+import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_OPENED;
 import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_UNKNOWN;
 
 import android.annotation.AnyThread;
@@ -153,6 +154,7 @@
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.policy.DevicePostureController;
+import com.android.systemui.statusbar.policy.DevicePostureController.DevicePostureInt;
 import com.android.systemui.telephony.TelephonyListenerManager;
 import com.android.systemui.util.Assert;
 import com.android.systemui.util.settings.SecureSettings;
@@ -359,7 +361,7 @@
     private final FaceManager mFaceManager;
     private final LockPatternUtils mLockPatternUtils;
     @VisibleForTesting
-    @DevicePostureController.DevicePostureInt
+    @DevicePostureInt
     protected int mConfigFaceAuthSupportedPosture;
 
     private KeyguardBypassController mKeyguardBypassController;
@@ -676,7 +678,10 @@
     public void onTrustManagedChanged(boolean managed, int userId) {
         Assert.isMainThread();
         mUserTrustIsManaged.put(userId, managed);
-        mUserTrustIsUsuallyManaged.put(userId, mTrustManager.isTrustUsuallyManaged(userId));
+        boolean trustUsuallyManaged = mTrustManager.isTrustUsuallyManaged(userId);
+        mLogger.logTrustUsuallyManagedUpdated(userId, mUserTrustIsUsuallyManaged.get(userId),
+                trustUsuallyManaged, "onTrustManagedChanged");
+        mUserTrustIsUsuallyManaged.put(userId, trustUsuallyManaged);
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
@@ -704,6 +709,12 @@
         if (mKeyguardGoingAway) {
             updateFaceListeningState(BIOMETRIC_ACTION_STOP,
                     FACE_AUTH_STOPPED_KEYGUARD_GOING_AWAY);
+            for (int i = 0; i < mCallbacks.size(); i++) {
+                KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+                if (cb != null) {
+                    cb.onKeyguardGoingAway();
+                }
+            }
         }
         updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
     }
@@ -864,7 +875,10 @@
 
     private void reportSuccessfulBiometricUnlock(boolean isStrongBiometric, int userId) {
         mBackgroundExecutor.execute(
-                () -> mLockPatternUtils.reportSuccessfulBiometricUnlock(isStrongBiometric, userId));
+                () -> {
+                    mLogger.logReportSuccessfulBiometricUnlock(isStrongBiometric, userId);
+                    mLockPatternUtils.reportSuccessfulBiometricUnlock(isStrongBiometric, userId);
+                });
     }
 
     private void handleFingerprintAuthFailed() {
@@ -1588,7 +1602,7 @@
             requestActiveUnlock(
                     ActiveUnlockConfig.ActiveUnlockRequestOrigin.ASSISTANT,
                     "assistant",
-                    false);
+                    /* dismissKeyguard */ true);
         }
     }
 
@@ -1840,10 +1854,20 @@
     final DevicePostureController.Callback mPostureCallback =
             new DevicePostureController.Callback() {
                 @Override
-                public void onPostureChanged(int posture) {
+                public void onPostureChanged(@DevicePostureInt int posture) {
+                    boolean currentPostureAllowsFaceAuth = doesPostureAllowFaceAuth(mPostureState);
+                    boolean newPostureAllowsFaceAuth = doesPostureAllowFaceAuth(posture);
                     mPostureState = posture;
-                    updateFaceListeningState(BIOMETRIC_ACTION_UPDATE,
-                            FACE_AUTH_UPDATED_POSTURE_CHANGED);
+                    if (currentPostureAllowsFaceAuth && !newPostureAllowsFaceAuth) {
+                        mLogger.d("New posture does not allow face auth, stopping it");
+                        updateFaceListeningState(BIOMETRIC_ACTION_STOP,
+                                FACE_AUTH_UPDATED_POSTURE_CHANGED);
+                    }
+                    if (mPostureState == DEVICE_POSTURE_OPENED) {
+                        mLogger.d("Posture changed to open - attempting to request active unlock");
+                        requestActiveUnlockFromWakeReason(PowerManager.WAKE_REASON_UNFOLD_DEVICE,
+                                false);
+                    }
                 }
             };
 
@@ -1970,26 +1994,10 @@
             FACE_AUTH_UPDATED_STARTED_WAKING_UP.setExtraInfo(pmWakeReason);
             updateFaceListeningState(BIOMETRIC_ACTION_UPDATE,
                     FACE_AUTH_UPDATED_STARTED_WAKING_UP);
-
-            final ActiveUnlockConfig.ActiveUnlockRequestOrigin requestOrigin =
-                    mActiveUnlockConfig.isWakeupConsideredUnlockIntent(pmWakeReason)
-                            ? ActiveUnlockConfig.ActiveUnlockRequestOrigin.UNLOCK_INTENT
-                            : ActiveUnlockConfig.ActiveUnlockRequestOrigin.WAKE;
-            final String reason = "wakingUp - " + PowerManager.wakeReasonToString(pmWakeReason);
-            if (mActiveUnlockConfig.shouldWakeupForceDismissKeyguard(pmWakeReason)) {
-                requestActiveUnlockDismissKeyguard(
-                        requestOrigin,
-                        reason
-                );
-            } else {
-                requestActiveUnlock(
-                        requestOrigin,
-                        reason
-                );
-            }
         } else {
             mLogger.logSkipUpdateFaceListeningOnWakeup(pmWakeReason);
         }
+        requestActiveUnlockFromWakeReason(pmWakeReason, true);
 
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
@@ -2372,8 +2380,12 @@
         updateSecondaryLockscreenRequirement(user);
         List<UserInfo> allUsers = mUserManager.getUsers();
         for (UserInfo userInfo : allUsers) {
+            boolean trustUsuallyManaged = mTrustManager.isTrustUsuallyManaged(userInfo.id);
+            mLogger.logTrustUsuallyManagedUpdated(userInfo.id,
+                    mUserTrustIsUsuallyManaged.get(userInfo.id),
+                    trustUsuallyManaged, "init from constructor");
             mUserTrustIsUsuallyManaged.put(userInfo.id,
-                    mTrustManager.isTrustUsuallyManaged(userInfo.id));
+                    trustUsuallyManaged);
         }
         updateAirplaneModeState();
 
@@ -2413,10 +2425,14 @@
     }
 
     private void updateFaceEnrolled(int userId) {
-        mIsFaceEnrolled = whitelistIpcs(
+        Boolean isFaceEnrolled = whitelistIpcs(
                 () -> mFaceManager != null && mFaceManager.isHardwareDetected()
                         && mFaceManager.hasEnrolledTemplates(userId)
                         && mBiometricEnabledForUser.get(userId));
+        if (mIsFaceEnrolled != isFaceEnrolled) {
+            mLogger.logFaceEnrolledUpdated(mIsFaceEnrolled, isFaceEnrolled);
+        }
+        mIsFaceEnrolled = isFaceEnrolled;
     }
 
     public boolean isFaceSupported() {
@@ -2495,11 +2511,13 @@
         // If this message exists, we should not authenticate again until this message is
         // consumed by the handler
         if (mHandler.hasMessages(MSG_BIOMETRIC_AUTHENTICATION_CONTINUE)) {
+            mLogger.logHandlerHasAuthContinueMsgs(action);
             return;
         }
 
         // don't start running fingerprint until they're registered
         if (!mAuthController.areAllFingerprintAuthenticatorsRegistered()) {
+            mLogger.d("All FP authenticators not registered, skipping FP listening state update");
             return;
         }
         final boolean shouldListenForFingerprint = shouldListenForFingerprint(isUdfpsSupported());
@@ -2612,6 +2630,32 @@
         }
     }
 
+    private void requestActiveUnlockFromWakeReason(@PowerManager.WakeReason int wakeReason,
+            boolean powerManagerWakeup) {
+        if (!mFaceWakeUpTriggersConfig.shouldTriggerFaceAuthOnWakeUpFrom(wakeReason)) {
+            mLogger.logActiveUnlockRequestSkippedForWakeReasonDueToFaceConfig(wakeReason);
+            return;
+        }
+
+        final ActiveUnlockConfig.ActiveUnlockRequestOrigin requestOrigin =
+                mActiveUnlockConfig.isWakeupConsideredUnlockIntent(wakeReason)
+                        ? ActiveUnlockConfig.ActiveUnlockRequestOrigin.UNLOCK_INTENT
+                        : ActiveUnlockConfig.ActiveUnlockRequestOrigin.WAKE;
+        final String reason = "wakingUp - " + PowerManager.wakeReasonToString(wakeReason)
+                + " powerManagerWakeup=" + powerManagerWakeup;
+        if (mActiveUnlockConfig.shouldWakeupForceDismissKeyguard(wakeReason)) {
+            requestActiveUnlockDismissKeyguard(
+                    requestOrigin,
+                    reason
+            );
+        } else {
+            requestActiveUnlock(
+                    requestOrigin,
+                    reason
+            );
+        }
+    }
+
     /**
      * Attempts to trigger active unlock from trust agent.
      */
@@ -2872,9 +2916,7 @@
         final boolean biometricEnabledForUser = mBiometricEnabledForUser.get(user);
         final boolean shouldListenForFaceAssistant = shouldListenForFaceAssistant();
         final boolean isUdfpsFingerDown = mAuthController.isUdfpsFingerDown();
-        final boolean isPostureAllowedForFaceAuth =
-                mConfigFaceAuthSupportedPosture == 0 /* DEVICE_POSTURE_UNKNOWN */ ? true
-                        : (mPostureState == mConfigFaceAuthSupportedPosture);
+        final boolean isPostureAllowedForFaceAuth = doesPostureAllowFaceAuth(mPostureState);
         // Only listen if this KeyguardUpdateMonitor belongs to the primary user. There is an
         // instance of KeyguardUpdateMonitor for each user but KeyguardUpdateMonitor is user-aware.
         final boolean shouldListen =
@@ -2923,6 +2965,11 @@
         return shouldListen;
     }
 
+    private boolean doesPostureAllowFaceAuth(@DevicePostureInt int posture) {
+        return mConfigFaceAuthSupportedPosture == DEVICE_POSTURE_UNKNOWN
+                || (posture == mConfigFaceAuthSupportedPosture);
+    }
+
     private void logListenerModelData(@NonNull KeyguardListenModel model) {
         mLogger.logKeyguardListenerModel(model);
         if (model instanceof KeyguardFingerprintListenModel) {
@@ -3071,8 +3118,13 @@
     @VisibleForTesting
     boolean isUnlockWithFingerprintPossible(int userId) {
         // TODO (b/242022358), make this rely on onEnrollmentChanged event and update it only once.
-        mIsUnlockWithFingerprintPossible.put(userId, mFpm != null && mFpm.isHardwareDetected()
-                && !isFingerprintDisabled(userId) && mFpm.hasEnrolledTemplates(userId));
+        boolean newFpEnrolled = mFpm != null && mFpm.isHardwareDetected()
+                && !isFingerprintDisabled(userId) && mFpm.hasEnrolledTemplates(userId);
+        Boolean oldFpEnrolled = mIsUnlockWithFingerprintPossible.getOrDefault(userId, false);
+        if (oldFpEnrolled != newFpEnrolled) {
+            mLogger.logFpEnrolledUpdated(userId, oldFpEnrolled, newFpEnrolled);
+        }
+        mIsUnlockWithFingerprintPossible.put(userId, newFpEnrolled);
         return mIsUnlockWithFingerprintPossible.get(userId);
     }
 
@@ -3188,7 +3240,10 @@
     void handleUserSwitching(int userId, CountDownLatch latch) {
         Assert.isMainThread();
         clearBiometricRecognized();
-        mUserTrustIsUsuallyManaged.put(userId, mTrustManager.isTrustUsuallyManaged(userId));
+        boolean trustUsuallyManaged = mTrustManager.isTrustUsuallyManaged(userId);
+        mLogger.logTrustUsuallyManagedUpdated(userId, mUserTrustIsUsuallyManaged.get(userId),
+                trustUsuallyManaged, "userSwitching");
+        mUserTrustIsUsuallyManaged.put(userId, trustUsuallyManaged);
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
@@ -3336,8 +3391,8 @@
      */
     private void handleBatteryUpdate(BatteryStatus status) {
         Assert.isMainThread();
-        mLogger.d("handleBatteryUpdate");
         final boolean batteryUpdateInteresting = isBatteryUpdateInteresting(mBatteryStatus, status);
+        mLogger.logHandleBatteryUpdate(batteryUpdateInteresting);
         mBatteryStatus = status;
         if (batteryUpdateInteresting) {
             for (int i = 0; i < mCallbacks.size(); i++) {
@@ -3614,7 +3669,9 @@
      * Register to receive notifications about general keyguard information
      * (see {@link KeyguardUpdateMonitorCallback}.
      *
-     * @param callback The callback to register
+     * @param callback The callback to register. Stay away from passing anonymous instances
+     *                 as they will likely be dereferenced. Ensure that the callback is a class
+     *                 field to persist it.
      */
     public void registerCallback(KeyguardUpdateMonitorCallback callback) {
         Assert.isMainThread();
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 0d4889a..feff216 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -317,4 +317,9 @@
      * Called when the non-strong biometric state changed.
      */
     public void onNonStrongBiometricAllowedChanged(int userId) { }
+
+    /**
+     * Called when keyguard is going away or not going away.
+     */
+    public void onKeyguardGoingAway() { }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
index 6c3c246..7661b8d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
@@ -168,7 +168,7 @@
     /**
      * Stop showing the alternate bouncer, if showing.
      */
-    void hideAlternateBouncer(boolean forceUpdateScrim);
+    void hideAlternateBouncer(boolean updateScrim);
 
     // TODO: Deprecate registerStatusBar in KeyguardViewController interface. It is currently
     //  only used for testing purposes in StatusBarKeyguardViewManager, and it prevents us from
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
index 3b0644e..7c7680a 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
@@ -50,6 +50,7 @@
     private int mDigit = -1;
     private int mTextViewResId;
     private PasswordTextView mTextView;
+    private boolean mAnimationsEnabled = true;
 
     @Nullable
     private NumPadAnimator mAnimator;
@@ -164,11 +165,11 @@
         switch(event.getActionMasked()) {
             case MotionEvent.ACTION_DOWN:
                 doHapticKeyClick();
-                if (mAnimator != null) mAnimator.expand();
+                if (mAnimator != null && mAnimationsEnabled) mAnimator.expand();
                 break;
             case MotionEvent.ACTION_UP:
             case MotionEvent.ACTION_CANCEL:
-                if (mAnimator != null) mAnimator.contract();
+                if (mAnimator != null && mAnimationsEnabled) mAnimator.contract();
                 break;
         }
         return super.onTouchEvent(event);
@@ -228,4 +229,11 @@
             mAnimator.setProgress(progress);
         }
     }
+
+    /**
+     * Controls the animation when a key is pressed
+     */
+    public void setAnimationEnabled(boolean enabled) {
+        mAnimationsEnabled = enabled;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java b/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java
index 35cae09..4881c914 100644
--- a/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java
+++ b/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java
@@ -30,7 +30,6 @@
 import android.graphics.Typeface;
 import android.os.PowerManager;
 import android.os.SystemClock;
-import android.provider.Settings;
 import android.text.InputType;
 import android.text.TextUtils;
 import android.util.AttributeSet;
@@ -98,7 +97,7 @@
     private Interpolator mAppearInterpolator;
     private Interpolator mDisappearInterpolator;
     private Interpolator mFastOutSlowInInterpolator;
-    private boolean mShowPassword;
+    private boolean mShowPassword = true;
     private UserActivityListener mUserActivityListener;
 
     public interface UserActivityListener {
@@ -152,8 +151,6 @@
         mDrawPaint.setTypeface(Typeface.create(
                 context.getString(com.android.internal.R.string.config_headlineFontFamily),
                 0));
-        mShowPassword = Settings.System.getInt(mContext.getContentResolver(),
-                Settings.System.TEXT_SHOW_PASSWORD, 1) == 1;
         mAppearInterpolator = AnimationUtils.loadInterpolator(mContext,
                 android.R.interpolator.linear_out_slow_in);
         mDisappearInterpolator = AnimationUtils.loadInterpolator(mContext,
@@ -385,6 +382,13 @@
         info.setInputType(InputType.TYPE_NUMBER_VARIATION_PASSWORD);
     }
 
+    /**
+     * Controls whether the last entered digit is briefly shown after being entered
+     */
+    public void setShowPassword(boolean enabled) {
+        mShowPassword = enabled;
+    }
+
     private class CharState {
         char whichChar;
         ValueAnimator textAnimator;
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/BiometricUnlockLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/BiometricUnlockLogger.kt
index bc0bd8c..20f9007 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/BiometricUnlockLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/BiometricUnlockLogger.kt
@@ -16,6 +16,7 @@
 
 package com.android.keyguard.logging
 
+import android.hardware.biometrics.BiometricSourceType
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.log.dagger.BiometricLog
 import com.android.systemui.plugins.log.LogBuffer
@@ -157,6 +158,36 @@
             }
         )
     }
+
+    fun deferringAuthenticationDueToSleep(
+        userId: Int,
+        biometricSourceType: BiometricSourceType,
+        alreadyPendingAuth: Boolean
+    ) {
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            {
+                int1 = userId
+                str1 = biometricSourceType.name
+                bool2 = alreadyPendingAuth
+            },
+            {
+                "onBiometricAuthenticated, deferring auth: userId: $int1, " +
+                    "biometricSourceType: $str1, " +
+                    "goingToSleep: true, " +
+                    "mPendingAuthentication != null: $bool2"
+            }
+        )
+    }
+
+    fun finishedGoingToSleepWithPendingAuth() {
+        logBuffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            "onFinishedGoingToSleep with pendingAuthenticated != null"
+        )
+    }
 }
 
 private fun wakeAndUnlockModeToString(mode: Int): String {
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt
index 379c78a..4d71a89 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt
@@ -16,6 +16,7 @@
 
 package com.android.keyguard.logging
 
+import com.android.systemui.biometrics.AuthRippleController
 import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController
 import com.android.systemui.log.dagger.KeyguardLog
 import com.android.systemui.plugins.log.LogBuffer
@@ -96,6 +97,21 @@
         )
     }
 
+    fun logUpdateBatteryIndication(
+        powerIndication: String,
+        pluggedIn: Boolean,
+    ) {
+        buffer.log(
+            KeyguardIndicationController.TAG,
+            LogLevel.DEBUG,
+            {
+                str1 = powerIndication
+                bool1 = pluggedIn
+            },
+            { "updateBatteryIndication powerIndication:$str1 pluggedIn:$bool1" }
+        )
+    }
+
     fun logKeyguardSwitchIndication(
         type: Int,
         message: String?,
@@ -111,6 +127,28 @@
         )
     }
 
+    fun logRefreshBatteryInfo(
+        isChargingOrFull: Boolean,
+        powerPluggedIn: Boolean,
+        batteryLevel: Int,
+        batteryOverheated: Boolean
+    ) {
+        buffer.log(
+            KeyguardIndicationController.TAG,
+            LogLevel.DEBUG,
+            {
+                bool1 = isChargingOrFull
+                bool2 = powerPluggedIn
+                bool3 = batteryOverheated
+                int1 = batteryLevel
+            },
+            {
+                "refreshBatteryInfo isChargingOrFull:$bool1 powerPluggedIn:$bool2" +
+                    " batteryOverheated:$bool3 batteryLevel:$int1"
+            }
+        )
+    }
+
     fun getKeyguardSwitchIndicationNonSensitiveLog(type: Int, message: String?): String {
         // only show the battery string. other strings may contain sensitive info
         return if (type == KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BATTERY) {
@@ -120,4 +158,29 @@
             "type=${KeyguardIndicationRotateTextViewController.indicationTypeToString(type)}"
         }
     }
+
+    fun notShowingUnlockRipple(keyguardNotShowing: Boolean, unlockNotAllowed: Boolean) {
+        buffer.log(
+            AuthRippleController.TAG,
+            LogLevel.DEBUG,
+            {
+                bool1 = keyguardNotShowing
+                bool2 = unlockNotAllowed
+            },
+            { "Not showing unlock ripple: keyguardNotShowing: $bool1, unlockNotAllowed: $bool2" }
+        )
+    }
+
+    fun showingUnlockRippleAt(x: Int, y: Int, context: String) {
+        buffer.log(
+            AuthRippleController.TAG,
+            LogLevel.DEBUG,
+            {
+                int1 = x
+                int2 = y
+                str1 = context
+            },
+            { "Showing unlock ripple with center (x, y): ($int1, $int2), context: $str1" }
+        )
+    }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
index e53f6ad..1661806 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
@@ -26,6 +26,7 @@
 import com.android.keyguard.KeyguardListenModel
 import com.android.keyguard.KeyguardUpdateMonitorCallback
 import com.android.keyguard.TrustGrantFlags
+import com.android.systemui.log.dagger.KeyguardUpdateMonitorLog
 import com.android.systemui.plugins.log.LogBuffer
 import com.android.systemui.plugins.log.LogLevel
 import com.android.systemui.plugins.log.LogLevel.DEBUG
@@ -33,18 +34,15 @@
 import com.android.systemui.plugins.log.LogLevel.INFO
 import com.android.systemui.plugins.log.LogLevel.VERBOSE
 import com.android.systemui.plugins.log.LogLevel.WARNING
-import com.android.systemui.log.dagger.KeyguardUpdateMonitorLog
 import com.google.errorprone.annotations.CompileTimeConstant
 import javax.inject.Inject
 
 private const val TAG = "KeyguardUpdateMonitorLog"
 
-/**
- * Helper class for logging for [com.android.keyguard.KeyguardUpdateMonitor]
- */
-class KeyguardUpdateMonitorLogger @Inject constructor(
-        @KeyguardUpdateMonitorLog private val logBuffer: LogBuffer
-) {
+/** Helper class for logging for [com.android.keyguard.KeyguardUpdateMonitor] */
+class KeyguardUpdateMonitorLogger
+@Inject
+constructor(@KeyguardUpdateMonitorLog private val logBuffer: LogBuffer) {
     fun d(@CompileTimeConstant msg: String) = log(msg, DEBUG)
 
     fun e(@CompileTimeConstant msg: String) = log(msg, ERROR)
@@ -56,15 +54,26 @@
     fun log(@CompileTimeConstant msg: String, level: LogLevel) = logBuffer.log(TAG, level, msg)
 
     fun logActiveUnlockTriggered(reason: String?) {
-        logBuffer.log("ActiveUnlock", DEBUG,
-                { str1 = reason },
-                { "initiate active unlock triggerReason=$str1" })
+        logBuffer.log(
+            "ActiveUnlock",
+            DEBUG,
+            { str1 = reason },
+            { "initiate active unlock triggerReason=$str1" }
+        )
+    }
+
+    fun logActiveUnlockRequestSkippedForWakeReasonDueToFaceConfig(wakeReason: Int) {
+        logBuffer.log(
+            "ActiveUnlock",
+            DEBUG,
+            { int1 = wakeReason },
+            { "Skip requesting active unlock from wake reason that doesn't trigger face auth" +
+                    " reason=${PowerManager.wakeReasonToString(int1)}" }
+        )
     }
 
     fun logAuthInterruptDetected(active: Boolean) {
-        logBuffer.log(TAG, DEBUG,
-                { bool1 = active },
-                { "onAuthInterruptDetected($bool1)" })
+        logBuffer.log(TAG, DEBUG, { bool1 = active }, { "onAuthInterruptDetected($bool1)" })
     }
 
     fun logBroadcastReceived(action: String?) {
@@ -72,9 +81,12 @@
     }
 
     fun logDeviceProvisionedState(deviceProvisioned: Boolean) {
-        logBuffer.log(TAG, DEBUG,
-                { bool1 = deviceProvisioned },
-                { "DEVICE_PROVISIONED state = $bool1" })
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            { bool1 = deviceProvisioned },
+            { "DEVICE_PROVISIONED state = $bool1" }
+        )
     }
 
     fun logException(ex: Exception, @CompileTimeConstant logMsg: String) {
@@ -82,46 +94,56 @@
     }
 
     fun logFaceAcquired(acquireInfo: Int) {
-        logBuffer.log(TAG, DEBUG,
-                { int1 = acquireInfo },
-                { "Face acquired acquireInfo=$int1" })
+        logBuffer.log(TAG, DEBUG, { int1 = acquireInfo }, { "Face acquired acquireInfo=$int1" })
     }
 
     fun logFaceAuthDisabledForUser(userId: Int) {
-        logBuffer.log(TAG, DEBUG,
-                { int1 = userId },
-                { "Face authentication disabled by DPM for userId: $int1" })
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            { int1 = userId },
+            { "Face authentication disabled by DPM for userId: $int1" }
+        )
     }
     fun logFaceAuthError(msgId: Int, originalErrMsg: String) {
-        logBuffer.log(TAG, DEBUG, {
-                    str1 = originalErrMsg
-                    int1 = msgId
-                }, { "Face error received: $str1 msgId= $int1" })
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            {
+                str1 = originalErrMsg
+                int1 = msgId
+            },
+            { "Face error received: $str1 msgId= $int1" }
+        )
     }
 
     fun logFaceAuthForWrongUser(authUserId: Int) {
-        logBuffer.log(TAG, DEBUG,
-                { int1 = authUserId },
-                { "Face authenticated for wrong user: $int1" })
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            { int1 = authUserId },
+            { "Face authenticated for wrong user: $int1" }
+        )
     }
 
     fun logFaceAuthHelpMsg(msgId: Int, helpMsg: String?) {
-        logBuffer.log(TAG, DEBUG, {
-                    int1 = msgId
-                    str1 = helpMsg
-                }, { "Face help received, msgId: $int1 msg: $str1" })
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            {
+                int1 = msgId
+                str1 = helpMsg
+            },
+            { "Face help received, msgId: $int1 msg: $str1" }
+        )
     }
 
     fun logFaceAuthRequested(reason: String?) {
-        logBuffer.log(TAG, DEBUG, {
-            str1 = reason
-        }, { "requestFaceAuth() reason=$str1" })
+        logBuffer.log(TAG, DEBUG, { str1 = reason }, { "requestFaceAuth() reason=$str1" })
     }
 
     fun logFaceAuthSuccess(userId: Int) {
-        logBuffer.log(TAG, DEBUG,
-                { int1 = userId },
-                { "Face auth succeeded for user $int1" })
+        logBuffer.log(TAG, DEBUG, { int1 = userId }, { "Face auth succeeded for user $int1" })
     }
 
     fun logFaceLockoutReset(@LockoutMode mode: Int) {
@@ -133,21 +155,30 @@
     }
 
     fun logFaceUnlockPossible(isFaceUnlockPossible: Boolean) {
-        logBuffer.log(TAG, DEBUG,
-                { bool1 = isFaceUnlockPossible },
-                {"isUnlockWithFacePossible: $bool1"})
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            { bool1 = isFaceUnlockPossible },
+            { "isUnlockWithFacePossible: $bool1" }
+        )
     }
 
     fun logFingerprintAuthForWrongUser(authUserId: Int) {
-        logBuffer.log(TAG, DEBUG,
-                { int1 = authUserId },
-                { "Fingerprint authenticated for wrong user: $int1" })
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            { int1 = authUserId },
+            { "Fingerprint authenticated for wrong user: $int1" }
+        )
     }
 
     fun logFingerprintDisabledForUser(userId: Int) {
-        logBuffer.log(TAG, DEBUG,
-                { int1 = userId },
-                { "Fingerprint disabled by DPM for userId: $int1" })
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            { int1 = userId },
+            { "Fingerprint disabled by DPM for userId: $int1" }
+        )
     }
 
     fun logFingerprintLockoutReset(@LockoutMode mode: Int) {
@@ -155,16 +186,24 @@
     }
 
     fun logFingerprintRunningState(fingerprintRunningState: Int) {
-        logBuffer.log(TAG, DEBUG,
-                { int1 = fingerprintRunningState },
-                { "fingerprintRunningState: $int1" })
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            { int1 = fingerprintRunningState },
+            { "fingerprintRunningState: $int1" }
+        )
     }
 
     fun logFingerprintSuccess(userId: Int, isStrongBiometric: Boolean) {
-        logBuffer.log(TAG, DEBUG, {
-            int1 = userId
-            bool1 = isStrongBiometric
-        }, {"Fingerprint auth successful: userId: $int1, isStrongBiometric: $bool1"})
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            {
+                int1 = userId
+                bool1 = isStrongBiometric
+            },
+            { "Fingerprint auth successful: userId: $int1, isStrongBiometric: $bool1" }
+        )
     }
 
     fun logFaceDetected(userId: Int, isStrongBiometric: Boolean) {
@@ -182,29 +221,42 @@
     }
 
     fun logFingerprintError(msgId: Int, originalErrMsg: String) {
-        logBuffer.log(TAG, DEBUG, {
-            str1 = originalErrMsg
-            int1 = msgId
-        }, { "Fingerprint error received: $str1 msgId= $int1" })
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            {
+                str1 = originalErrMsg
+                int1 = msgId
+            },
+            { "Fingerprint error received: $str1 msgId= $int1" }
+        )
     }
 
     fun logInvalidSubId(subId: Int) {
-        logBuffer.log(TAG, INFO,
-                { int1 = subId },
-                { "Previously active sub id $int1 is now invalid, will remove" })
+        logBuffer.log(
+            TAG,
+            INFO,
+            { int1 = subId },
+            { "Previously active sub id $int1 is now invalid, will remove" }
+        )
     }
 
     fun logPrimaryKeyguardBouncerChanged(
-            primaryBouncerIsOrWillBeShowing: Boolean,
-            primaryBouncerFullyShown: Boolean
+        primaryBouncerIsOrWillBeShowing: Boolean,
+        primaryBouncerFullyShown: Boolean
     ) {
-        logBuffer.log(TAG, DEBUG, {
-            bool1 = primaryBouncerIsOrWillBeShowing
-            bool2 = primaryBouncerFullyShown
-        }, {
-            "handlePrimaryBouncerChanged " +
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            {
+                bool1 = primaryBouncerIsOrWillBeShowing
+                bool2 = primaryBouncerFullyShown
+            },
+            {
+                "handlePrimaryBouncerChanged " +
                     "primaryBouncerIsOrWillBeShowing=$bool1 primaryBouncerFullyShown=$bool2"
-        })
+            }
+        )
     }
 
     fun logKeyguardListenerModel(model: KeyguardListenModel) {
@@ -212,98 +264,134 @@
     }
 
     fun logKeyguardShowingChanged(showing: Boolean, occluded: Boolean, visible: Boolean) {
-        logBuffer.log(TAG, DEBUG, {
-            bool1 = showing
-            bool2 = occluded
-            bool3 = visible
-        }, {
-            "keyguardShowingChanged(showing=$bool1 occluded=$bool2 visible=$bool3)"
-        })
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            {
+                bool1 = showing
+                bool2 = occluded
+                bool3 = visible
+            },
+            { "keyguardShowingChanged(showing=$bool1 occluded=$bool2 visible=$bool3)" }
+        )
     }
 
     fun logMissingSupervisorAppError(userId: Int) {
-        logBuffer.log(TAG, ERROR,
-                { int1 = userId },
-                { "No Profile Owner or Device Owner supervision app found for User $int1" })
+        logBuffer.log(
+            TAG,
+            ERROR,
+            { int1 = userId },
+            { "No Profile Owner or Device Owner supervision app found for User $int1" }
+        )
     }
 
     fun logPhoneStateChanged(newState: String?) {
-        logBuffer.log(TAG, DEBUG,
-                { str1 = newState },
-                { "handlePhoneStateChanged($str1)" })
+        logBuffer.log(TAG, DEBUG, { str1 = newState }, { "handlePhoneStateChanged($str1)" })
     }
 
     fun logRegisterCallback(callback: KeyguardUpdateMonitorCallback?) {
-        logBuffer.log(TAG, VERBOSE,
-                { str1 = "$callback" },
-                { "*** register callback for $str1" })
+        logBuffer.log(TAG, VERBOSE, { str1 = "$callback" }, { "*** register callback for $str1" })
     }
 
     fun logRetryingAfterFaceHwUnavailable(retryCount: Int) {
-        logBuffer.log(TAG, WARNING,
-                { int1 = retryCount },
-                { "Retrying face after HW unavailable, attempt $int1" })
+        logBuffer.log(
+            TAG,
+            WARNING,
+            { int1 = retryCount },
+            { "Retrying face after HW unavailable, attempt $int1" }
+        )
     }
 
     fun logRetryAfterFpErrorWithDelay(msgId: Int, errString: String?, delay: Int) {
-        logBuffer.log(TAG, DEBUG, {
-            int1 = msgId
-            int2 = delay
-            str1 = "$errString"
-        }, {
-            "Fingerprint scheduling retry auth after $int2 ms due to($int1) -> $str1"
-        })
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            {
+                int1 = msgId
+                int2 = delay
+                str1 = "$errString"
+            },
+            { "Fingerprint scheduling retry auth after $int2 ms due to($int1) -> $str1" }
+        )
     }
 
     fun logRetryAfterFpHwUnavailable(retryCount: Int) {
-        logBuffer.log(TAG, WARNING,
-                { int1 = retryCount },
-                { "Retrying fingerprint attempt: $int1" })
+        logBuffer.log(
+            TAG,
+            WARNING,
+            { int1 = retryCount },
+            { "Retrying fingerprint attempt: $int1" }
+        )
     }
 
     fun logSendPrimaryBouncerChanged(
         primaryBouncerIsOrWillBeShowing: Boolean,
         primaryBouncerFullyShown: Boolean,
     ) {
-        logBuffer.log(TAG, DEBUG, {
-            bool1 = primaryBouncerIsOrWillBeShowing
-            bool2 = primaryBouncerFullyShown
-        }, {
-            "sendPrimaryBouncerChanged primaryBouncerIsOrWillBeShowing=$bool1 " +
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            {
+                bool1 = primaryBouncerIsOrWillBeShowing
+                bool2 = primaryBouncerFullyShown
+            },
+            {
+                "sendPrimaryBouncerChanged primaryBouncerIsOrWillBeShowing=$bool1 " +
                     "primaryBouncerFullyShown=$bool2"
-        })
+            }
+        )
     }
 
     fun logServiceStateChange(subId: Int, serviceState: ServiceState?) {
-        logBuffer.log(TAG, DEBUG, {
-            int1 = subId
-            str1 = "$serviceState"
-        }, { "handleServiceStateChange(subId=$int1, serviceState=$str1)" })
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            {
+                int1 = subId
+                str1 = "$serviceState"
+            },
+            { "handleServiceStateChange(subId=$int1, serviceState=$str1)" }
+        )
     }
 
     fun logServiceStateIntent(action: String?, serviceState: ServiceState?, subId: Int) {
-        logBuffer.log(TAG, VERBOSE, {
-            str1 = action
-            str2 = "$serviceState"
-            int1 = subId
-        }, { "action $str1 serviceState=$str2 subId=$int1" })
+        logBuffer.log(
+            TAG,
+            VERBOSE,
+            {
+                str1 = action
+                str2 = "$serviceState"
+                int1 = subId
+            },
+            { "action $str1 serviceState=$str2 subId=$int1" }
+        )
     }
 
     fun logSimState(subId: Int, slotId: Int, state: Int) {
-        logBuffer.log(TAG, DEBUG, {
-            int1 = subId
-            int2 = slotId
-            long1 = state.toLong()
-        }, { "handleSimStateChange(subId=$int1, slotId=$int2, state=$long1)" })
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            {
+                int1 = subId
+                int2 = slotId
+                long1 = state.toLong()
+            },
+            { "handleSimStateChange(subId=$int1, slotId=$int2, state=$long1)" }
+        )
     }
 
     fun logSimStateFromIntent(action: String?, extraSimState: String?, slotId: Int, subId: Int) {
-        logBuffer.log(TAG, VERBOSE, {
-            str1 = action
-            str2 = extraSimState
-            int1 = slotId
-            int2 = subId
-        }, { "action $str1 state: $str2 slotId: $int1 subid: $int2" })
+        logBuffer.log(
+            TAG,
+            VERBOSE,
+            {
+                str1 = action
+                str2 = extraSimState
+                int1 = slotId
+                int2 = subId
+            },
+            { "action $str1 state: $str2 slotId: $int1 subid: $int2" }
+        )
     }
 
     fun logSimUnlocked(subId: Int) {
@@ -311,78 +399,98 @@
     }
 
     fun logStartedListeningForFace(faceRunningState: Int, faceAuthUiEvent: FaceAuthUiEvent) {
-        logBuffer.log(TAG, VERBOSE, {
-            int1 = faceRunningState
-            str1 = faceAuthUiEvent.reason
-            str2 = faceAuthUiEvent.extraInfoToString()
-        }, { "startListeningForFace(): $int1, reason: $str1 $str2" })
+        logBuffer.log(
+            TAG,
+            VERBOSE,
+            {
+                int1 = faceRunningState
+                str1 = faceAuthUiEvent.reason
+                str2 = faceAuthUiEvent.extraInfoToString()
+            },
+            { "startListeningForFace(): $int1, reason: $str1 $str2" }
+        )
     }
 
     fun logStartedListeningForFaceFromWakeUp(faceRunningState: Int, @WakeReason pmWakeReason: Int) {
-        logBuffer.log(TAG, VERBOSE, {
-            int1 = faceRunningState
-            str1 = PowerManager.wakeReasonToString(pmWakeReason)
-        }, { "startListeningForFace(): $int1, reason: wakeUp-$str1" })
+        logBuffer.log(
+            TAG,
+            VERBOSE,
+            {
+                int1 = faceRunningState
+                str1 = PowerManager.wakeReasonToString(pmWakeReason)
+            },
+            { "startListeningForFace(): $int1, reason: wakeUp-$str1" }
+        )
     }
 
     fun logStoppedListeningForFace(faceRunningState: Int, faceAuthReason: String) {
-        logBuffer.log(TAG, VERBOSE, {
-            int1 = faceRunningState
-            str1 = faceAuthReason
-        }, { "stopListeningForFace(): currentFaceRunningState: $int1, reason: $str1" })
+        logBuffer.log(
+            TAG,
+            VERBOSE,
+            {
+                int1 = faceRunningState
+                str1 = faceAuthReason
+            },
+            { "stopListeningForFace(): currentFaceRunningState: $int1, reason: $str1" }
+        )
     }
 
     fun logSubInfo(subInfo: SubscriptionInfo?) {
-        logBuffer.log(TAG, VERBOSE,
-                { str1 = "$subInfo" },
-                { "SubInfo:$str1" })
+        logBuffer.log(TAG, VERBOSE, { str1 = "$subInfo" }, { "SubInfo:$str1" })
     }
 
     fun logTimeFormatChanged(newTimeFormat: String?) {
-        logBuffer.log(TAG, DEBUG,
-                { str1 = newTimeFormat },
-                { "handleTimeFormatUpdate timeFormat=$str1" })
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            { str1 = newTimeFormat },
+            { "handleTimeFormatUpdate timeFormat=$str1" }
+        )
     }
     fun logUdfpsPointerDown(sensorId: Int) {
-        logBuffer.log(TAG, DEBUG,
-                { int1 = sensorId },
-                { "onUdfpsPointerDown, sensorId: $int1" })
+        logBuffer.log(TAG, DEBUG, { int1 = sensorId }, { "onUdfpsPointerDown, sensorId: $int1" })
     }
 
     fun logUdfpsPointerUp(sensorId: Int) {
-        logBuffer.log(TAG, DEBUG,
-                { int1 = sensorId },
-                { "onUdfpsPointerUp, sensorId: $int1" })
+        logBuffer.log(TAG, DEBUG, { int1 = sensorId }, { "onUdfpsPointerUp, sensorId: $int1" })
     }
 
     fun logUnexpectedFaceCancellationSignalState(faceRunningState: Int, unlockPossible: Boolean) {
-        logBuffer.log(TAG, ERROR, {
-                    int1 = faceRunningState
-                    bool1 = unlockPossible
-                }, {
-                    "Cancellation signal is not null, high chance of bug in " +
-                            "face auth lifecycle management. " +
-                            "Face state: $int1, unlockPossible: $bool1"
-                })
+        logBuffer.log(
+            TAG,
+            ERROR,
+            {
+                int1 = faceRunningState
+                bool1 = unlockPossible
+            },
+            {
+                "Cancellation signal is not null, high chance of bug in " +
+                    "face auth lifecycle management. " +
+                    "Face state: $int1, unlockPossible: $bool1"
+            }
+        )
     }
 
     fun logUnexpectedFpCancellationSignalState(
         fingerprintRunningState: Int,
         unlockPossible: Boolean
     ) {
-        logBuffer.log(TAG, ERROR, {
-                    int1 = fingerprintRunningState
-                    bool1 = unlockPossible
-                }, {
-                    "Cancellation signal is not null, high chance of bug in " +
-                            "fp auth lifecycle management. FP state: $int1, unlockPossible: $bool1"
-                })
+        logBuffer.log(
+            TAG,
+            ERROR,
+            {
+                int1 = fingerprintRunningState
+                bool1 = unlockPossible
+            },
+            {
+                "Cancellation signal is not null, high chance of bug in " +
+                    "fp auth lifecycle management. FP state: $int1, unlockPossible: $bool1"
+            }
+        )
     }
 
     fun logUnregisterCallback(callback: KeyguardUpdateMonitorCallback?) {
-        logBuffer.log(TAG, VERBOSE,
-                { str1 = "$callback" },
-                { "*** unregister callback for $str1" })
+        logBuffer.log(TAG, VERBOSE, { str1 = "$callback" }, { "*** unregister callback for $str1" })
     }
 
     fun logUserRequestedUnlock(
@@ -390,75 +498,184 @@
         reason: String?,
         dismissKeyguard: Boolean
     ) {
-        logBuffer.log("ActiveUnlock", DEBUG, {
-                    str1 = requestOrigin?.name
-                    str2 = reason
-                    bool1 = dismissKeyguard
-                }, { "reportUserRequestedUnlock origin=$str1 reason=$str2 dismissKeyguard=$bool1" })
+        logBuffer.log(
+            "ActiveUnlock",
+            DEBUG,
+            {
+                str1 = requestOrigin?.name
+                str2 = reason
+                bool1 = dismissKeyguard
+            },
+            { "reportUserRequestedUnlock origin=$str1 reason=$str2 dismissKeyguard=$bool1" }
+        )
     }
 
     fun logTrustGrantedWithFlags(
-            flags: Int,
-            newlyUnlocked: Boolean,
-            userId: Int,
-            message: String?
+        flags: Int,
+        newlyUnlocked: Boolean,
+        userId: Int,
+        message: String?
     ) {
-        logBuffer.log(TAG, DEBUG, {
-            int1 = flags
-            bool1 = newlyUnlocked
-            int2 = userId
-            str1 = message
-        }, { "trustGrantedWithFlags[user=$int2] newlyUnlocked=$bool1 " +
-                "flags=${TrustGrantFlags(int1)} message=$str1" })
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            {
+                int1 = flags
+                bool1 = newlyUnlocked
+                int2 = userId
+                str1 = message
+            },
+            {
+                "trustGrantedWithFlags[user=$int2] newlyUnlocked=$bool1 " +
+                    "flags=${TrustGrantFlags(int1)} message=$str1"
+            }
+        )
     }
 
-    fun logTrustChanged(
-            wasTrusted: Boolean,
-            isNowTrusted: Boolean,
-            userId: Int
-    ) {
-        logBuffer.log(TAG, DEBUG, {
-            bool1 = wasTrusted
-            bool2 = isNowTrusted
-            int1 = userId
-        }, { "onTrustChanged[user=$int1] wasTrusted=$bool1 isNowTrusted=$bool2" })
+    fun logTrustChanged(wasTrusted: Boolean, isNowTrusted: Boolean, userId: Int) {
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            {
+                bool1 = wasTrusted
+                bool2 = isNowTrusted
+                int1 = userId
+            },
+            { "onTrustChanged[user=$int1] wasTrusted=$bool1 isNowTrusted=$bool2" }
+        )
     }
 
     fun logKeyguardStateUpdate(
-            secure: Boolean,
-            canDismissLockScreen: Boolean,
-            trusted: Boolean,
-            trustManaged: Boolean
-
+        secure: Boolean,
+        canDismissLockScreen: Boolean,
+        trusted: Boolean,
+        trustManaged: Boolean
     ) {
-        logBuffer.log("KeyguardState", DEBUG, {
-            bool1 = secure
-            bool2 = canDismissLockScreen
-            bool3 = trusted
-            bool4 = trustManaged
-        }, { "#update secure=$bool1 canDismissKeyguard=$bool2" +
-                " trusted=$bool3 trustManaged=$bool4" })
+        logBuffer.log(
+            "KeyguardState",
+            DEBUG,
+            {
+                bool1 = secure
+                bool2 = canDismissLockScreen
+                bool3 = trusted
+                bool4 = trustManaged
+            },
+            {
+                "#update secure=$bool1 canDismissKeyguard=$bool2" +
+                    " trusted=$bool3 trustManaged=$bool4"
+            }
+        )
     }
 
     fun logSkipUpdateFaceListeningOnWakeup(@WakeReason pmWakeReason: Int) {
-        logBuffer.log(TAG, VERBOSE, {
-            str1 = PowerManager.wakeReasonToString(pmWakeReason)
-        }, { "Skip updating face listening state on wakeup from $str1"})
+        logBuffer.log(
+            TAG,
+            VERBOSE,
+            { str1 = PowerManager.wakeReasonToString(pmWakeReason) },
+            { "Skip updating face listening state on wakeup from $str1" }
+        )
     }
 
     fun logTaskStackChangedForAssistant(assistantVisible: Boolean) {
-        logBuffer.log(TAG, VERBOSE, {
-            bool1 = assistantVisible
-        }, {
-            "TaskStackChanged for ACTIVITY_TYPE_ASSISTANT, assistant visible: $bool1"
-        })
+        logBuffer.log(
+            TAG,
+            VERBOSE,
+            { bool1 = assistantVisible },
+            { "TaskStackChanged for ACTIVITY_TYPE_ASSISTANT, assistant visible: $bool1" }
+        )
     }
 
     fun logAssistantVisible(assistantVisible: Boolean) {
-        logBuffer.log(TAG, VERBOSE, {
-            bool1 = assistantVisible
-        }, {
-            "Updating mAssistantVisible to new value: $bool1"
-        })
+        logBuffer.log(
+            TAG,
+            VERBOSE,
+            { bool1 = assistantVisible },
+            { "Updating mAssistantVisible to new value: $bool1" }
+        )
+    }
+
+    fun logReportSuccessfulBiometricUnlock(isStrongBiometric: Boolean, userId: Int) {
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            {
+                bool1 = isStrongBiometric
+                int1 = userId
+            },
+            { "reporting successful biometric unlock: isStrongBiometric: $bool1, userId: $int1" }
+        )
+    }
+
+    fun logHandlerHasAuthContinueMsgs(action: Int) {
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            { int1 = action },
+            {
+                "MSG_BIOMETRIC_AUTHENTICATION_CONTINUE already queued up, " +
+                    "ignoring updating FP listening state to $int1"
+            }
+        )
+    }
+
+    fun logFaceEnrolledUpdated(oldValue: Boolean, newValue: Boolean) {
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            {
+                bool1 = oldValue
+                bool2 = newValue
+            },
+            { "Face enrolled state changed: old: $bool1, new: $bool2" }
+        )
+    }
+
+    fun logFpEnrolledUpdated(userId: Int, oldValue: Boolean, newValue: Boolean) {
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            {
+                int1 = userId
+                bool1 = oldValue
+                bool2 = newValue
+            },
+            { "Fp enrolled state changed for userId: $int1 old: $bool1, new: $bool2" }
+        )
+    }
+
+    fun logTrustUsuallyManagedUpdated(
+        userId: Int,
+        oldValue: Boolean,
+        newValue: Boolean,
+        context: String
+    ) {
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            {
+                int1 = userId
+                bool1 = oldValue
+                bool2 = newValue
+                str1 = context
+            },
+            {
+                "trustUsuallyManaged changed for " +
+                    "userId: $int1 " +
+                    "old: $bool1, " +
+                    "new: $bool2 " +
+                    "context: $context"
+            }
+        )
+    }
+
+    fun logHandleBatteryUpdate(isInteresting: Boolean) {
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            {
+                bool1 = isInteresting
+            },
+            { "handleBatteryUpdate: $bool1" }
+        )
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags b/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags
index 9c847be..08236b7 100644
--- a/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags
+++ b/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags
@@ -61,3 +61,8 @@
 ##       4: SYSTEM_REGISTER_USER     System sysui registers user's callbacks
 ##       5: SYSTEM_UNREGISTER_USER   System sysui unregisters user's callbacks (after death)
 36060 sysui_recents_connection (type|1),(user|1)
+
+# ---------------------------
+# KeyguardViewMediator.java
+# ---------------------------
+36080 sysui_keyguard (isOccluded|1),(animate|1)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
index 52312b8..4b5c50f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
@@ -230,29 +230,21 @@
             if (isReverseDefaultRotation) (rotation + 1) % 4 else rotation
 
     @RawRes
-    private fun getSideFpsAnimationForTransition(rotation: Int): Int {
-        when (rotation) {
-            Surface.ROTATION_90 -> if (context.isInRearDisplayMode()) {
-                return R.raw.biometricprompt_rear_portrait_reverse_base
-            } else if (isDeviceFolded) {
-                return R.raw.biometricprompt_folded_base_topleft
-            } else {
-                return R.raw.biometricprompt_portrait_base_topleft
-            }
-            Surface.ROTATION_270 -> if (context.isInRearDisplayMode()) {
-                return R.raw.biometricprompt_rear_portrait_base
-            } else if (isDeviceFolded) {
-                return R.raw.biometricprompt_folded_base_bottomright
-            } else {
-                return R.raw.biometricprompt_portrait_base_bottomright
-            }
-            else -> if (context.isInRearDisplayMode()) {
-                return R.raw.biometricprompt_rear_landscape_base
-            } else if (isDeviceFolded) {
-                return R.raw.biometricprompt_folded_base_default
-            } else {
-                return R.raw.biometricprompt_landscape_base
-            }
+    private fun getSideFpsAnimationForTransition(rotation: Int): Int = when (rotation) {
+        Surface.ROTATION_90 -> if (isDeviceFolded) {
+            R.raw.biometricprompt_folded_base_topleft
+        } else {
+            R.raw.biometricprompt_portrait_base_topleft
+        }
+        Surface.ROTATION_270 -> if (isDeviceFolded) {
+            R.raw.biometricprompt_folded_base_bottomright
+        } else {
+            R.raw.biometricprompt_portrait_base_bottomright
+        }
+        else -> if (isDeviceFolded) {
+            R.raw.biometricprompt_folded_base_default
+        } else {
+            R.raw.biometricprompt_landscape_base
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
index a7b6e6a..13bb6d3 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
@@ -658,7 +658,9 @@
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
         mIconController.onConfigurationChanged(newConfig);
-        updateState(mSavedState.getInt(AuthDialog.KEY_BIOMETRIC_STATE));
+        if (mSavedState != null) {
+            updateState(mSavedState.getInt(AuthDialog.KEY_BIOMETRIC_STATE));
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index d68fcd0..b3cb79e 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -26,6 +26,7 @@
 import androidx.annotation.VisibleForTesting
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.keyguard.KeyguardUpdateMonitorCallback
+import com.android.keyguard.logging.KeyguardLogger
 import com.android.settingslib.Utils
 import com.android.systemui.R
 import com.android.systemui.animation.Interpolators
@@ -74,6 +75,7 @@
     private val udfpsControllerProvider: Provider<UdfpsController>,
     private val statusBarStateController: StatusBarStateController,
     private val featureFlags: FeatureFlags,
+    private val logger: KeyguardLogger,
         rippleView: AuthRippleView?
 ) : ViewController<AuthRippleView>(rippleView), KeyguardStateController.Callback,
     WakefulnessLifecycle.Observer {
@@ -88,11 +90,6 @@
     private var udfpsController: UdfpsController? = null
     private var udfpsRadius: Float = -1f
 
-    override fun onInit() {
-        mView.setAlphaInDuration(sysuiContext.resources.getInteger(
-                R.integer.auth_ripple_alpha_in_duration).toLong())
-    }
-
     @VisibleForTesting
     public override fun onViewAttached() {
         authController.addCallback(authControllerCallback)
@@ -120,8 +117,11 @@
     }
 
     fun showUnlockRipple(biometricSourceType: BiometricSourceType) {
-        if (!keyguardStateController.isShowing ||
-                !keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(biometricSourceType)) {
+        val keyguardNotShowing = !keyguardStateController.isShowing
+        val unlockNotAllowed = !keyguardUpdateMonitor
+                .isUnlockingWithBiometricAllowed(biometricSourceType)
+        if (keyguardNotShowing || unlockNotAllowed) {
+            logger.notShowingUnlockRipple(keyguardNotShowing, unlockNotAllowed)
             return
         }
 
@@ -138,6 +138,7 @@
                                 Math.max(it.y, centralSurfaces.displayHeight.toInt() - it.y)
                         )
                 )
+                logger.showingUnlockRippleAt(it.x, it.y, "FP sensor radius: $udfpsRadius")
                 showUnlockedRipple()
             }
         } else if (biometricSourceType == BiometricSourceType.FACE) {
@@ -155,6 +156,7 @@
                                 Math.max(it.y, centralSurfaces.displayHeight.toInt() - it.y)
                         )
                 )
+                logger.showingUnlockRippleAt(it.x, it.y, "Face unlock ripple")
                 showUnlockedRipple()
             }
         }
@@ -390,6 +392,7 @@
     }
 
     companion object {
-        const val RIPPLE_ANIMATION_DURATION: Long = 1533
+        const val RIPPLE_ANIMATION_DURATION: Long = 800
+        const val TAG = "AuthRippleController"
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
index 4b32759..b007134 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
@@ -31,7 +31,7 @@
 import com.android.systemui.animation.Interpolators
 import com.android.systemui.surfaceeffects.ripple.RippleShader
 
-private const val RIPPLE_SPARKLE_STRENGTH: Float = 0.4f
+private const val RIPPLE_SPARKLE_STRENGTH: Float = 0.3f
 
 /**
  * Handles two ripple effects: dwell ripple and unlocked ripple
@@ -54,12 +54,11 @@
     private var lockScreenColorVal = Color.WHITE
     private val fadeDuration = 83L
     private val retractDuration = 400L
-    private var alphaInDuration: Long = 0
     private val dwellShader = DwellRippleShader()
     private val dwellPaint = Paint()
     private val rippleShader = RippleShader()
     private val ripplePaint = Paint()
-    private var unlockedRippleAnimator: AnimatorSet? = null
+    private var unlockedRippleAnimator: Animator? = null
     private var fadeDwellAnimator: Animator? = null
     private var retractDwellAnimator: Animator? = null
     private var dwellPulseOutAnimator: Animator? = null
@@ -75,8 +74,8 @@
         }
     private var radius: Float = 0f
         set(value) {
-            rippleShader.rippleSize.setMaxSize(value * 2f, value * 2f)
-            field = value
+            field = value * .9f
+            rippleShader.rippleSize.setMaxSize(field * 2f, field * 2f)
         }
     private var origin: Point = Point()
         set(value) {
@@ -85,11 +84,12 @@
         }
 
     init {
-        rippleShader.color = 0xffffffff.toInt() // default color
         rippleShader.rawProgress = 0f
+        rippleShader.pixelDensity = resources.displayMetrics.density
         rippleShader.sparkleStrength = RIPPLE_SPARKLE_STRENGTH
-        setupRippleFadeParams()
+        updateRippleFadeParams()
         ripplePaint.shader = rippleShader
+        setLockScreenColor(0xffffffff.toInt()) // default color
 
         dwellShader.color = 0xffffffff.toInt() // default color
         dwellShader.progress = 0f
@@ -110,10 +110,6 @@
         dwellRadius = sensorRadius * 1.5f
     }
 
-    fun setAlphaInDuration(duration: Long) {
-        alphaInDuration = duration
-    }
-
     /**
      * Animate dwell ripple inwards back to radius 0
      */
@@ -252,7 +248,6 @@
 
                 override fun onAnimationEnd(animation: Animator?) {
                     drawDwell = false
-                    resetRippleAlpha()
                 }
             })
             start()
@@ -266,7 +261,6 @@
         unlockedRippleAnimator?.cancel()
 
         val rippleAnimator = ValueAnimator.ofFloat(0f, 1f).apply {
-            interpolator = Interpolators.LINEAR_OUT_SLOW_IN
             duration = AuthRippleController.RIPPLE_ANIMATION_DURATION
             addUpdateListener { animator ->
                 val now = animator.currentPlayTime
@@ -277,22 +271,7 @@
             }
         }
 
-        val alphaInAnimator = ValueAnimator.ofInt(0, 255).apply {
-            duration = alphaInDuration
-            addUpdateListener { animator ->
-                rippleShader.color = ColorUtils.setAlphaComponent(
-                    rippleShader.color,
-                    animator.animatedValue as Int
-                )
-                invalidate()
-            }
-        }
-
-        unlockedRippleAnimator = AnimatorSet().apply {
-            playTogether(
-                rippleAnimator,
-                alphaInAnimator
-            )
+        unlockedRippleAnimator = rippleAnimator.apply {
             addListener(object : AnimatorListenerAdapter() {
                 override fun onAnimationStart(animation: Animator?) {
                     drawRipple = true
@@ -310,17 +289,12 @@
         unlockedRippleAnimator?.start()
     }
 
-    fun resetRippleAlpha() {
-        rippleShader.color = ColorUtils.setAlphaComponent(
-                rippleShader.color,
-                255
-        )
-    }
-
     fun setLockScreenColor(color: Int) {
         lockScreenColorVal = color
-        rippleShader.color = lockScreenColorVal
-        resetRippleAlpha()
+        rippleShader.color = ColorUtils.setAlphaComponent(
+                lockScreenColorVal,
+                62
+        )
     }
 
     fun updateDwellRippleColor(isDozing: Boolean) {
@@ -339,15 +313,17 @@
         )
     }
 
-    private fun setupRippleFadeParams() {
+    private fun updateRippleFadeParams() {
         with(rippleShader) {
-            baseRingFadeParams.fadeOutStart = RippleShader.DEFAULT_BASE_RING_FADE_OUT_START
-            baseRingFadeParams.fadeOutEnd = RippleShader.DEFAULT_FADE_OUT_END
+            baseRingFadeParams.fadeInStart = 0f
+            baseRingFadeParams.fadeInEnd = .2f
+            baseRingFadeParams.fadeOutStart = .2f
+            baseRingFadeParams.fadeOutEnd = 1f
 
-            centerFillFadeParams.fadeInStart = RippleShader.DEFAULT_FADE_IN_START
-            centerFillFadeParams.fadeInEnd = RippleShader.DEFAULT_CENTER_FILL_FADE_IN_END
-            centerFillFadeParams.fadeOutStart = RippleShader.DEFAULT_CENTER_FILL_FADE_OUT_START
-            centerFillFadeParams.fadeOutEnd = RippleShader.DEFAULT_CENTER_FILL_FADE_OUT_END
+            centerFillFadeParams.fadeInStart = 0f
+            centerFillFadeParams.fadeInEnd = .15f
+            centerFillFadeParams.fadeOutStart = .15f
+            centerFillFadeParams.fadeOutEnd = .56f
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
index f7d87fc..c98a62f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
@@ -64,6 +64,7 @@
 import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor
 import com.android.systemui.recents.OverviewProxyService
 import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.util.traceSection
 import java.io.PrintWriter
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
@@ -172,16 +173,12 @@
                 override fun show(
                     sensorId: Int,
                     @BiometricOverlayConstants.ShowReason reason: Int
-                ) {
-                    if (
-                        reason.isReasonToAutoShow(activityTaskManager) &&
-                            !context.isInRearDisplayMode()
-                    ) {
+                ) =
+                    if (reason.isReasonToAutoShow(activityTaskManager)) {
                         show(SideFpsUiRequestSource.AUTO_SHOW, reason)
                     } else {
                         hide(SideFpsUiRequestSource.AUTO_SHOW)
                     }
-                }
 
                 override fun hide(sensorId: Int) = hide(SideFpsUiRequestSource.AUTO_SHOW)
             }
@@ -198,7 +195,7 @@
             scope.launch {
                 alternateBouncerInteractor.isVisible.collect { isVisible: Boolean ->
                     if (isVisible) {
-                        show(SideFpsUiRequestSource.ALTERNATE_BOUNCER)
+                        show(SideFpsUiRequestSource.ALTERNATE_BOUNCER, REASON_AUTH_KEYGUARD)
                     } else {
                         hide(SideFpsUiRequestSource.ALTERNATE_BOUNCER)
                     }
@@ -215,7 +212,9 @@
         requests.add(request)
         mainExecutor.execute {
             if (overlayView == null) {
-                createOverlayForDisplay(reason)
+                traceSection("SideFpsController#show(request=${request.name}, reason=$reason") {
+                    createOverlayForDisplay(reason)
+                }
             } else {
                 Log.v(TAG, "overlay already shown")
             }
@@ -227,7 +226,7 @@
         requests.remove(request)
         mainExecutor.execute {
             if (requests.isEmpty()) {
-                overlayView = null
+                traceSection("SideFpsController#hide(${request.name}") { overlayView = null }
             }
         }
     }
@@ -437,13 +436,17 @@
     @BiometricOverlayConstants.ShowReason reason: Int
 ) {
     fun update() {
-        val c = context.getColor(R.color.biometric_dialog_accent)
-        val chevronFill = context.getColor(R.color.sfps_chevron_fill)
         val isKeyguard = reason == REASON_AUTH_KEYGUARD
         if (isKeyguard) {
+            val color = context.getColor(R.color.numpad_key_color_secondary) // match bouncer color
+            val chevronFill =
+                com.android.settingslib.Utils.getColorAttrDefaultColor(
+                    context,
+                    android.R.attr.textColorPrimaryInverse
+                )
             for (key in listOf(".blue600", ".blue400")) {
                 addValueCallback(KeyPath(key, "**"), LottieProperty.COLOR_FILTER) {
-                    PorterDuffColorFilter(c, PorterDuff.Mode.SRC_ATOP)
+                    PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP)
                 }
             }
             addValueCallback(KeyPath(".black", "**"), LottieProperty.COLOR_FILTER) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/Utils.kt b/packages/SystemUI/src/com/android/systemui/biometrics/Utils.kt
index 3d56326..d0d6f4c 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/Utils.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/Utils.kt
@@ -36,7 +36,6 @@
 import android.view.accessibility.AccessibilityEvent
 import android.view.accessibility.AccessibilityManager
 import com.android.internal.widget.LockPatternUtils
-import com.android.systemui.R
 import java.lang.annotation.Retention
 import java.lang.annotation.RetentionPolicy
 
@@ -118,7 +117,4 @@
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(CREDENTIAL_PIN, CREDENTIAL_PATTERN, CREDENTIAL_PASSWORD)
     internal annotation class CredentialType
-}
-
-fun Context.isInRearDisplayMode(): Boolean = resources.getIntArray(
-        com.android.internal.R.array.config_rearDisplayDeviceStates).isNotEmpty()
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
index bc0f995..f83885b 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
@@ -38,6 +38,7 @@
 public class FalsingDataProvider {
 
     private static final long MOTION_EVENT_AGE_MS = 1000;
+    private static final long DROP_EVENT_THRESHOLD_MS = 50;
     private static final float THREE_HUNDRED_SIXTY_DEG = (float) (2 * Math.PI);
 
     private final int mWidthPixels;
@@ -60,6 +61,7 @@
     private float mAngle = 0;
     private MotionEvent mFirstRecentMotionEvent;
     private MotionEvent mLastMotionEvent;
+    private boolean mDropLastEvent;
     private boolean mJustUnlockedWithFace;
     private boolean mA11YAction;
 
@@ -95,6 +97,12 @@
             // Ensure prior gesture was completed. May be a no-op.
             completePriorGesture();
         }
+
+        // Drop the gesture closing event if it is close in time to a previous ACTION_MOVE event.
+        // The reason is that the closing ACTION_UP event of  a swipe can be a bit offseted from the
+        // previous ACTION_MOVE event and when it happens, it makes some classifiers fail.
+        mDropLastEvent = shouldDropEvent(motionEvent);
+
         mRecentMotionEvents.addAll(motionEvents);
 
         FalsingClassifier.logVerbose("Size: " + mRecentMotionEvents.size());
@@ -129,6 +137,7 @@
             mPriorMotionEvents = mRecentMotionEvents;
             mRecentMotionEvents = new TimeLimitedMotionEventBuffer(MOTION_EVENT_AGE_MS);
         }
+        mDropLastEvent = false;
         mA11YAction = false;
     }
 
@@ -150,8 +159,18 @@
         return mYdpi;
     }
 
+    /**
+     * Get the {@link MotionEvent}s of the most recent gesture.
+     *
+     * Note that this list may not include the last recorded event.
+     * @see #mDropLastEvent
+     */
     public List<MotionEvent> getRecentMotionEvents() {
-        return mRecentMotionEvents;
+        if (!mDropLastEvent || mRecentMotionEvents.isEmpty()) {
+            return mRecentMotionEvents;
+        } else {
+            return mRecentMotionEvents.subList(0, mRecentMotionEvents.size() - 1);
+        }
     }
 
     public List<MotionEvent> getPriorMotionEvents() {
@@ -169,7 +188,12 @@
         return mFirstRecentMotionEvent;
     }
 
-    /** Get the last recorded {@link MotionEvent}. */
+    /**
+     * Get the last {@link MotionEvent} of the most recent gesture.
+     *
+     * Note that this may be the event prior to the last recorded event.
+     * @see #mDropLastEvent
+     */
     public MotionEvent getLastMotionEvent() {
         recalculateData();
         return mLastMotionEvent;
@@ -236,12 +260,13 @@
             return;
         }
 
-        if (mRecentMotionEvents.isEmpty()) {
+        List<MotionEvent> recentMotionEvents = getRecentMotionEvents();
+        if (recentMotionEvents.isEmpty()) {
             mFirstRecentMotionEvent = null;
             mLastMotionEvent = null;
         } else {
-            mFirstRecentMotionEvent = mRecentMotionEvents.get(0);
-            mLastMotionEvent = mRecentMotionEvents.get(mRecentMotionEvents.size() - 1);
+            mFirstRecentMotionEvent = recentMotionEvents.get(0);
+            mLastMotionEvent = recentMotionEvents.get(recentMotionEvents.size() - 1);
         }
 
         calculateAngleInternal();
@@ -249,6 +274,17 @@
         mDirty = false;
     }
 
+    private boolean shouldDropEvent(MotionEvent event) {
+        if (mRecentMotionEvents.size() < 3) return false;
+
+        MotionEvent lastEvent = mRecentMotionEvents.get(mRecentMotionEvents.size() - 1);
+        boolean isCompletingGesture = event.getActionMasked() == MotionEvent.ACTION_UP
+                && lastEvent.getActionMasked() == MotionEvent.ACTION_MOVE;
+        boolean isRecentEvent =
+                event.getEventTime() - lastEvent.getEventTime() < DROP_EVENT_THRESHOLD_MS;
+        return isCompletingGesture && isRecentEvent;
+    }
+
     private void calculateAngleInternal() {
         if (mRecentMotionEvents.size() < 2) {
             mAngle = Float.MAX_VALUE;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java b/packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java
index e5da389..addd8e2 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java
@@ -183,7 +183,7 @@
 
     @Override
     public List<MotionEvent> subList(int fromIndex, int toIndex) {
-        throw new UnsupportedOperationException();
+        return mMotionEvents.subList(fromIndex, toIndex);
     }
 
     class Iter implements ListIterator<MotionEvent> {
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
index c214f53..e049ae0 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
@@ -263,10 +263,11 @@
     @Override // ClipboardListener.ClipboardOverlay
     public void setClipData(ClipData data, String source) {
         ClipboardModel model = ClipboardModel.fromClipData(mContext, mClipboardUtils, data, source);
-        if (mExitAnimator != null && mExitAnimator.isRunning()) {
+        boolean wasExiting = (mExitAnimator != null && mExitAnimator.isRunning());
+        if (wasExiting) {
             mExitAnimator.cancel();
         }
-        boolean shouldAnimate = !model.dataMatches(mClipboardModel);
+        boolean shouldAnimate = !model.dataMatches(mClipboardModel) || wasExiting;
         mClipboardModel = model;
         mClipboardLogger.setClipSource(mClipboardModel.getSource());
         if (shouldAnimate) {
@@ -313,15 +314,19 @@
                 mOnPreviewTapped = this::editText;
                 break;
             case IMAGE:
-                if (model.isSensitive() || model.loadThumbnail(mContext) != null) {
-                    mView.showImagePreview(
-                            model.isSensitive() ? null : model.loadThumbnail(mContext));
-                    mView.setEditAccessibilityAction(true);
-                    mOnPreviewTapped = () -> editImage(model.getUri());
-                } else {
-                    // image loading failed
-                    mView.showDefaultTextPreview();
-                }
+                mBgExecutor.execute(() -> {
+                    if (model.isSensitive() || model.loadThumbnail(mContext) != null) {
+                        mView.post(() -> {
+                            mView.showImagePreview(
+                                    model.isSensitive() ? null : model.loadThumbnail(mContext));
+                            mView.setEditAccessibilityAction(true);
+                        });
+                        mOnPreviewTapped = () -> editImage(model.getUri());
+                    } else {
+                        // image loading failed
+                        mView.post(mView::showDefaultTextPreview);
+                    }
+                });
                 break;
             case URI:
             case OTHER:
@@ -346,9 +351,20 @@
     }
 
     private void animateFromMinimized() {
-        mIsMinimized = false;
-        setExpandedView();
-        animateIn();
+        if (mEnterAnimator != null && mEnterAnimator.isRunning()) {
+            mEnterAnimator.cancel();
+        }
+        mEnterAnimator = mView.getMinimizedFadeoutAnimation();
+        mEnterAnimator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                super.onAnimationEnd(animation);
+                mIsMinimized = false;
+                setExpandedView();
+                animateIn();
+            }
+        });
+        mEnterAnimator.start();
     }
 
     private String getAccessibilityAnnouncement(ClipboardModel.Type type) {
@@ -363,15 +379,15 @@
 
     private void classifyText(ClipboardModel model) {
         mBgExecutor.execute(() -> {
-            Optional<RemoteAction> remoteAction = mClipboardUtils.getAction(
-                            model.getText(), model.getTextLinks(), model.getSource());
+            Optional<RemoteAction> remoteAction =
+                    mClipboardUtils.getAction(model.getTextLinks(), model.getSource());
             if (model.equals(mClipboardModel)) {
                 remoteAction.ifPresent(action -> {
                     mClipboardLogger.logUnguarded(CLIPBOARD_OVERLAY_ACTION_SHOWN);
-                    mView.setActionChip(action, () -> {
+                    mView.post(() -> mView.setActionChip(action, () -> {
                         mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_ACTION_TAPPED);
                         animateOut();
-                    });
+                    }));
                 });
             }
         });
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtils.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtils.java
index a85f8b9..25caaea 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtils.java
@@ -39,6 +39,9 @@
 
 class ClipboardOverlayUtils {
 
+    // minimum proportion of entire text an entity must take up, to be considered for smart actions
+    private static final float MINIMUM_ENTITY_PROPORTION = .8f;
+
     private final TextClassifier mTextClassifier;
 
     @Inject
@@ -65,19 +68,23 @@
         return false;
     }
 
-    public Optional<RemoteAction> getAction(CharSequence text, TextLinks textLinks, String source) {
-        return getActions(text, textLinks).stream().filter(remoteAction -> {
+    public Optional<RemoteAction> getAction(TextLinks textLinks, String source) {
+        return getActions(textLinks).stream().filter(remoteAction -> {
             ComponentName component = remoteAction.getActionIntent().getIntent().getComponent();
             return component != null && !TextUtils.equals(source, component.getPackageName());
         }).findFirst();
     }
 
-    private ArrayList<RemoteAction> getActions(CharSequence text, TextLinks textLinks) {
+    private ArrayList<RemoteAction> getActions(TextLinks textLinks) {
         ArrayList<RemoteAction> actions = new ArrayList<>();
         for (TextLinks.TextLink link : textLinks.getLinks()) {
-            TextClassification classification = mTextClassifier.classifyText(
-                    text, link.getStart(), link.getEnd(), null);
-            actions.addAll(classification.getActions());
+            // skip classification for incidental entities
+            if (link.getEnd() - link.getStart()
+                    >= textLinks.getText().length() * MINIMUM_ENTITY_PROPORTION) {
+                TextClassification classification = mTextClassifier.classifyText(
+                        textLinks.getText(), link.getStart(), link.getEnd(), null);
+                actions.addAll(classification.getActions());
+            }
         }
         return actions;
     }
@@ -92,9 +99,13 @@
     private ArrayList<RemoteAction> getActions(ClipData.Item item) {
         ArrayList<RemoteAction> actions = new ArrayList<>();
         for (TextLinks.TextLink link : item.getTextLinks().getLinks()) {
-            TextClassification classification = mTextClassifier.classifyText(
-                    item.getText(), link.getStart(), link.getEnd(), null);
-            actions.addAll(classification.getActions());
+            // skip classification for incidental entities
+            if (link.getEnd() - link.getStart()
+                    >= item.getText().length() * MINIMUM_ENTITY_PROPORTION) {
+                TextClassification classification = mTextClassifier.classifyText(
+                        item.getText(), link.getStart(), link.getEnd(), null);
+                actions.addAll(classification.getActions());
+            }
         }
         return actions;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java
index f372bb4..28c57d3 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java
@@ -21,6 +21,7 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
 import android.annotation.Nullable;
@@ -286,6 +287,20 @@
         mActionChips.clear();
     }
 
+    Animator getMinimizedFadeoutAnimation() {
+        ObjectAnimator anim = ObjectAnimator.ofFloat(mMinimizedPreview, "alpha", 1, 0);
+        anim.setDuration(66);
+        anim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                super.onAnimationEnd(animation);
+                mMinimizedPreview.setVisibility(View.GONE);
+                mMinimizedPreview.setAlpha(1);
+            }
+        });
+        return anim;
+    }
+
     Animator getEnterAnimation() {
         if (mAccessibilityManager.isEnabled()) {
             mDismissButton.setVisibility(View.VISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/common/shared/model/TintedIcon.kt b/packages/SystemUI/src/com/android/systemui/common/shared/model/TintedIcon.kt
index 5dabbbb..6a6c3eb 100644
--- a/packages/SystemUI/src/com/android/systemui/common/shared/model/TintedIcon.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/shared/model/TintedIcon.kt
@@ -16,10 +16,10 @@
 
 package com.android.systemui.common.shared.model
 
-import androidx.annotation.AttrRes
+import androidx.annotation.ColorRes
 
 /** Models an icon with a specific tint. */
 data class TintedIcon(
     val icon: Icon,
-    @AttrRes val tintAttr: Int?,
+    @ColorRes val tint: Int?,
 )
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/binder/TintedIconViewBinder.kt b/packages/SystemUI/src/com/android/systemui/common/ui/binder/TintedIconViewBinder.kt
index dea8cfd..bcc5932 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/binder/TintedIconViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/binder/TintedIconViewBinder.kt
@@ -17,15 +17,14 @@
 package com.android.systemui.common.ui.binder
 
 import android.widget.ImageView
-import com.android.settingslib.Utils
 import com.android.systemui.common.shared.model.TintedIcon
 
 object TintedIconViewBinder {
     /**
      * Binds the given tinted icon to the view.
      *
-     * [TintedIcon.tintAttr] will always be applied, meaning that if it is null, then the tint
-     * *will* be reset to null.
+     * [TintedIcon.tint] will always be applied, meaning that if it is null, then the tint *will* be
+     * reset to null.
      */
     fun bind(
         tintedIcon: TintedIcon,
@@ -33,8 +32,8 @@
     ) {
         IconViewBinder.bind(tintedIcon.icon, view)
         view.imageTintList =
-            if (tintedIcon.tintAttr != null) {
-                Utils.getColorAttr(view.context, tintedIcon.tintAttr)
+            if (tintedIcon.tint != null) {
+                view.resources.getColorStateList(tintedIcon.tint, view.context.theme)
             } else {
                 null
             }
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
index 3555d0a..2d37c29 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
@@ -173,12 +173,6 @@
     fun removeFavorites(componentName: ComponentName): Boolean
 
     /**
-     * Checks if the favorites can be removed. You can't remove components from the preferred list.
-     * @param componentName the name of the service that provides the [Control]
-     */
-    fun canRemoveFavorites(componentName: ComponentName): Boolean
-
-    /**
      * Replaces the favorites for the given structure.
      *
      * Calling this method will eliminate the previous selection of favorites and replace it with a
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
index 8547903..e8c97bf 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
@@ -37,6 +37,7 @@
 import com.android.systemui.controls.ControlsServiceInfo
 import com.android.systemui.controls.management.ControlsListingController
 import com.android.systemui.controls.panels.AuthorizedPanelsRepository
+import com.android.systemui.controls.panels.SelectedComponentRepository
 import com.android.systemui.controls.ui.ControlsUiController
 import com.android.systemui.controls.ui.SelectedItem
 import com.android.systemui.dagger.SysUISingleton
@@ -55,16 +56,17 @@
 
 @SysUISingleton
 class ControlsControllerImpl @Inject constructor (
-    private val context: Context,
-    @Background private val executor: DelayableExecutor,
-    private val uiController: ControlsUiController,
-    private val bindingController: ControlsBindingController,
-    private val listingController: ControlsListingController,
-    private val userFileManager: UserFileManager,
-    private val userTracker: UserTracker,
-    private val authorizedPanelsRepository: AuthorizedPanelsRepository,
-    optionalWrapper: Optional<ControlsFavoritePersistenceWrapper>,
-    dumpManager: DumpManager,
+        private val context: Context,
+        @Background private val executor: DelayableExecutor,
+        private val uiController: ControlsUiController,
+        private val selectedComponentRepository: SelectedComponentRepository,
+        private val bindingController: ControlsBindingController,
+        private val listingController: ControlsListingController,
+        private val userFileManager: UserFileManager,
+        private val userTracker: UserTracker,
+        private val authorizedPanelsRepository: AuthorizedPanelsRepository,
+        optionalWrapper: Optional<ControlsFavoritePersistenceWrapper>,
+        dumpManager: DumpManager,
 ) : Dumpable, ControlsController {
 
     companion object {
@@ -497,17 +499,14 @@
         }
     }
 
-    override fun canRemoveFavorites(componentName: ComponentName): Boolean =
-            !authorizedPanelsRepository.getPreferredPackages().contains(componentName.packageName)
-
     override fun removeFavorites(componentName: ComponentName): Boolean {
         if (!confirmAvailability()) return false
-        if (!canRemoveFavorites(componentName)) return false
 
         executor.execute {
-            Favorites.removeStructures(componentName)
+            if (Favorites.removeStructures(componentName)) {
+                persistenceWrapper.storeFavorites(Favorites.getAllStructures())
+            }
             authorizedPanelsRepository.removeAuthorizedPanels(setOf(componentName.packageName))
-            persistenceWrapper.storeFavorites(Favorites.getAllStructures())
         }
         return true
     }
@@ -574,7 +573,9 @@
     }
 
     override fun setPreferredSelection(selectedItem: SelectedItem) {
-        uiController.updatePreferences(selectedItem)
+        selectedComponentRepository.setSelectedComponent(
+                SelectedComponentRepository.SelectedComponent(selectedItem)
+        )
     }
 
     override fun dump(pw: PrintWriter, args: Array<out String>) {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt
index d949d11..2af49aa 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt
@@ -36,6 +36,8 @@
 import com.android.systemui.controls.management.ControlsRequestDialog
 import com.android.systemui.controls.panels.AuthorizedPanelsRepository
 import com.android.systemui.controls.panels.AuthorizedPanelsRepositoryImpl
+import com.android.systemui.controls.panels.SelectedComponentRepository
+import com.android.systemui.controls.panels.SelectedComponentRepositoryImpl
 import com.android.systemui.controls.settings.ControlsSettingsDialogManager
 import com.android.systemui.controls.settings.ControlsSettingsDialogManagerImpl
 import com.android.systemui.controls.ui.ControlActionCoordinator
@@ -114,6 +116,11 @@
         repository: AuthorizedPanelsRepositoryImpl
     ): AuthorizedPanelsRepository
 
+    @Binds
+    abstract fun providePreferredPanelRepository(
+        repository: SelectedComponentRepositoryImpl
+    ): SelectedComponentRepository
+
     @BindsOptionalOf
     abstract fun optionalPersistenceWrapper(): ControlsFavoritePersistenceWrapper
 
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingController.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingController.kt
index b9f1666..cf5ccc5 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingController.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.controls.management
 
+import android.annotation.WorkerThread
 import android.content.ComponentName
 import com.android.systemui.controls.ControlsServiceInfo
 import com.android.systemui.util.UserAwareController
@@ -33,6 +34,9 @@
      */
     fun getCurrentServices(): List<ControlsServiceInfo>
 
+    @WorkerThread
+    fun forceReload()
+
     /**
      * Get the app label for a given component.
      *
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
index c81a2c7..8ba060e 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
@@ -16,8 +16,11 @@
 
 package com.android.systemui.controls.management
 
+import android.annotation.WorkerThread
 import android.content.ComponentName
 import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
 import android.os.UserHandle
 import android.service.controls.ControlsProviderService
 import android.util.Log
@@ -65,7 +68,7 @@
     private val serviceListingBuilder: (Context) -> ServiceListing,
     private val userTracker: UserTracker,
     dumpManager: DumpManager,
-    featureFlags: FeatureFlags
+    private val featureFlags: FeatureFlags
 ) : ControlsListingController, Dumpable {
 
     @Inject
@@ -97,18 +100,7 @@
         // After here, `list` is not captured, so we don't risk modifying it outside of the callback
         backgroundExecutor.execute {
             if (userChangeInProgress.get() > 0) return@execute
-            if (featureFlags.isEnabled(Flags.USE_APP_PANELS)) {
-                val allowAllApps = featureFlags.isEnabled(Flags.APP_PANELS_ALL_APPS_ALLOWED)
-                newServices.forEach {
-                    it.resolvePanelActivity(allowAllApps) }
-            }
-
-            if (newServices != availableServices) {
-                availableServices = newServices
-                callbacks.forEach {
-                    it.onServicesUpdated(getCurrentServices())
-                }
-            }
+            updateServices(newServices)
         }
     }
 
@@ -120,6 +112,21 @@
         serviceListing.reload()
     }
 
+    private fun updateServices(newServices: List<ControlsServiceInfo>) {
+        if (featureFlags.isEnabled(Flags.USE_APP_PANELS)) {
+            val allowAllApps = featureFlags.isEnabled(Flags.APP_PANELS_ALL_APPS_ALLOWED)
+            newServices.forEach {
+                it.resolvePanelActivity(allowAllApps) }
+        }
+
+        if (newServices != availableServices) {
+            availableServices = newServices
+            callbacks.forEach {
+                it.onServicesUpdated(getCurrentServices())
+            }
+        }
+    }
+
     override fun changeUser(newUser: UserHandle) {
         userChangeInProgress.incrementAndGet()
         serviceListing.setListening(false)
@@ -178,6 +185,23 @@
     override fun getCurrentServices(): List<ControlsServiceInfo> =
             availableServices.map(ControlsServiceInfo::copy)
 
+    @WorkerThread
+    override fun forceReload() {
+        val packageManager = context.packageManager
+        val intent = Intent(ControlsProviderService.SERVICE_CONTROLS)
+        val user = userTracker.userHandle
+        val flags = PackageManager.GET_SERVICES or
+                PackageManager.GET_META_DATA or
+                PackageManager.MATCH_DIRECT_BOOT_UNAWARE or
+                PackageManager.MATCH_DIRECT_BOOT_AWARE
+        val services = packageManager.queryIntentServicesAsUser(
+                intent,
+                PackageManager.ResolveInfoFlags.of(flags.toLong()),
+                user
+        ).map { ControlsServiceInfo(userTracker.userContext, it.serviceInfo) }
+        updateServices(services)
+    }
+
     /**
      * Get the localized label for the component.
      *
diff --git a/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImpl.kt
index e51e832..5c2402b 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImpl.kt
@@ -20,6 +20,8 @@
 import android.content.Context
 import android.content.SharedPreferences
 import com.android.systemui.R
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
 import com.android.systemui.settings.UserFileManager
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl
@@ -30,7 +32,8 @@
 constructor(
     private val context: Context,
     private val userFileManager: UserFileManager,
-    private val userTracker: UserTracker
+    private val userTracker: UserTracker,
+    private val featureFlags: FeatureFlags,
 ) : AuthorizedPanelsRepository {
 
     override fun getAuthorizedPanels(): Set<String> {
@@ -71,8 +74,18 @@
                 userTracker.userId,
             )
 
-        // If we've never run this (i.e., the key doesn't exist), add the default packages
-        if (sharedPref.getStringSet(KEY, null) == null) {
+        // We should add default packages in two cases:
+        // 1) We've never run this
+        // 2) APP_PANELS_REMOVE_APPS_ALLOWED got disabled after user removed all apps
+        val needToSetup =
+            if (featureFlags.isEnabled(Flags.APP_PANELS_REMOVE_APPS_ALLOWED)) {
+                sharedPref.getStringSet(KEY, null) == null
+            } else {
+                // There might be an empty set that need to be overridden after the feature has been
+                // turned off after being turned on
+                sharedPref.getStringSet(KEY, null).isNullOrEmpty()
+            }
+        if (needToSetup) {
             sharedPref.edit().putStringSet(KEY, getPreferredPackages()).apply()
         }
         return sharedPref
diff --git a/packages/SystemUI/src/com/android/systemui/controls/panels/SelectedComponentRepository.kt b/packages/SystemUI/src/com/android/systemui/controls/panels/SelectedComponentRepository.kt
new file mode 100644
index 0000000..5bb6eec
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/panels/SelectedComponentRepository.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.controls.panels
+
+import android.content.ComponentName
+import com.android.systemui.controls.ui.ControlsUiController
+import com.android.systemui.controls.ui.SelectedItem
+import com.android.systemui.flags.Flags
+
+/** Stores user-selected preferred component. */
+interface SelectedComponentRepository {
+
+    /**
+     * Returns currently set preferred component, or null when nothing is set. Consider using
+     * [ControlsUiController.getPreferredSelectedItem] to get domain specific data
+     */
+    fun getSelectedComponent(): SelectedComponent?
+
+    /** Sets preferred component. Use [getSelectedComponent] to get current one */
+    fun setSelectedComponent(selectedComponent: SelectedComponent)
+
+    /** Clears current preferred component. [getSelectedComponent] will return null afterwards */
+    fun removeSelectedComponent()
+
+    /**
+     * Return true when default preferred component should be set up and false the otherwise. This
+     * is always true when [Flags.APP_PANELS_REMOVE_APPS_ALLOWED] is disabled
+     */
+    fun shouldAddDefaultComponent(): Boolean
+
+    /**
+     * Sets if default component should be added. This is ignored when
+     * [Flags.APP_PANELS_REMOVE_APPS_ALLOWED] is disabled
+     */
+    fun setShouldAddDefaultComponent(shouldAdd: Boolean)
+
+    data class SelectedComponent(
+        val name: String,
+        val componentName: ComponentName?,
+        val isPanel: Boolean,
+    ) {
+        constructor(
+            selectedItem: SelectedItem
+        ) : this(
+            name = selectedItem.name.toString(),
+            componentName = selectedItem.componentName,
+            isPanel = selectedItem is SelectedItem.PanelItem,
+        )
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/panels/SelectedComponentRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/panels/SelectedComponentRepositoryImpl.kt
new file mode 100644
index 0000000..0fb5b66
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/panels/SelectedComponentRepositoryImpl.kt
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.controls.panels
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.SharedPreferences
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.settings.UserFileManager
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl
+import javax.inject.Inject
+
+@SysUISingleton
+class SelectedComponentRepositoryImpl
+@Inject
+constructor(
+    private val userFileManager: UserFileManager,
+    private val userTracker: UserTracker,
+    private val featureFlags: FeatureFlags,
+) : SelectedComponentRepository {
+
+    private companion object {
+        const val PREF_COMPONENT = "controls_component"
+        const val PREF_STRUCTURE_OR_APP_NAME = "controls_structure"
+        const val PREF_IS_PANEL = "controls_is_panel"
+        const val SHOULD_ADD_DEFAULT_PANEL = "should_add_default_panel"
+    }
+
+    private val sharedPreferences: SharedPreferences
+        get() =
+            userFileManager.getSharedPreferences(
+                fileName = DeviceControlsControllerImpl.PREFS_CONTROLS_FILE,
+                mode = Context.MODE_PRIVATE,
+                userId = userTracker.userId
+            )
+
+    override fun getSelectedComponent(): SelectedComponentRepository.SelectedComponent? {
+        with(sharedPreferences) {
+            val componentString = getString(PREF_COMPONENT, null) ?: return null
+            return SelectedComponentRepository.SelectedComponent(
+                name = getString(PREF_STRUCTURE_OR_APP_NAME, "")!!,
+                componentName = ComponentName.unflattenFromString(componentString),
+                isPanel = getBoolean(PREF_IS_PANEL, false)
+            )
+        }
+    }
+
+    override fun setSelectedComponent(
+        selectedComponent: SelectedComponentRepository.SelectedComponent
+    ) {
+        sharedPreferences
+            .edit()
+            .putString(PREF_COMPONENT, selectedComponent.componentName?.flattenToString())
+            .putString(PREF_STRUCTURE_OR_APP_NAME, selectedComponent.name)
+            .putBoolean(PREF_IS_PANEL, selectedComponent.isPanel)
+            .apply()
+    }
+
+    override fun removeSelectedComponent() {
+        sharedPreferences
+            .edit()
+            .remove(PREF_COMPONENT)
+            .remove(PREF_STRUCTURE_OR_APP_NAME)
+            .remove(PREF_IS_PANEL)
+            .apply()
+    }
+
+    override fun shouldAddDefaultComponent(): Boolean =
+        if (featureFlags.isEnabled(Flags.APP_PANELS_REMOVE_APPS_ALLOWED)) {
+            sharedPreferences.getBoolean(SHOULD_ADD_DEFAULT_PANEL, true)
+        } else {
+            true
+        }
+
+    override fun setShouldAddDefaultComponent(shouldAdd: Boolean) {
+        sharedPreferences.edit().putBoolean(SHOULD_ADD_DEFAULT_PANEL, shouldAdd).apply()
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/settings/ControlsSettingsDialogManager.kt b/packages/SystemUI/src/com/android/systemui/controls/settings/ControlsSettingsDialogManager.kt
index 06d4a08..ce0f2e9 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/settings/ControlsSettingsDialogManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/settings/ControlsSettingsDialogManager.kt
@@ -155,17 +155,18 @@
         d.show()
     }
 
-    private fun turnOnSettingSecurely(settings: List<String>) {
+    private fun turnOnSettingSecurely(settings: List<String>, onComplete: () -> Unit) {
         val action =
             ActivityStarter.OnDismissAction {
                 settings.forEach { setting ->
                     secureSettings.putIntForUser(setting, 1, userTracker.userId)
                 }
+                onComplete()
                 true
             }
         activityStarter.dismissKeyguardThenExecute(
             action,
-            /* cancel */ null,
+            /* cancel */ onComplete,
             /* afterKeyguardGone */ true
         )
     }
@@ -186,7 +187,11 @@
                 if (!showDeviceControlsInLockscreen) {
                     settings.add(Settings.Secure.LOCKSCREEN_SHOW_CONTROLS)
                 }
-                turnOnSettingSecurely(settings)
+                // If we are toggling the flag, we want to call onComplete after the keyguard is
+                // dismissed (and the setting is turned on), to pass the correct value.
+                turnOnSettingSecurely(settings, onComplete)
+            } else {
+                onComplete()
             }
             if (attempts != MAX_NUMBER_ATTEMPTS_CONTROLS_DIALOG) {
                 prefs
@@ -194,7 +199,6 @@
                     .putInt(PREFS_SETTINGS_DIALOG_ATTEMPTS, MAX_NUMBER_ATTEMPTS_CONTROLS_DIALOG)
                     .apply()
             }
-            onComplete()
         }
 
         override fun onCancel(dialog: DialogInterface?) {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/start/ControlsStartable.kt b/packages/SystemUI/src/com/android/systemui/controls/start/ControlsStartable.kt
index 9d99253..461cacc 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/start/ControlsStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/start/ControlsStartable.kt
@@ -18,17 +18,17 @@
 package com.android.systemui.controls.start
 
 import android.content.Context
-import android.content.res.Resources
 import android.os.UserHandle
+import androidx.annotation.WorkerThread
 import com.android.systemui.CoreStartable
-import com.android.systemui.R
 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.controls.panels.AuthorizedPanelsRepository
+import com.android.systemui.controls.panels.SelectedComponentRepository
 import com.android.systemui.controls.ui.SelectedItem
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.settings.UserTracker
 import java.util.concurrent.Executor
 import javax.inject.Inject
@@ -37,7 +37,7 @@
  * Started with SystemUI to perform early operations for device controls subsystem (only if enabled)
  *
  * In particular, it will perform the following:
- * * If there is no preferred selection for provider and at least one of the preferred packages 
+ * * If there is no preferred selection for provider and at least one of the preferred packages
  * provides a panel, it will select the first one that does.
  * * If the preferred selection provides a panel, it will bind to that service (to reduce latency on
  * displaying the panel).
@@ -48,10 +48,11 @@
 class ControlsStartable
 @Inject
 constructor(
-    @Main private val resources: Resources,
-    @Background private val executor: Executor,
-    private val controlsComponent: ControlsComponent,
-    private val userTracker: UserTracker
+        @Background private val executor: Executor,
+        private val controlsComponent: ControlsComponent,
+        private val userTracker: UserTracker,
+        private val authorizedPanelsRepository: AuthorizedPanelsRepository,
+        private val selectedComponentRepository: SelectedComponentRepository,
 ) : CoreStartable {
 
     // These two controllers can only be accessed after `start` method once we've checked if the
@@ -75,22 +76,27 @@
             // Controls is disabled, we don't need this anymore
             return
         }
-        startForUser()
+        executor.execute(this::startForUser)
         userTracker.addCallback(userTrackerCallback, executor)
     }
 
+    @WorkerThread
     private fun startForUser() {
+        controlsListingController.forceReload()
         selectDefaultPanelIfNecessary()
         bindToPanel()
     }
 
     private fun selectDefaultPanelIfNecessary() {
+        if (!selectedComponentRepository.shouldAddDefaultComponent()) {
+            return
+        }
         val currentSelection = controlsController.getPreferredSelection()
         if (currentSelection == SelectedItem.EMPTY_SELECTION) {
             val availableServices = controlsListingController.getCurrentServices()
             val panels = availableServices.filter { it.panelActivity != null }
-            resources
-                .getStringArray(R.array.config_controlsPreferredPackages)
+            authorizedPanelsRepository
+                .getPreferredPackages()
                 // Looking for the first element in the string array such that there is one package
                 // that has a panel. It will return null if there are no packages in the array,
                 // or if no packages in the array have a panel associated with it.
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt
index bf0a692..c964b96 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt
@@ -20,6 +20,8 @@
 import android.content.Context
 import android.content.Intent
 import android.content.IntentFilter
+import android.content.pm.ActivityInfo
+import android.content.res.Configuration
 import android.os.Bundle
 import android.os.RemoteException
 import android.service.dreams.IDreamManager
@@ -45,7 +47,8 @@
  * destroyed on SCREEN_OFF events, due to issues with occluded activities over lockscreen as well as
  * user expectations for the activity to not continue running.
  */
-class ControlsActivity @Inject constructor(
+// Open for testing
+open class ControlsActivity @Inject constructor(
     private val uiController: ControlsUiController,
     private val broadcastDispatcher: BroadcastDispatcher,
     private val dreamManager: IDreamManager,
@@ -57,9 +60,11 @@
     private lateinit var parent: ViewGroup
     private lateinit var broadcastReceiver: BroadcastReceiver
     private var mExitToDream: Boolean = false
+    private lateinit var lastConfiguration: Configuration
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
+        lastConfiguration = resources.configuration
         if (featureFlags.isEnabled(Flags.USE_APP_PANELS)) {
             window.addPrivateFlags(WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY)
         }
@@ -92,6 +97,17 @@
         initBroadcastReceiver()
     }
 
+    override fun onConfigurationChanged(newConfig: Configuration) {
+        super.onConfigurationChanged(newConfig)
+        val interestingFlags = ActivityInfo.CONFIG_ORIENTATION or
+                ActivityInfo.CONFIG_SCREEN_SIZE or
+                ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE
+        if (lastConfiguration.diff(newConfig) and interestingFlags != 0 ) {
+            uiController.onSizeChange()
+        }
+        lastConfiguration = newConfig
+    }
+
     override fun onStart() {
         super.onStart()
 
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt
index 58673bb..0cc4683 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt
@@ -65,7 +65,7 @@
      */
     fun getPreferredSelectedItem(structures: List<StructureInfo>): SelectedItem
 
-    fun updatePreferences(selectedItem: SelectedItem)
+    fun onSizeChange()
 }
 
 sealed class SelectedItem {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index c61dad6..5543916 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -64,6 +64,7 @@
 import com.android.systemui.controls.management.ControlsListingController
 import com.android.systemui.controls.management.ControlsProviderSelectorActivity
 import com.android.systemui.controls.panels.AuthorizedPanelsRepository
+import com.android.systemui.controls.panels.SelectedComponentRepository
 import com.android.systemui.controls.settings.ControlsSettingsRepository
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
@@ -73,9 +74,7 @@
 import com.android.systemui.flags.Flags
 import com.android.systemui.globalactions.GlobalActionsPopupMenu
 import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.settings.UserFileManager
 import com.android.systemui.settings.UserTracker
-import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.asIndenting
 import com.android.systemui.util.concurrency.DelayableExecutor
@@ -84,7 +83,7 @@
 import dagger.Lazy
 import java.io.PrintWriter
 import java.text.Collator
-import java.util.*
+import java.util.Optional
 import java.util.function.Consumer
 import javax.inject.Inject
 
@@ -98,25 +97,22 @@
         @Main val uiExecutor: DelayableExecutor,
         @Background val bgExecutor: DelayableExecutor,
         val controlsListingController: Lazy<ControlsListingController>,
-        val controlActionCoordinator: ControlActionCoordinator,
+        private val controlActionCoordinator: ControlActionCoordinator,
         private val activityStarter: ActivityStarter,
         private val iconCache: CustomIconCache,
         private val controlsMetricsLogger: ControlsMetricsLogger,
         private val keyguardStateController: KeyguardStateController,
-        private val userFileManager: UserFileManager,
         private val userTracker: UserTracker,
         private val taskViewFactory: Optional<TaskViewFactory>,
         private val controlsSettingsRepository: ControlsSettingsRepository,
         private val authorizedPanelsRepository: AuthorizedPanelsRepository,
+        private val selectedComponentRepository: SelectedComponentRepository,
         private val featureFlags: FeatureFlags,
         private val dialogsFactory: ControlsDialogsFactory,
         dumpManager: DumpManager
 ) : ControlsUiController, Dumpable {
 
     companion object {
-        private const val PREF_COMPONENT = "controls_component"
-        private const val PREF_STRUCTURE_OR_APP_NAME = "controls_structure"
-        private const val PREF_IS_PANEL = "controls_is_panel"
 
         private const val FADE_IN_MILLIS = 200L
 
@@ -128,6 +124,7 @@
     }
 
     private var selectedItem: SelectedItem = SelectedItem.EMPTY_SELECTION
+    private var selectionItem: SelectionItem? = null
     private lateinit var allStructures: List<StructureInfo>
     private val controlsById = mutableMapOf<ControlKey, ControlWithState>()
     private val controlViewsById = mutableMapOf<ControlKey, ControlViewHolder>()
@@ -138,12 +135,6 @@
     private val popupThemedContext = ContextThemeWrapper(context, R.style.Control_ListPopupWindow)
     private var retainCache = false
     private var lastSelections = emptyList<SelectionItem>()
-    private val sharedPreferences
-        get() = userFileManager.getSharedPreferences(
-            fileName = DeviceControlsControllerImpl.PREFS_CONTROLS_FILE,
-            mode = 0,
-            userId = userTracker.userId
-        )
 
     private var taskViewController: PanelTaskViewController? = null
 
@@ -240,6 +231,7 @@
         this.overflowMenuAdapter = null
         hidden = false
         retainCache = false
+        selectionItem = null
 
         controlActionCoordinator.activityContext = activityContext
 
@@ -282,7 +274,7 @@
         }
     }
 
-    private fun reload(parent: ViewGroup) {
+    private fun reload(parent: ViewGroup, dismissTaskView: Boolean = true) {
         if (hidden) return
 
         controlsListingController.get().removeCallback(listingCallback)
@@ -341,20 +333,18 @@
             if (!controlsController.get().removeFavorites(componentName)) {
                 return@createRemoveAppDialog
             }
-            if (
-                    sharedPreferences.getString(PREF_COMPONENT, "") ==
-                    componentName.flattenToString()
-            ) {
-                sharedPreferences
-                        .edit()
-                        .remove(PREF_COMPONENT)
-                        .remove(PREF_STRUCTURE_OR_APP_NAME)
-                        .remove(PREF_IS_PANEL)
-                        .commit()
+
+            if (selectedComponentRepository.getSelectedComponent()?.componentName ==
+                    componentName) {
+                selectedComponentRepository.removeSelectedComponent()
             }
 
-            allStructures = controlsController.get().getFavorites()
-            selectedItem = getPreferredSelectedItem(allStructures)
+            val selectedItem = getPreferredSelectedItem(controlsController.get().getFavorites())
+            if (selectedItem == SelectedItem.EMPTY_SELECTION) {
+                // User removed the last panel. In this case we start app selection flow and don't
+                // want to auto-add it again
+                selectedComponentRepository.setShouldAddDefaultComponent(false)
+            }
             reload(parent)
         }.apply { show() }
     }
@@ -437,6 +427,7 @@
         } else {
             Log.w(ControlsUiController.TAG, "Not TaskViewFactory to display panel $selectionItem")
         }
+        this.selectionItem = selectionItem
 
         bgExecutor.execute {
             val intent = Intent(Intent.ACTION_MAIN)
@@ -522,8 +513,7 @@
                             ADD_APP_ID
                     ))
                 }
-                if (featureFlags.isEnabled(Flags.APP_PANELS_REMOVE_APPS_ALLOWED) &&
-                        controlsController.get().canRemoveFavorites(selectedItem.componentName)) {
+                if (featureFlags.isEnabled(Flags.APP_PANELS_REMOVE_APPS_ALLOWED)) {
                     add(OverflowMenuAdapter.MenuItem(
                             context.getText(R.string.controls_menu_remove),
                             REMOVE_APP_ID,
@@ -569,7 +559,7 @@
                                 ADD_CONTROLS_ID -> startFavoritingActivity(selectedStructure)
                                 EDIT_CONTROLS_ID -> startEditingActivity(selectedStructure)
                                 REMOVE_APP_ID -> startRemovingApp(
-                                        selectedStructure.componentName, selectionItem.appName
+                                        selectionItem.componentName, selectionItem.appName
                                 )
                             }
                             dismiss()
@@ -618,6 +608,7 @@
         if (items.size == 1) {
             spinner.setBackground(null)
             anchor.setOnClickListener(null)
+            anchor.isClickable = false
             return
         } else {
             spinner.background = parent.context.resources
@@ -670,6 +661,7 @@
         val maxColumns = ControlAdapter.findMaxColumns(activityContext.resources)
 
         val listView = parent.requireViewById(R.id.global_actions_controls_list) as ViewGroup
+        listView.removeAllViews()
         var lastRow: ViewGroup = createRow(inflater, listView)
         selectedStructure.controls.forEach {
             val key = ControlKey(selectedStructure.componentName, it.controlId)
@@ -714,29 +706,22 @@
     }
 
     override fun getPreferredSelectedItem(structures: List<StructureInfo>): SelectedItem {
-        val sp = sharedPreferences
-
-        val component = sp.getString(PREF_COMPONENT, null)?.let {
-            ComponentName.unflattenFromString(it)
-        } ?: EMPTY_COMPONENT
-        val name = sp.getString(PREF_STRUCTURE_OR_APP_NAME, "")!!
-        val isPanel = sp.getBoolean(PREF_IS_PANEL, false)
-        return if (isPanel) {
-            SelectedItem.PanelItem(name, component)
+        val preferredPanel = selectedComponentRepository.getSelectedComponent()
+        val component = preferredPanel?.componentName ?: EMPTY_COMPONENT
+        return if (preferredPanel?.isPanel == true) {
+            SelectedItem.PanelItem(preferredPanel.name, component)
         } else {
             if (structures.isEmpty()) return SelectedItem.EMPTY_SELECTION
             SelectedItem.StructureItem(structures.firstOrNull {
-                component == it.componentName && name == it.structure
-            } ?: structures.get(0))
+                component == it.componentName && preferredPanel?.name == it.structure
+            } ?: structures[0])
         }
     }
 
-    override fun updatePreferences(selectedItem: SelectedItem) {
-        sharedPreferences.edit()
-                .putString(PREF_COMPONENT, selectedItem.componentName.flattenToString())
-                .putString(PREF_STRUCTURE_OR_APP_NAME, selectedItem.name.toString())
-                .putBoolean(PREF_IS_PANEL, selectedItem is SelectedItem.PanelItem)
-                .apply()
+    private fun updatePreferences(selectedItem: SelectedItem) {
+        selectedComponentRepository.setSelectedComponent(
+                SelectedComponentRepository.SelectedComponent(selectedItem)
+        )
     }
 
     private fun maybeUpdateSelectedItem(item: SelectionItem): Boolean {
@@ -824,6 +809,15 @@
         }
     }
 
+    override fun onSizeChange() {
+        selectionItem?.let {
+            when (selectedItem) {
+                is SelectedItem.StructureItem -> createListView(it)
+                is SelectedItem.PanelItem -> taskViewController?.refreshBounds() ?: reload(parent)
+            }
+        } ?: reload(parent)
+    }
+
     private fun createRow(inflater: LayoutInflater, listView: ViewGroup): ViewGroup {
         val row = inflater.inflate(R.layout.controls_row, listView, false) as ViewGroup
         listView.addView(row)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/PanelTaskViewController.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/PanelTaskViewController.kt
index 78e87ca..1f89c91 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/PanelTaskViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/PanelTaskViewController.kt
@@ -37,7 +37,7 @@
     private val activityContext: Context,
     private val uiExecutor: Executor,
     private val pendingIntent: PendingIntent,
-    private val taskView: TaskView,
+    val taskView: TaskView,
     private val hide: () -> Unit = {}
 ) {
 
@@ -108,6 +108,10 @@
             }
         }
 
+    fun refreshBounds() {
+        taskView.onLocationChanged()
+    }
+
     fun dismiss() {
         taskView.release()
     }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index d1c34a8..4fa4075 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
@@ -97,6 +97,7 @@
 import android.view.inputmethod.InputMethodManager;
 import android.view.textclassifier.TextClassificationManager;
 
+import androidx.asynclayoutinflater.view.AsyncLayoutInflater;
 import androidx.core.app.NotificationManagerCompat;
 
 import com.android.internal.app.IBatteryStats;
@@ -388,6 +389,13 @@
         return LayoutInflater.from(context);
     }
 
+    /** */
+    @Provides
+    @Singleton
+    public AsyncLayoutInflater provideAsyncLayoutInflater(Context context) {
+        return new AsyncLayoutInflater(context);
+    }
+
     @Provides
     static MediaProjectionManager provideMediaProjectionManager(Context context) {
         return context.getSystemService(MediaProjectionManager.class);
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index f0ee443..05527bd 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -70,11 +70,14 @@
 import com.android.systemui.settings.DisplayTracker;
 import com.android.systemui.settings.dagger.MultiUserUtilsModule;
 import com.android.systemui.shade.ShadeController;
+import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
+import com.android.systemui.shade.transition.LargeScreenShadeInterpolatorImpl;
 import com.android.systemui.smartspace.dagger.SmartspaceModule;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.connectivity.ConnectivityModule;
+import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
 import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
@@ -256,9 +259,7 @@
     abstract FingerprintInteractiveToAuthProvider optionalFingerprintInteractiveToAuthProvider();
 
     @BindsOptionalOf
-    //TODO(b/269430792 remove full qualifier. Full qualifier is used to avoid merge conflict.)
-    abstract com.android.systemui.statusbar.events.SystemStatusAnimationScheduler
-    optionalSystemStatusAnimationScheduler();
+    abstract SystemStatusAnimationScheduler optionalSystemStatusAnimationScheduler();
 
     @SysUISingleton
     @Binds
@@ -307,4 +308,8 @@
 
     @Binds
     abstract FgsManagerController bindFgsManagerController(FgsManagerControllerImpl impl);
+
+    @Binds
+    abstract LargeScreenShadeInterpolator largeScreensShadeInterpolator(
+            LargeScreenShadeInterpolatorImpl impl);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index fc3263f..f0aefb5 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -398,7 +398,8 @@
         }
         if ((mState == State.DOZE_AOD_PAUSED || mState == State.DOZE_AOD_PAUSING
                 || mState == State.DOZE_AOD || mState == State.DOZE
-                || mState == State.DOZE_AOD_DOCKED) && requestedState == State.DOZE_PULSE_DONE) {
+                || mState == State.DOZE_AOD_DOCKED || mState == State.DOZE_SUSPEND_TRIGGERS)
+                && requestedState == State.DOZE_PULSE_DONE) {
             Log.i(TAG, "Dropping pulse done because current state is already done: " + mState);
             return mState;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamMonitor.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamMonitor.java
index 055cd52..7f567aa 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamMonitor.java
@@ -23,6 +23,7 @@
 import com.android.systemui.CoreStartable;
 import com.android.systemui.dreams.callbacks.DreamStatusBarStateCallback;
 import com.android.systemui.dreams.conditions.DreamCondition;
+import com.android.systemui.flags.RestartDozeListener;
 import com.android.systemui.shared.condition.Monitor;
 import com.android.systemui.util.condition.ConditionalCoreStartable;
 
@@ -39,17 +40,19 @@
     private final Monitor mConditionMonitor;
     private final DreamCondition mDreamCondition;
     private final DreamStatusBarStateCallback mCallback;
+    private RestartDozeListener mRestartDozeListener;
 
 
     @Inject
     public DreamMonitor(Monitor monitor, DreamCondition dreamCondition,
             @Named(DREAM_PRETEXT_MONITOR) Monitor pretextMonitor,
-            DreamStatusBarStateCallback callback) {
+            DreamStatusBarStateCallback callback,
+            RestartDozeListener restartDozeListener) {
         super(pretextMonitor);
         mConditionMonitor = monitor;
         mDreamCondition = dreamCondition;
         mCallback = callback;
-
+        mRestartDozeListener = restartDozeListener;
     }
 
     @Override
@@ -61,5 +64,8 @@
         mConditionMonitor.addSubscription(new Monitor.Subscription.Builder(mCallback)
                 .addCondition(mDreamCondition)
                 .build());
+
+        mRestartDozeListener.init();
+        mRestartDozeListener.maybeRestartSleep();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
index ca1cef3..d0a92f0 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
@@ -43,7 +43,6 @@
 import javax.inject.Inject
 import javax.inject.Named
 import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.flow.flatMapLatest
 import kotlinx.coroutines.launch
 
@@ -131,9 +130,17 @@
         }
     }
 
-    /** Starts the dream content and dream overlay entry animations. */
+    /**
+     * Starts the dream content and dream overlay entry animations.
+     *
+     * @param downwards if true, the entry animation translations downwards into position rather
+     *   than upwards.
+     */
     @JvmOverloads
-    fun startEntryAnimations(animatorBuilder: () -> AnimatorSet = { AnimatorSet() }) {
+    fun startEntryAnimations(
+        downwards: Boolean,
+        animatorBuilder: () -> AnimatorSet = { AnimatorSet() }
+    ) {
         cancelAnimations()
 
         mAnimator =
@@ -153,7 +160,7 @@
                         interpolator = Interpolators.LINEAR
                     ),
                     translationYAnimator(
-                        from = mDreamInTranslationYDistance.toFloat(),
+                        from = mDreamInTranslationYDistance.toFloat() * (if (downwards) -1 else 1),
                         to = 0f,
                         durationMs = mDreamInTranslationYDurationMs,
                         interpolator = Interpolators.EMPHASIZED_DECELERATE
@@ -167,6 +174,71 @@
             }
     }
 
+    /**
+     * Starts the dream content and dream overlay exit animations.
+     *
+     * This should only be used when the low light dream is entering, animations to/from other SysUI
+     * views is controlled by `transitionViewModel`.
+     */
+    // TODO(b/256916668): integrate with the keyguard transition model once dream surfaces work is
+    // done.
+    @JvmOverloads
+    fun startExitAnimations(animatorBuilder: () -> AnimatorSet = { AnimatorSet() }): Animator {
+        cancelAnimations()
+
+        mAnimator =
+            animatorBuilder().apply {
+                playTogether(
+                    translationYAnimator(
+                        from = 0f,
+                        to = -mDreamInTranslationYDistance.toFloat(),
+                        durationMs = mDreamInTranslationYDurationMs,
+                        delayMs = 0,
+                        interpolator = Interpolators.EMPHASIZED
+                    ),
+                    alphaAnimator(
+                            from =
+                                mCurrentAlphaAtPosition.getOrDefault(
+                                    key = POSITION_BOTTOM,
+                                    defaultValue = 1f
+                                ),
+                            to = 0f,
+                            durationMs = mDreamInComplicationsAnimDurationMs,
+                            delayMs = 0,
+                            positions = POSITION_BOTTOM
+                        )
+                        .apply {
+                            doOnEnd {
+                                // The logical end of the animation is once the alpha and blur
+                                // animations finish, end the animation so that any listeners are
+                                // notified. The Y translation animation is much longer than all of
+                                // the other animations due to how the spec is defined, but is not
+                                // expected to run to completion.
+                                mAnimator?.end()
+                            }
+                        },
+                    alphaAnimator(
+                        from =
+                            mCurrentAlphaAtPosition.getOrDefault(
+                                key = POSITION_TOP,
+                                defaultValue = 1f
+                            ),
+                        to = 0f,
+                        durationMs = mDreamInComplicationsAnimDurationMs,
+                        delayMs = 0,
+                        positions = POSITION_TOP
+                    )
+                )
+                doOnEnd {
+                    mAnimator = null
+                    mOverlayStateController.setExitAnimationsRunning(false)
+                }
+                start()
+            }
+        mOverlayStateController.setExitAnimationsRunning(true)
+        return mAnimator as AnimatorSet
+    }
+
     /** Starts the dream content and dream overlay exit animations. */
     fun wakeUp(doneCallback: Runnable, executor: DelayableExecutor) {
         cancelAnimations()
@@ -182,19 +254,6 @@
             }
     }
 
-    /**
-     * Ends the dream content and dream overlay animations, if they're currently running.
-     *
-     * @see [AnimatorSet.end]
-     */
-    fun endAnimations() {
-        mAnimator =
-            mAnimator?.let {
-                it.end()
-                null
-            }
-    }
-
     private fun blurAnimator(
         view: View,
         fromBlurRadius: Float,
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
index 50cfb6a..4b478cd 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
@@ -23,6 +23,7 @@
 import static com.android.systemui.dreams.complication.ComplicationLayoutParams.POSITION_BOTTOM;
 import static com.android.systemui.dreams.complication.ComplicationLayoutParams.POSITION_TOP;
 
+import android.animation.Animator;
 import android.content.res.Resources;
 import android.os.Handler;
 import android.util.MathUtils;
@@ -31,6 +32,7 @@
 
 import androidx.annotation.NonNull;
 
+import com.android.dream.lowlight.LowLightTransitionCoordinator;
 import com.android.systemui.R;
 import com.android.systemui.animation.Interpolators;
 import com.android.systemui.dagger.qualifiers.Main;
@@ -54,11 +56,14 @@
  * View controller for {@link DreamOverlayContainerView}.
  */
 @DreamOverlayComponent.DreamOverlayScope
-public class DreamOverlayContainerViewController extends ViewController<DreamOverlayContainerView> {
+public class DreamOverlayContainerViewController extends
+        ViewController<DreamOverlayContainerView> implements
+        LowLightTransitionCoordinator.LowLightEnterListener {
     private final DreamOverlayStatusBarViewController mStatusBarViewController;
     private final BlurUtils mBlurUtils;
     private final DreamOverlayAnimationsController mDreamOverlayAnimationsController;
     private final DreamOverlayStateController mStateController;
+    private final LowLightTransitionCoordinator mLowLightTransitionCoordinator;
 
     private final ComplicationHostViewController mComplicationHostViewController;
 
@@ -143,19 +148,18 @@
             };
 
     /**
-     * If true, overlay entry animations should be skipped once.
-     *
-     * This is turned on when exiting low light and should be turned off once the entry animations
-     * are skipped once.
+     * If {@code true}, the dream has just transitioned from the low light dream back to the user
+     * dream and we should play an entry animation where the overlay slides in downwards from the
+     * top instead of the typicla slide in upwards from the bottom.
      */
-    private boolean mSkipEntryAnimations;
+    private boolean mExitingLowLight;
 
     private final DreamOverlayStateController.Callback
             mDreamOverlayStateCallback =
             new DreamOverlayStateController.Callback() {
                 @Override
                 public void onExitLowLight() {
-                    mSkipEntryAnimations = true;
+                    mExitingLowLight = true;
                 }
             };
 
@@ -165,6 +169,7 @@
             ComplicationHostViewController complicationHostViewController,
             @Named(DreamOverlayModule.DREAM_OVERLAY_CONTENT_VIEW) ViewGroup contentView,
             DreamOverlayStatusBarViewController statusBarViewController,
+            LowLightTransitionCoordinator lowLightTransitionCoordinator,
             BlurUtils blurUtils,
             @Main Handler handler,
             @Main Resources resources,
@@ -182,6 +187,7 @@
         mBlurUtils = blurUtils;
         mDreamOverlayAnimationsController = animationsController;
         mStateController = stateController;
+        mLowLightTransitionCoordinator = lowLightTransitionCoordinator;
 
         mBouncerlessScrimController = bouncerlessScrimController;
         mBouncerlessScrimController.addCallback(mBouncerlessExpansionCallback);
@@ -208,6 +214,7 @@
         mStatusBarViewController.init();
         mComplicationHostViewController.init();
         mDreamOverlayAnimationsController.init(mView);
+        mLowLightTransitionCoordinator.setLowLightEnterListener(this);
     }
 
     @Override
@@ -219,14 +226,10 @@
 
         // Start dream entry animations. Skip animations for low light clock.
         if (!mStateController.isLowLightActive()) {
-            mDreamOverlayAnimationsController.startEntryAnimations();
-
-            if (mSkipEntryAnimations) {
-                // If we're transitioning from the low light dream back to the user dream, skip the
-                // overlay animations and show immediately.
-                mDreamOverlayAnimationsController.endAnimations();
-                mSkipEntryAnimations = false;
-            }
+            // If this is transitioning from the low light dream to the user dream, the overlay
+            // should translate in downwards instead of upwards.
+            mDreamOverlayAnimationsController.startEntryAnimations(mExitingLowLight);
+            mExitingLowLight = false;
         }
     }
 
@@ -310,4 +313,12 @@
 
         mDreamOverlayAnimationsController.wakeUp(onAnimationEnd, callbackExecutor);
     }
+
+    @Override
+    public Animator onBeforeEnterLowLight() {
+        // Return the animator so that the transition coordinator waits for the overlay exit
+        // animations to finish before entering low light, as otherwise the default DreamActivity
+        // animation plays immediately and there's no time for this animation to play.
+        return mDreamOverlayAnimationsController.startExitAnimations();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
index 854323f..a0fef75 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
@@ -139,6 +139,7 @@
                     ComponentName lowLightDreamComponent,
             DreamOverlayCallbackController dreamOverlayCallbackController,
             @Named(DREAM_OVERLAY_WINDOW_TITLE) String windowTitle) {
+        super(executor);
         mContext = context;
         mExecutor = executor;
         mWindowManager = windowManager;
@@ -176,55 +177,50 @@
 
     @Override
     public void onStartDream(@NonNull WindowManager.LayoutParams layoutParams) {
-        mExecutor.execute(() -> {
-            setCurrentStateLocked(Lifecycle.State.STARTED);
+        setCurrentStateLocked(Lifecycle.State.STARTED);
 
-            mUiEventLogger.log(DreamOverlayEvent.DREAM_OVERLAY_ENTER_START);
+        mUiEventLogger.log(DreamOverlayEvent.DREAM_OVERLAY_ENTER_START);
 
-            if (mDestroyed) {
-                // The task could still be executed after the service has been destroyed. Bail if
-                // that is the case.
-                return;
-            }
+        if (mDestroyed) {
+            // The task could still be executed after the service has been destroyed. Bail if
+            // that is the case.
+            return;
+        }
 
-            if (mStarted) {
-                // Reset the current dream overlay before starting a new one. This can happen
-                // when two dreams overlap (briefly, for a smoother dream transition) and both
-                // dreams are bound to the dream overlay service.
-                resetCurrentDreamOverlayLocked();
-            }
+        if (mStarted) {
+            // Reset the current dream overlay before starting a new one. This can happen
+            // when two dreams overlap (briefly, for a smoother dream transition) and both
+            // dreams are bound to the dream overlay service.
+            resetCurrentDreamOverlayLocked();
+        }
 
-            mDreamOverlayContainerViewController =
-                    mDreamOverlayComponent.getDreamOverlayContainerViewController();
-            mDreamOverlayTouchMonitor = mDreamOverlayComponent.getDreamOverlayTouchMonitor();
-            mDreamOverlayTouchMonitor.init();
+        mDreamOverlayContainerViewController =
+                mDreamOverlayComponent.getDreamOverlayContainerViewController();
+        mDreamOverlayTouchMonitor = mDreamOverlayComponent.getDreamOverlayTouchMonitor();
+        mDreamOverlayTouchMonitor.init();
 
-            mStateController.setShouldShowComplications(shouldShowComplications());
+        mStateController.setShouldShowComplications(shouldShowComplications());
 
-            // If we are not able to add the overlay window, reset the overlay.
-            if (!addOverlayWindowLocked(layoutParams)) {
-                resetCurrentDreamOverlayLocked();
-                return;
-            }
+        // If we are not able to add the overlay window, reset the overlay.
+        if (!addOverlayWindowLocked(layoutParams)) {
+            resetCurrentDreamOverlayLocked();
+            return;
+        }
 
+        setCurrentStateLocked(Lifecycle.State.RESUMED);
+        mStateController.setOverlayActive(true);
+        final ComponentName dreamComponent = getDreamComponent();
+        mStateController.setLowLightActive(
+                dreamComponent != null && dreamComponent.equals(mLowLightDreamComponent));
+        mUiEventLogger.log(DreamOverlayEvent.DREAM_OVERLAY_COMPLETE_START);
 
-            setCurrentStateLocked(Lifecycle.State.RESUMED);
-            mStateController.setOverlayActive(true);
-            final ComponentName dreamComponent = getDreamComponent();
-            mStateController.setLowLightActive(
-                    dreamComponent != null && dreamComponent.equals(mLowLightDreamComponent));
-            mUiEventLogger.log(DreamOverlayEvent.DREAM_OVERLAY_COMPLETE_START);
-
-            mDreamOverlayCallbackController.onStartDream();
-            mStarted = true;
-        });
+        mDreamOverlayCallbackController.onStartDream();
+        mStarted = true;
     }
 
     @Override
     public void onEndDream() {
-        mExecutor.execute(() -> {
-            resetCurrentDreamOverlayLocked();
-        });
+        resetCurrentDreamOverlayLocked();
     }
 
     private Lifecycle.State getCurrentStateLocked() {
@@ -237,12 +233,10 @@
 
     @Override
     public void onWakeUp(@NonNull Runnable onCompletedCallback) {
-        mExecutor.execute(() -> {
-            if (mDreamOverlayContainerViewController != null) {
-                mDreamOverlayCallbackController.onWakeUp();
-                mDreamOverlayContainerViewController.wakeUp(onCompletedCallback, mExecutor);
-            }
-        });
+        if (mDreamOverlayContainerViewController != null) {
+            mDreamOverlayCallbackController.onWakeUp();
+            mDreamOverlayContainerViewController.wakeUp(onCompletedCallback, mExecutor);
+        }
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
index 2c7ecb1..a475653 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
@@ -27,6 +27,8 @@
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dreams.complication.Complication;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.statusbar.policy.CallbackController;
 
 import java.util.ArrayList;
@@ -102,15 +104,27 @@
 
     private final Collection<Complication> mComplications = new HashSet();
 
+    private final FeatureFlags mFeatureFlags;
+
+    private final int mSupportedTypes;
+
     @VisibleForTesting
     @Inject
     public DreamOverlayStateController(@Main Executor executor,
-            @Named(DREAM_OVERLAY_ENABLED) boolean overlayEnabled) {
+            @Named(DREAM_OVERLAY_ENABLED) boolean overlayEnabled,
+            FeatureFlags featureFlags) {
         mExecutor = executor;
         mOverlayEnabled = overlayEnabled;
+        mFeatureFlags = featureFlags;
         if (DEBUG) {
             Log.d(TAG, "Dream overlay enabled:" + mOverlayEnabled);
         }
+        if (mFeatureFlags.isEnabled(Flags.ALWAYS_SHOW_HOME_CONTROLS_ON_DREAMS)) {
+            mSupportedTypes = Complication.COMPLICATION_TYPE_NONE
+                    | Complication.COMPLICATION_TYPE_HOME_CONTROLS;
+        } else {
+            mSupportedTypes = Complication.COMPLICATION_TYPE_NONE;
+        }
     }
 
     /**
@@ -179,7 +193,7 @@
                     if (mShouldShowComplications) {
                         return (requiredTypes & getAvailableComplicationTypes()) == requiredTypes;
                     }
-                    return requiredTypes == Complication.COMPLICATION_TYPE_NONE;
+                    return (requiredTypes & mSupportedTypes) == requiredTypes;
                 })
                 .collect(Collectors.toCollection(HashSet::new))
                 : mComplications);
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationHostViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationHostViewController.java
index a2e11b2..aad2090 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationHostViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationHostViewController.java
@@ -22,14 +22,18 @@
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.os.Debug;
+import android.os.UserHandle;
+import android.provider.Settings;
 import android.util.Log;
 import android.view.View;
 
 import androidx.constraintlayout.widget.ConstraintLayout;
 import androidx.lifecycle.LifecycleOwner;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.dreams.DreamOverlayStateController;
 import com.android.systemui.util.ViewController;
+import com.android.systemui.util.settings.SecureSettings;
 
 import java.util.Collection;
 import java.util.HashMap;
@@ -54,9 +58,8 @@
     private final LifecycleOwner mLifecycleOwner;
     private final ComplicationCollectionViewModel mComplicationCollectionViewModel;
     private final HashMap<ComplicationId, Complication.ViewHolder> mComplications = new HashMap<>();
-
-    // Whether dream entry animations are finished.
-    private boolean mEntryAnimationsFinished = false;
+    @VisibleForTesting
+    boolean mIsAnimationEnabled;
 
     @Inject
     protected ComplicationHostViewController(
@@ -64,20 +67,17 @@
             ComplicationLayoutEngine layoutEngine,
             DreamOverlayStateController dreamOverlayStateController,
             LifecycleOwner lifecycleOwner,
-            @Named(SCOPED_COMPLICATIONS_MODEL) ComplicationCollectionViewModel viewModel) {
+            @Named(SCOPED_COMPLICATIONS_MODEL) ComplicationCollectionViewModel viewModel,
+            SecureSettings secureSettings) {
         super(view);
         mLayoutEngine = layoutEngine;
         mLifecycleOwner = lifecycleOwner;
         mComplicationCollectionViewModel = viewModel;
         mDreamOverlayStateController = dreamOverlayStateController;
 
-        mDreamOverlayStateController.addCallback(new DreamOverlayStateController.Callback() {
-            @Override
-            public void onStateChanged() {
-                mEntryAnimationsFinished =
-                        mDreamOverlayStateController.areEntryAnimationsFinished();
-            }
-        });
+        // Whether animations are enabled.
+        mIsAnimationEnabled = secureSettings.getFloatForUser(
+                Settings.Global.ANIMATOR_DURATION_SCALE, 1.0f, UserHandle.USER_CURRENT) != 0.0f;
     }
 
     @Override
@@ -148,7 +148,8 @@
 
                     // Complications to be added before dream entry animations are finished are set
                     // to invisible and are animated in.
-                    if (!mEntryAnimationsFinished) {
+                    if (!mDreamOverlayStateController.areEntryAnimationsFinished()
+                            && mIsAnimationEnabled) {
                         view.setVisibility(View.INVISIBLE);
                     }
                     mComplications.put(id, viewHolder);
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationTypesUpdater.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationTypesUpdater.java
index 244212b..1702eac 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationTypesUpdater.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationTypesUpdater.java
@@ -75,6 +75,10 @@
                 Settings.Secure.SCREENSAVER_COMPLICATIONS_ENABLED,
                 settingsObserver,
                 UserHandle.myUserId());
+        mSecureSettings.registerContentObserverForUser(
+                Settings.Secure.SCREENSAVER_HOME_CONTROLS_ENABLED,
+                settingsObserver,
+                UserHandle.myUserId());
         settingsObserver.onChange(false);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java
index 7f395d8..82a8858 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java
@@ -33,7 +33,6 @@
 import com.android.internal.logging.UiEvent;
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.CoreStartable;
-import com.android.systemui.R;
 import com.android.systemui.animation.ActivityLaunchAnimator;
 import com.android.systemui.controls.ControlsServiceInfo;
 import com.android.systemui.controls.dagger.ControlsComponent;
@@ -157,14 +156,14 @@
      * Contains values/logic associated with the dream complication view.
      */
     public static class DreamHomeControlsChipViewHolder implements ViewHolder {
-        private final View mView;
+        private final ImageView mView;
         private final ComplicationLayoutParams mLayoutParams;
         private final DreamHomeControlsChipViewController mViewController;
 
         @Inject
         DreamHomeControlsChipViewHolder(
                 DreamHomeControlsChipViewController dreamHomeControlsChipViewController,
-                @Named(DREAM_HOME_CONTROLS_CHIP_VIEW) View view,
+                @Named(DREAM_HOME_CONTROLS_CHIP_VIEW) ImageView view,
                 @Named(DREAM_HOME_CONTROLS_CHIP_LAYOUT_PARAMS) ComplicationLayoutParams layoutParams
         ) {
             mView = view;
@@ -174,7 +173,7 @@
         }
 
         @Override
-        public View getView() {
+        public ImageView getView() {
             return mView;
         }
 
@@ -187,7 +186,7 @@
     /**
      * Controls behavior of the dream complication.
      */
-    static class DreamHomeControlsChipViewController extends ViewController<View> {
+    static class DreamHomeControlsChipViewController extends ViewController<ImageView> {
         private static final String TAG = "DreamHomeControlsCtrl";
         private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
@@ -216,7 +215,7 @@
 
         @Inject
         DreamHomeControlsChipViewController(
-                @Named(DREAM_HOME_CONTROLS_CHIP_VIEW) View view,
+                @Named(DREAM_HOME_CONTROLS_CHIP_VIEW) ImageView view,
                 ActivityStarter activityStarter,
                 Context context,
                 ControlsComponent controlsComponent,
@@ -231,10 +230,9 @@
 
         @Override
         protected void onViewAttached() {
-            final ImageView chip = mView.findViewById(R.id.home_controls_chip);
-            chip.setImageResource(mControlsComponent.getTileImageId());
-            chip.setContentDescription(mContext.getString(mControlsComponent.getTileTitleId()));
-            chip.setOnClickListener(this::onClickHomeControls);
+            mView.setImageResource(mControlsComponent.getTileImageId());
+            mView.setContentDescription(mContext.getString(mControlsComponent.getTileTitleId()));
+            mView.setOnClickListener(this::onClickHomeControls);
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamHomeControlsComplicationComponent.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamHomeControlsComplicationComponent.java
index a7aa97f..cf05d2d 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamHomeControlsComplicationComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamHomeControlsComplicationComponent.java
@@ -19,7 +19,7 @@
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
 
 import android.view.LayoutInflater;
-import android.view.View;
+import android.widget.ImageView;
 
 import com.android.systemui.R;
 import com.android.systemui.dreams.complication.DreamHomeControlsComplication;
@@ -74,8 +74,8 @@
         @Provides
         @DreamHomeControlsComplicationScope
         @Named(DREAM_HOME_CONTROLS_CHIP_VIEW)
-        static View provideHomeControlsChipView(LayoutInflater layoutInflater) {
-            return layoutInflater.inflate(R.layout.dream_overlay_home_controls_chip,
+        static ImageView provideHomeControlsChipView(LayoutInflater layoutInflater) {
+            return (ImageView) layoutInflater.inflate(R.layout.dream_overlay_home_controls_chip,
                     null, false);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java
index 9b954f5f..3be42cb 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java
@@ -23,6 +23,8 @@
 import com.android.systemui.dagger.SystemUIBinder;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dreams.complication.ComplicationLayoutParams;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 
 import javax.inject.Named;
 
@@ -47,17 +49,27 @@
     String DREAM_MEDIA_ENTRY_LAYOUT_PARAMS = "media_entry_layout_params";
 
     int DREAM_CLOCK_TIME_COMPLICATION_WEIGHT = 1;
+    int DREAM_CLOCK_TIME_COMPLICATION_WEIGHT_NO_SMARTSPACE = 2;
     int DREAM_SMARTSPACE_COMPLICATION_WEIGHT = 2;
     int DREAM_MEDIA_COMPLICATION_WEIGHT = 0;
     int DREAM_HOME_CONTROLS_CHIP_COMPLICATION_WEIGHT = 4;
     int DREAM_MEDIA_ENTRY_COMPLICATION_WEIGHT = 3;
+    int DREAM_WEATHER_COMPLICATION_WEIGHT = 0;
 
     /**
      * Provides layout parameters for the clock time complication.
      */
     @Provides
     @Named(DREAM_CLOCK_TIME_COMPLICATION_LAYOUT_PARAMS)
-    static ComplicationLayoutParams provideClockTimeLayoutParams() {
+    static ComplicationLayoutParams provideClockTimeLayoutParams(FeatureFlags featureFlags) {
+        if (featureFlags.isEnabled(Flags.HIDE_SMARTSPACE_ON_DREAM_OVERLAY)) {
+            return new ComplicationLayoutParams(0,
+                    ViewGroup.LayoutParams.WRAP_CONTENT,
+                    ComplicationLayoutParams.POSITION_BOTTOM
+                            | ComplicationLayoutParams.POSITION_START,
+                    ComplicationLayoutParams.DIRECTION_END,
+                    DREAM_CLOCK_TIME_COMPLICATION_WEIGHT_NO_SMARTSPACE);
+        }
         return new ComplicationLayoutParams(0,
                 ViewGroup.LayoutParams.WRAP_CONTENT,
                 ComplicationLayoutParams.POSITION_BOTTOM
@@ -89,8 +101,8 @@
     @Named(DREAM_MEDIA_ENTRY_LAYOUT_PARAMS)
     static ComplicationLayoutParams provideMediaEntryLayoutParams(@Main Resources res) {
         return new ComplicationLayoutParams(
-                res.getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width),
-                res.getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height),
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT,
                 ComplicationLayoutParams.POSITION_BOTTOM
                         | ComplicationLayoutParams.POSITION_START,
                 ComplicationLayoutParams.DIRECTION_END,
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java b/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java
index 2befce7..5bbfbda 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java
@@ -15,6 +15,7 @@
  */
 package com.android.systemui.dreams.conditions;
 
+import android.app.DreamManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -30,6 +31,7 @@
  */
 public class DreamCondition extends Condition {
     private final Context mContext;
+    private final DreamManager mDreamManager;
 
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
@@ -39,8 +41,10 @@
     };
 
     @Inject
-    public DreamCondition(Context context) {
+    public DreamCondition(Context context,
+            DreamManager dreamManager) {
         mContext = context;
+        mDreamManager = dreamManager;
     }
 
     private void processIntent(Intent intent) {
@@ -62,8 +66,8 @@
         final IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_DREAMING_STARTED);
         filter.addAction(Intent.ACTION_DREAMING_STOPPED);
-        final Intent stickyIntent = mContext.registerReceiver(mReceiver, filter);
-        processIntent(stickyIntent);
+        mContext.registerReceiver(mReceiver, filter);
+        updateCondition(mDreamManager.isDreaming());
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/smartspace/DreamSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/dreams/smartspace/DreamSmartspaceController.kt
index 63f63a5..78e132f 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/smartspace/DreamSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/smartspace/DreamSmartspaceController.kt
@@ -30,14 +30,15 @@
 import com.android.systemui.plugins.BcSmartspaceDataPlugin
 import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceTargetListener
 import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceView
+import com.android.systemui.plugins.BcSmartspaceDataPlugin.UI_SURFACE_DREAM
 import com.android.systemui.smartspace.SmartspacePrecondition
 import com.android.systemui.smartspace.SmartspaceTargetFilter
+import com.android.systemui.smartspace.dagger.SmartspaceModule
 import com.android.systemui.smartspace.dagger.SmartspaceModule.Companion.DREAM_SMARTSPACE_DATA_PLUGIN
 import com.android.systemui.smartspace.dagger.SmartspaceModule.Companion.DREAM_SMARTSPACE_PRECONDITION
 import com.android.systemui.smartspace.dagger.SmartspaceModule.Companion.DREAM_SMARTSPACE_TARGET_FILTER
 import com.android.systemui.smartspace.dagger.SmartspaceViewComponent
 import com.android.systemui.util.concurrency.Execution
-import java.lang.RuntimeException
 import java.util.Optional
 import java.util.concurrent.Executor
 import javax.inject.Inject
@@ -56,13 +57,16 @@
     @Named(DREAM_SMARTSPACE_PRECONDITION) private val precondition: SmartspacePrecondition,
     @Named(DREAM_SMARTSPACE_TARGET_FILTER)
     private val optionalTargetFilter: Optional<SmartspaceTargetFilter>,
-    @Named(DREAM_SMARTSPACE_DATA_PLUGIN) optionalPlugin: Optional<BcSmartspaceDataPlugin>
+    @Named(DREAM_SMARTSPACE_DATA_PLUGIN) optionalPlugin: Optional<BcSmartspaceDataPlugin>,
+    @Named(SmartspaceModule.WEATHER_SMARTSPACE_DATA_PLUGIN)
+    optionalWeatherPlugin: Optional<BcSmartspaceDataPlugin>,
 ) {
     companion object {
         private const val TAG = "DreamSmartspaceCtrlr"
     }
 
     private var session: SmartspaceSession? = null
+    private val weatherPlugin: BcSmartspaceDataPlugin? = optionalWeatherPlugin.orElse(null)
     private val plugin: BcSmartspaceDataPlugin? = optionalPlugin.orElse(null)
     private var targetFilter: SmartspaceTargetFilter? = optionalTargetFilter.orElse(null)
 
@@ -116,31 +120,54 @@
     private val sessionListener = SmartspaceSession.OnTargetsAvailableListener { targets ->
         execution.assertIsMainThread()
 
+        // The weather data plugin takes unfiltered targets and performs the filtering internally.
+        weatherPlugin?.onTargetsAvailable(targets)
+
         onTargetsAvailableUnfiltered(targets)
         val filteredTargets = targets.filter { targetFilter?.filterSmartspaceTarget(it) ?: true }
         plugin?.onTargetsAvailable(filteredTargets)
     }
 
     /**
+     * Constructs the weather view with custom layout and connects it to the weather plugin.
+     */
+    fun buildAndConnectWeatherView(parent: ViewGroup, customView: View?): View? {
+        return buildAndConnectViewWithPlugin(parent, weatherPlugin, customView)
+    }
+
+    /**
      * Constructs the smartspace view and connects it to the smartspace service.
      */
     fun buildAndConnectView(parent: ViewGroup): View? {
+        return buildAndConnectViewWithPlugin(parent, plugin, null)
+    }
+
+    private fun buildAndConnectViewWithPlugin(
+        parent: ViewGroup,
+        smartspaceDataPlugin: BcSmartspaceDataPlugin?,
+        customView: View?
+    ): View? {
         execution.assertIsMainThread()
 
         if (!precondition.conditionsMet()) {
             throw RuntimeException("Cannot build view when not enabled")
         }
 
-        val view = buildView(parent)
+        val view = buildView(parent, smartspaceDataPlugin, customView)
 
         connectSession()
 
         return view
     }
 
-    private fun buildView(parent: ViewGroup): View? {
-        return if (plugin != null) {
-            var view = smartspaceViewComponentFactory.create(parent, plugin, stateChangeListener)
+    private fun buildView(
+        parent: ViewGroup,
+        smartspaceDataPlugin: BcSmartspaceDataPlugin?,
+        customView: View?
+    ): View? {
+        return if (smartspaceDataPlugin != null) {
+            val view = smartspaceViewComponentFactory.create(parent, smartspaceDataPlugin,
+                stateChangeListener, customView)
                 .getView()
             if (view !is View) {
                 return null
@@ -157,7 +184,10 @@
     }
 
     private fun connectSession() {
-        if (plugin == null || session != null || !hasActiveSessionListeners()) {
+        if (plugin == null && weatherPlugin == null) {
+            return
+        }
+        if (session != null || !hasActiveSessionListeners()) {
             return
         }
 
@@ -166,13 +196,14 @@
         }
 
         val newSession = smartspaceManager.createSmartspaceSession(
-            SmartspaceConfig.Builder(context, "dream").build()
+            SmartspaceConfig.Builder(context, UI_SURFACE_DREAM).build()
         )
         Log.d(TAG, "Starting smartspace session for dream")
         newSession.addOnTargetsAvailableListener(uiExecutor, sessionListener)
         this.session = newSession
 
-        plugin.registerSmartspaceEventNotifier {
+        weatherPlugin?.registerSmartspaceEventNotifier { e -> session?.notifySmartspaceEvent(e) }
+        plugin?.registerSmartspaceEventNotifier {
                 e ->
             session?.notifySmartspaceEvent(e)
         }
@@ -199,22 +230,47 @@
 
         session = null
 
+        weatherPlugin?.registerSmartspaceEventNotifier(null)
+        weatherPlugin?.onTargetsAvailable(emptyList())
+
         plugin?.registerSmartspaceEventNotifier(null)
         plugin?.onTargetsAvailable(emptyList())
         Log.d(TAG, "Ending smartspace session for dream")
     }
 
     fun addListener(listener: SmartspaceTargetListener) {
+        addAndRegisterListener(listener, plugin)
+    }
+
+    fun removeListener(listener: SmartspaceTargetListener) {
+        removeAndUnregisterListener(listener, plugin)
+    }
+
+    fun addListenerForWeatherPlugin(listener: SmartspaceTargetListener) {
+        addAndRegisterListener(listener, weatherPlugin)
+    }
+
+    fun removeListenerForWeatherPlugin(listener: SmartspaceTargetListener) {
+        removeAndUnregisterListener(listener, weatherPlugin)
+    }
+
+    private fun addAndRegisterListener(
+        listener: SmartspaceTargetListener,
+        smartspaceDataPlugin: BcSmartspaceDataPlugin?
+    ) {
         execution.assertIsMainThread()
-        plugin?.registerListener(listener)
+        smartspaceDataPlugin?.registerListener(listener)
         listeners.add(listener)
 
         connectSession()
     }
 
-    fun removeListener(listener: SmartspaceTargetListener) {
+    private fun removeAndUnregisterListener(
+        listener: SmartspaceTargetListener,
+        smartspaceDataPlugin: BcSmartspaceDataPlugin?
+    ) {
         execution.assertIsMainThread()
-        plugin?.unregisterListener(listener)
+        smartspaceDataPlugin?.unregisterListener(listener)
         listeners.remove(listener)
         disconnect()
     }
diff --git a/packages/SystemUI/src/com/android/systemui/flags/ConditionalRestarter.kt b/packages/SystemUI/src/com/android/systemui/flags/ConditionalRestarter.kt
new file mode 100644
index 0000000..b20e33a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/flags/ConditionalRestarter.kt
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.flags
+
+import android.util.Log
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import java.util.concurrent.TimeUnit
+import javax.inject.Inject
+import javax.inject.Named
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+
+/** Restarts the process after all passed in [Condition]s are true. */
+class ConditionalRestarter
+@Inject
+constructor(
+    private val systemExitRestarter: SystemExitRestarter,
+    private val conditions: Set<@JvmSuppressWildcards Condition>,
+    @Named(RESTART_DELAY) private val restartDelaySec: Long,
+    @Application private val applicationScope: CoroutineScope,
+    @Background private val backgroundDispatcher: CoroutineDispatcher,
+) : Restarter {
+
+    private var restartJob: Job? = null
+    private var pendingReason = ""
+    private var androidRestartRequested = false
+
+    override fun restartSystemUI(reason: String) {
+        Log.d(FeatureFlagsDebug.TAG, "SystemUI Restart requested. Restarting when idle.")
+        scheduleRestart(reason)
+    }
+
+    override fun restartAndroid(reason: String) {
+        Log.d(FeatureFlagsDebug.TAG, "Android Restart requested. Restarting when idle.")
+        androidRestartRequested = true
+        scheduleRestart(reason)
+    }
+
+    private fun scheduleRestart(reason: String = "") {
+        pendingReason = if (reason.isEmpty()) pendingReason else reason
+
+        if (conditions.all { c -> c.canRestartNow(this::scheduleRestart) }) {
+            if (restartJob == null) {
+                restartJob =
+                    applicationScope.launch(backgroundDispatcher) {
+                        delay(TimeUnit.SECONDS.toMillis(restartDelaySec))
+                        restartNow()
+                    }
+            }
+        } else {
+            restartJob?.cancel()
+            restartJob = null
+        }
+    }
+
+    private fun restartNow() {
+        if (androidRestartRequested) {
+            systemExitRestarter.restartAndroid(pendingReason)
+        } else {
+            systemExitRestarter.restartSystemUI(pendingReason)
+        }
+    }
+
+    interface Condition {
+        /**
+         * Should return true if the system is ready to restart.
+         *
+         * A call to this function means that we want to restart and are waiting for this condition
+         * to return true.
+         *
+         * retryFn should be cached if it is _not_ ready to restart, and later called when it _is_
+         * ready to restart. At that point, this method will be called again to verify that the
+         * system is ready.
+         *
+         * Multiple calls to an instance of this method may happen for a single restart attempt if
+         * multiple [Condition]s are being checked. If any one [Condition] returns false, all the
+         * [Condition]s will need to be rechecked on the next restart attempt.
+         */
+        fun canRestartNow(retryFn: () -> Unit): Boolean
+    }
+
+    companion object {
+        const val RESTART_DELAY = "restarter_restart_delay"
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java
index 58fe094..367a9b9 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java
@@ -85,9 +85,34 @@
     private final ServerFlagReader.ChangeListener mOnPropertiesChanged =
             new ServerFlagReader.ChangeListener() {
                 @Override
-                public void onChange(Flag<?> flag) {
-                    mRestarter.restartSystemUI(
-                            "Server flag change: " + flag.getNamespace() + "." + flag.getName());
+                public void onChange(Flag<?> flag, String value) {
+                    boolean shouldRestart = false;
+                    if (mBooleanFlagCache.containsKey(flag.getName())) {
+                        boolean newValue = value == null ? false : Boolean.parseBoolean(value);
+                        if (mBooleanFlagCache.get(flag.getName()) != newValue) {
+                            shouldRestart = true;
+                        }
+                    } else if (mStringFlagCache.containsKey(flag.getName())) {
+                        String newValue = value == null ? "" : value;
+                        if (mStringFlagCache.get(flag.getName()) != value) {
+                            shouldRestart = true;
+                        }
+                    } else if (mIntFlagCache.containsKey(flag.getName())) {
+                        int newValue = 0;
+                        try {
+                            newValue = value == null ? 0 : Integer.parseInt(value);
+                        } catch (NumberFormatException e) {
+                        }
+                        if (mIntFlagCache.get(flag.getName()) != newValue) {
+                            shouldRestart = true;
+                        }
+                    }
+                    if (shouldRestart) {
+                        mRestarter.restartSystemUI(
+                                "Server flag change: " + flag.getNamespace() + "."
+                                        + flag.getName());
+
+                    }
                 }
             };
 
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugRestarter.kt b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugRestarter.kt
deleted file mode 100644
index a6956a4..0000000
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugRestarter.kt
+++ /dev/null
@@ -1,70 +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.flags
-
-import android.util.Log
-import com.android.systemui.keyguard.WakefulnessLifecycle
-import javax.inject.Inject
-
-/** Restarts SystemUI when the screen is locked. */
-class FeatureFlagsDebugRestarter
-@Inject
-constructor(
-    private val wakefulnessLifecycle: WakefulnessLifecycle,
-    private val systemExitRestarter: SystemExitRestarter,
-) : Restarter {
-
-    private var androidRestartRequested = false
-    private var pendingReason = ""
-
-    val observer =
-        object : WakefulnessLifecycle.Observer {
-            override fun onFinishedGoingToSleep() {
-                Log.d(FeatureFlagsDebug.TAG, "Restarting due to systemui flag change")
-                restartNow()
-            }
-        }
-
-    override fun restartSystemUI(reason: String) {
-        Log.d(FeatureFlagsDebug.TAG, "SystemUI Restart requested. Restarting on next screen off.")
-        Log.i(FeatureFlagsDebug.TAG, reason)
-        scheduleRestart(reason)
-    }
-
-    override fun restartAndroid(reason: String) {
-        Log.d(FeatureFlagsDebug.TAG, "Android Restart requested. Restarting on next screen off.")
-        androidRestartRequested = true
-        scheduleRestart(reason)
-    }
-
-    fun scheduleRestart(reason: String) {
-        pendingReason = reason
-        if (wakefulnessLifecycle.wakefulness == WakefulnessLifecycle.WAKEFULNESS_ASLEEP) {
-            restartNow()
-        } else {
-            wakefulnessLifecycle.addObserver(observer)
-        }
-    }
-
-    private fun restartNow() {
-        if (androidRestartRequested) {
-            systemExitRestarter.restartAndroid(pendingReason)
-        } else {
-            systemExitRestarter.restartSystemUI(pendingReason)
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugStartable.kt b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugStartable.kt
index 06ca0ad..28c45b8 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugStartable.kt
@@ -22,7 +22,6 @@
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.statusbar.commandline.CommandRegistry
 import com.android.systemui.util.InitializationChecker
-import com.android.systemui.util.concurrency.DelayableExecutor
 import dagger.Binds
 import dagger.Module
 import dagger.multibindings.ClassKey
@@ -38,8 +37,6 @@
     private val featureFlags: FeatureFlagsDebug,
     private val broadcastSender: BroadcastSender,
     private val initializationChecker: InitializationChecker,
-    private val restartDozeListener: RestartDozeListener,
-    private val delayableExecutor: DelayableExecutor
 ) : CoreStartable {
 
     init {
@@ -55,9 +52,6 @@
             // protected broadcast should only be sent for the main process
             val intent = Intent(FlagManager.ACTION_SYSUI_STARTED)
             broadcastSender.sendBroadcast(intent)
-
-            restartDozeListener.init()
-            delayableExecutor.executeDelayed({ restartDozeListener.maybeRestartSleep() }, 1000)
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java
index 9859ff6..9d19a7d 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java
@@ -53,13 +53,38 @@
     private final Map<String, Flag<?>> mAllFlags;
     private final Map<String, Boolean> mBooleanCache = new HashMap<>();
     private final Map<String, String> mStringCache = new HashMap<>();
+    private final Map<String, Integer> mIntCache = new HashMap<>();
 
     private final ServerFlagReader.ChangeListener mOnPropertiesChanged =
             new ServerFlagReader.ChangeListener() {
                 @Override
-                public void onChange(Flag<?> flag) {
-                    mRestarter.restartSystemUI(
-                            "Server flag change: " + flag.getNamespace() + "." + flag.getName());
+                public void onChange(Flag<?> flag, String value) {
+                    boolean shouldRestart = false;
+                    if (mBooleanCache.containsKey(flag.getName())) {
+                        boolean newValue = value == null ? false : Boolean.parseBoolean(value);
+                        if (mBooleanCache.get(flag.getName()) != newValue) {
+                            shouldRestart = true;
+                        }
+                    } else if (mStringCache.containsKey(flag.getName())) {
+                        String newValue = value == null ? "" : value;
+                        if (mStringCache.get(flag.getName()) != newValue) {
+                            shouldRestart = true;
+                        }
+                    } else if (mIntCache.containsKey(flag.getName())) {
+                        int newValue = 0;
+                        try {
+                            newValue = value == null ? 0 : Integer.parseInt(value);
+                        } catch (NumberFormatException e) {
+                        }
+                        if (mIntCache.get(flag.getName()) != newValue) {
+                            shouldRestart = true;
+                        }
+                    }
+                    if (shouldRestart) {
+                        mRestarter.restartSystemUI(
+                                "Server flag change: " + flag.getNamespace() + "."
+                                        + flag.getName());
+                    }
                 }
             };
 
@@ -97,68 +122,97 @@
 
     @Override
     public boolean isEnabled(@NotNull ReleasedFlag flag) {
-        return mServerFlagReader.readServerOverride(flag.getNamespace(), flag.getName(), true);
+        // Fill the cache.
+        return isEnabledInternal(flag.getName(),
+                mServerFlagReader.readServerOverride(flag.getNamespace(), flag.getName(), true));
     }
 
     @Override
     public boolean isEnabled(ResourceBooleanFlag flag) {
-        if (!mBooleanCache.containsKey(flag.getName())) {
-            return isEnabled(flag.getName(), mResources.getBoolean(flag.getResourceId()));
-        }
-
-        return mBooleanCache.get(flag.getName());
+        // Fill the cache.
+        return isEnabledInternal(flag.getName(), mResources.getBoolean(flag.getResourceId()));
     }
 
     @Override
     public boolean isEnabled(SysPropBooleanFlag flag) {
-        if (!mBooleanCache.containsKey(flag.getName())) {
-            return isEnabled(
-                    flag.getName(),
-                    mSystemProperties.getBoolean(flag.getName(), flag.getDefault()));
-        }
-
-        return mBooleanCache.get(flag.getName());
+        // Fill the cache.
+        return isEnabledInternal(
+                flag.getName(),
+                mSystemProperties.getBoolean(flag.getName(), flag.getDefault()));
     }
 
-    private boolean isEnabled(String name, boolean defaultValue) {
-        mBooleanCache.put(name, defaultValue);
-        return defaultValue;
+    /**
+     * Checks and fills the boolean cache. This is important, Always call through to this method!
+     *
+     * We use the cache as a way to decide if we need to restart the process when server-side
+     * changes occur.
+     */
+    private boolean isEnabledInternal(String name, boolean defaultValue) {
+        // Fill the cache.
+        if (!mBooleanCache.containsKey(name)) {
+            mBooleanCache.put(name, defaultValue);
+        }
+
+        return mBooleanCache.get(name);
     }
 
     @NonNull
     @Override
     public String getString(@NonNull StringFlag flag) {
-        return getString(flag.getName(), flag.getDefault());
+        // Fill the cache.
+        return getStringInternal(flag.getName(), flag.getDefault());
     }
 
     @NonNull
     @Override
     public String getString(@NonNull ResourceStringFlag flag) {
-        if (!mStringCache.containsKey(flag.getName())) {
-            return getString(flag.getName(),
-                    requireNonNull(mResources.getString(flag.getResourceId())));
-        }
-
-        return mStringCache.get(flag.getName());
+        // Fill the cache.
+        return getStringInternal(flag.getName(),
+                requireNonNull(mResources.getString(flag.getResourceId())));
     }
 
-    private String getString(String name, String defaultValue) {
-        mStringCache.put(name, defaultValue);
-        return defaultValue;
+    /**
+     * Checks and fills the String cache. This is important, Always call through to this method!
+     *
+     * We use the cache as a way to decide if we need to restart the process when server-side
+     * changes occur.
+     */
+    private String getStringInternal(String name, String defaultValue) {
+        if (!mStringCache.containsKey(name)) {
+            mStringCache.put(name, defaultValue);
+        }
+
+        return mStringCache.get(name);
     }
 
     @NonNull
     @Override
     public int getInt(@NonNull IntFlag flag) {
-        return flag.getDefault();
+        // Fill the cache.
+        return getIntInternal(flag.getName(), flag.getDefault());
     }
 
     @NonNull
     @Override
     public int getInt(@NonNull ResourceIntFlag flag) {
+        // Fill the cache.
         return mResources.getInteger(flag.getResourceId());
     }
 
+    /**
+     * Checks and fills the integer cache. This is important, Always call through to this method!
+     *
+     * We use the cache as a way to decide if we need to restart the process when server-side
+     * changes occur.
+     */
+    private int getIntInternal(String name, int defaultValue) {
+        if (!mIntCache.containsKey(name)) {
+            mIntCache.put(name, defaultValue);
+        }
+
+        return mIntCache.get(name);
+    }
+
     @Override
     public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
         pw.println("can override: false");
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsReleaseRestarter.kt b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsReleaseRestarter.kt
deleted file mode 100644
index c08266c..0000000
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsReleaseRestarter.kt
+++ /dev/null
@@ -1,101 +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.flags
-
-import android.util.Log
-import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.keyguard.WakefulnessLifecycle
-import com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP
-import com.android.systemui.statusbar.policy.BatteryController
-import com.android.systemui.util.concurrency.DelayableExecutor
-import java.util.concurrent.TimeUnit
-import javax.inject.Inject
-
-/** Restarts SystemUI when the device appears idle. */
-class FeatureFlagsReleaseRestarter
-@Inject
-constructor(
-    private val wakefulnessLifecycle: WakefulnessLifecycle,
-    private val batteryController: BatteryController,
-    @Background private val bgExecutor: DelayableExecutor,
-    private val systemExitRestarter: SystemExitRestarter
-) : Restarter {
-    var listenersAdded = false
-    var pendingRestart: Runnable? = null
-    private var pendingReason = ""
-    var androidRestartRequested = false
-
-    val observer =
-        object : WakefulnessLifecycle.Observer {
-            override fun onFinishedGoingToSleep() {
-                scheduleRestart(pendingReason)
-            }
-        }
-
-    val batteryCallback =
-        object : BatteryController.BatteryStateChangeCallback {
-            override fun onBatteryLevelChanged(level: Int, pluggedIn: Boolean, charging: Boolean) {
-                scheduleRestart(pendingReason)
-            }
-        }
-
-    override fun restartSystemUI(reason: String) {
-        Log.d(
-            FeatureFlagsDebug.TAG,
-            "SystemUI Restart requested. Restarting when plugged in and idle."
-        )
-        scheduleRestart(reason)
-    }
-
-    override fun restartAndroid(reason: String) {
-        Log.d(
-            FeatureFlagsDebug.TAG,
-            "Android Restart requested. Restarting when plugged in and idle."
-        )
-        androidRestartRequested = true
-        scheduleRestart(reason)
-    }
-
-    private fun scheduleRestart(reason: String) {
-        // Don't bother adding listeners twice.
-        pendingReason = reason
-        if (!listenersAdded) {
-            listenersAdded = true
-            wakefulnessLifecycle.addObserver(observer)
-            batteryController.addCallback(batteryCallback)
-        }
-        if (
-            wakefulnessLifecycle.wakefulness == WAKEFULNESS_ASLEEP && batteryController.isPluggedIn
-        ) {
-            if (pendingRestart == null) {
-                pendingRestart = bgExecutor.executeDelayed(this::restartNow, 30L, TimeUnit.SECONDS)
-            }
-        } else if (pendingRestart != null) {
-            pendingRestart?.run()
-            pendingRestart = null
-        }
-    }
-
-    private fun restartNow() {
-        Log.d(FeatureFlagsRelease.TAG, "Restarting due to systemui flag change")
-        if (androidRestartRequested) {
-            systemExitRestarter.restartAndroid(pendingReason)
-        } else {
-            systemExitRestarter.restartSystemUI(pendingReason)
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsReleaseStartable.kt b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsReleaseStartable.kt
index 133e67f..f97112d 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsReleaseStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsReleaseStartable.kt
@@ -18,8 +18,6 @@
 
 import com.android.systemui.CoreStartable
 import com.android.systemui.dump.DumpManager
-import com.android.systemui.util.InitializationChecker
-import com.android.systemui.util.concurrency.DelayableExecutor
 import dagger.Binds
 import dagger.Module
 import dagger.multibindings.ClassKey
@@ -31,9 +29,6 @@
 constructor(
     dumpManager: DumpManager,
     featureFlags: FeatureFlags,
-    private val initializationChecker: InitializationChecker,
-    private val restartDozeListener: RestartDozeListener,
-    private val delayableExecutor: DelayableExecutor
 ) : CoreStartable {
 
     init {
@@ -42,12 +37,7 @@
         }
     }
 
-    override fun start() {
-        if (initializationChecker.initializeComponents()) {
-            restartDozeListener.init()
-            delayableExecutor.executeDelayed({ restartDozeListener.maybeRestartSleep() }, 1000)
-        }
-    }
+    override fun start() {}
 }
 
 @Module
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 9b36b92..e47f1ff 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -74,8 +74,12 @@
     val NOTIFICATION_MEMORY_MONITOR_ENABLED =
         releasedFlag(112, "notification_memory_monitor_enabled")
 
+    /**
+     * This flag is server-controlled and should stay as [unreleasedFlag] since we never want to
+     * enable it on release builds.
+     */
     val NOTIFICATION_MEMORY_LOGGING_ENABLED =
-        unreleasedFlag(119, "notification_memory_logging_enabled", teamfood = true)
+        unreleasedFlag(119, "notification_memory_logging_enabled")
 
     // TODO(b/254512731): Tracking Bug
     @JvmField val NOTIFICATION_DISMISSAL_FADE = releasedFlag(113, "notification_dismissal_fade")
@@ -109,6 +113,13 @@
     @JvmField
     val NOTIFICATION_ANIMATE_BIG_PICTURE = unreleasedFlag(120, "notification_animate_big_picture")
 
+    @JvmField
+    val ANIMATED_NOTIFICATION_SHADE_INSETS =
+        unreleasedFlag(270682168, "animated_notification_shade_insets", teamfood = true)
+
+    // TODO(b/268005230): Tracking Bug
+    @JvmField val SENSITIVE_REVEAL_ANIM = unreleasedFlag(268005230, "sensitive_reveal_anim")
+
     // 200 - keyguard/lockscreen
     // ** Flag retired **
     // public static final BooleanFlag KEYGUARD_LAYOUT =
@@ -125,14 +136,14 @@
 
     // TODO(b/254512676): Tracking Bug
     @JvmField
-    val LOCKSCREEN_CUSTOM_CLOCKS = unreleasedFlag(207, "lockscreen_custom_clocks", teamfood = true)
+    val LOCKSCREEN_CUSTOM_CLOCKS = unreleasedFlag(207, "lockscreen_custom_clocks")
 
     /**
      * Whether the clock on a wide lock screen should use the new "stepping" animation for moving
      * the digits when the clock moves.
      */
     @JvmField
-    val STEP_CLOCK_ANIMATION = unreleasedFlag(212, "step_clock_animation", teamfood = true)
+    val STEP_CLOCK_ANIMATION = releasedFlag(212, "step_clock_animation")
 
     /**
      * Migration from the legacy isDozing/dozeAmount paths to the new KeyguardTransitionRepository
@@ -210,6 +221,25 @@
             teamfood = true,
         )
 
+    /** Enables UI updates for AI wallpapers in the wallpaper picker. */
+    // TODO(b/267722622): Tracking Bug
+    @JvmField
+    val WALLPAPER_PICKER_UI_FOR_AIWP =
+            releasedFlag(
+                    229,
+                    "wallpaper_picker_ui_for_aiwp"
+            )
+
+    /** Whether to inflate the bouncer view on a background thread. */
+    // TODO(b/272091103): Tracking Bug
+    @JvmField
+    val ASYNC_INFLATE_BOUNCER = unreleasedFlag(229, "async_inflate_bouncer", teamfood = false)
+
+    /** Whether to inflate the bouncer view on a background thread. */
+    // TODO(b/273341787): Tracking Bug
+    @JvmField
+    val PREVENT_BYPASS_KEYGUARD = unreleasedFlag(230, "prevent_bypass_keyguard")
+
     // 300 - power menu
     // TODO(b/254512600): Tracking Bug
     @JvmField val POWER_MENU_LITE = releasedFlag(300, "power_menu_lite")
@@ -227,7 +257,13 @@
 
     // TODO(b/270223352): Tracking Bug
     @JvmField
-    val HIDE_SMARTSPACE_ON_DREAM_OVERLAY = unreleasedFlag(404, "hide_smartspace_on_dream_overlay")
+    val HIDE_SMARTSPACE_ON_DREAM_OVERLAY =
+        releasedFlag(404, "hide_smartspace_on_dream_overlay")
+
+    // TODO(b/271460958): Tracking Bug
+    @JvmField
+    val SHOW_WEATHER_COMPLICATION_ON_DREAM_OVERLAY =
+        releasedFlag(405, "show_weather_complication_on_dream_overlay")
 
     // 500 - quick settings
 
@@ -295,7 +331,8 @@
         unreleasedFlag(611, "new_status_bar_icons_debug_coloring")
 
     // TODO(b/265892345): Tracking Bug
-    val PLUG_IN_STATUS_BAR_CHIP = unreleasedFlag(265892345, "plug_in_status_bar_chip")
+    val PLUG_IN_STATUS_BAR_CHIP =
+            unreleasedFlag(265892345, "plug_in_status_bar_chip", teamfood = true)
 
     // 700 - dialer/calls
     // TODO(b/254512734): Tracking Bug
@@ -380,13 +417,21 @@
     @JvmField val ROUNDED_BOX_RIPPLE = releasedFlag(1002, "rounded_box_ripple")
 
     // TODO(b/270882464): Tracking Bug
-    val ENABLE_DOCK_SETUP_V2 = unreleasedFlag(1005, "enable_dock_setup_v2")
+    val ENABLE_DOCK_SETUP_V2 = releasedFlag(1005, "enable_dock_setup_v2")
 
     // TODO(b/265045965): Tracking Bug
     val SHOW_LOWLIGHT_ON_DIRECT_BOOT = releasedFlag(1003, "show_lowlight_on_direct_boot")
 
     @JvmField
-    val ENABLE_LOW_LIGHT_CLOCK_UNDOCKED = unreleasedFlag(1004, "enable_low_light_clock_undocked")
+    // TODO(b/271428141): Tracking Bug
+    val ENABLE_LOW_LIGHT_CLOCK_UNDOCKED = unreleasedFlag(
+        1004,
+        "enable_low_light_clock_undocked", teamfood = true)
+
+    // TODO(b/273509374): Tracking Bug
+    @JvmField
+    val ALWAYS_SHOW_HOME_CONTROLS_ON_DREAMS = unreleasedFlag(1006,
+        "always_show_home_controls_on_dreams")
 
     // 1100 - windowing
     @Keep
@@ -437,11 +482,13 @@
         sysPropBooleanFlag(
             1110,
             "persist.wm.debug.enable_pip_keep_clear_algorithm",
-            default = false
+            default = true
         )
 
     // TODO(b/256873975): Tracking Bug
-    @JvmField @Keep val WM_BUBBLE_BAR = unreleasedFlag(1111, "wm_bubble_bar")
+    @JvmField
+    @Keep
+    val WM_BUBBLE_BAR = sysPropBooleanFlag(1111, "persist.wm.debug.bubble_bar", default = false)
 
     // TODO(b/260271148): Tracking bug
     @Keep
@@ -470,7 +517,14 @@
     @Keep
     @JvmField
     val ENABLE_PIP_APP_ICON_OVERLAY =
-        sysPropBooleanFlag(1115, "persist.wm.debug.enable_pip_app_icon_overlay", default = false)
+        sysPropBooleanFlag(1115, "persist.wm.debug.enable_pip_app_icon_overlay", default = true)
+
+    // TODO(b/272110828): Tracking bug
+    @Keep
+    @JvmField
+    val ENABLE_MOVE_FLOATING_WINDOW_IN_TABLETOP =
+        sysPropBooleanFlag(
+            1116, "persist.wm.debug.enable_move_floating_window_in_tabletop", default = true)
 
     // 1200 - predictive back
     @Keep
@@ -547,7 +601,7 @@
 
     // 1500 - chooser aka sharesheet
     // TODO(b/254512507): Tracking Bug
-    val CHOOSER_UNBUNDLED = releasedFlag(1500, "chooser_unbundled")
+    val CHOOSER_UNBUNDLED = unreleasedFlag(1500, "chooser_unbundled")
 
     // TODO(b/266983432) Tracking Bug
     val SHARESHEET_CUSTOM_ACTIONS =
@@ -580,7 +634,7 @@
     @JvmField
     val LEAVE_SHADE_OPEN_FOR_BUGREPORT = releasedFlag(1800, "leave_shade_open_for_bugreport")
     // TODO(b/265944639): Tracking Bug
-    @JvmField val DUAL_SHADE = releasedFlag(1801, "dual_shade")
+    @JvmField val DUAL_SHADE = unreleasedFlag(1801, "dual_shade")
 
     // 1900
     @JvmField val NOTE_TASKS = unreleasedFlag(1900, "keycode_flag")
@@ -613,7 +667,7 @@
 
     // 2300 - stylus
     @JvmField
-    val TRACK_STYLUS_EVER_USED = unreleasedFlag(2300, "track_stylus_ever_used", teamfood = true)
+    val TRACK_STYLUS_EVER_USED = releasedFlag(2300, "track_stylus_ever_used")
     @JvmField val ENABLE_STYLUS_CHARGING_UI = unreleasedFlag(2301, "enable_stylus_charging_ui")
     @JvmField
     val ENABLE_USI_BATTERY_NOTIFICATIONS = unreleasedFlag(2302, "enable_usi_battery_notifications")
@@ -642,6 +696,12 @@
     val ENABLE_DARK_VIGNETTE_WHEN_FOLDING =
         unreleasedFlag(2700, "enable_dark_vignette_when_folding")
 
+    // TODO(b/265764985): Tracking Bug
+    @Keep
+    @JvmField
+    val ENABLE_UNFOLD_STATUS_BAR_ANIMATIONS =
+        unreleasedFlag(2701, "enable_unfold_status_bar_animations")
+
     // TODO(b259590361): Tracking bug
     val EXPERIMENTAL_FLAG = unreleasedFlag(2, "exp_flag_release")
 
@@ -652,4 +712,14 @@
     // TODO(b/259428678): Tracking Bug
     @JvmField
     val KEYBOARD_BACKLIGHT_INDICATOR = unreleasedFlag(2601, "keyboard_backlight_indicator")
+
+    // TODO(b/272036292): Tracking Bug
+    @JvmField
+    val LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION =
+            unreleasedFlag(2602, "large_shade_granular_alpha_interpolation", teamfood = true)
+
+    // TODO(b/272805037): Tracking Bug
+    @JvmField
+    val ADVANCED_VPN_ENABLED = unreleasedFlag(2800, name = "AdvancedVpn__enable_feature",
+            namespace = "vpn", teamfood = false)
 }
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagsCommonModule.kt b/packages/SystemUI/src/com/android/systemui/flags/FlagsCommonModule.kt
index 0054d26..3c50125 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FlagsCommonModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/FlagsCommonModule.kt
@@ -15,6 +15,7 @@
  */
 package com.android.systemui.flags
 
+import dagger.Binds
 import dagger.Module
 import dagger.Provides
 import javax.inject.Named
@@ -22,6 +23,8 @@
 /** Module containing shared code for all FeatureFlag implementations. */
 @Module
 interface FlagsCommonModule {
+    @Binds fun bindsRestarter(impl: ConditionalRestarter): Restarter
+
     companion object {
         const val ALL_FLAGS = "all_flags"
 
diff --git a/packages/SystemUI/src/com/android/systemui/flags/PluggedInCondition.kt b/packages/SystemUI/src/com/android/systemui/flags/PluggedInCondition.kt
new file mode 100644
index 0000000..3120638
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/flags/PluggedInCondition.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.flags
+
+import com.android.systemui.statusbar.policy.BatteryController
+import javax.inject.Inject
+
+/** Returns true when the device is plugged in. */
+class PluggedInCondition
+@Inject
+constructor(
+    private val batteryController: BatteryController,
+) : ConditionalRestarter.Condition {
+
+    var listenersAdded = false
+    var retryFn: (() -> Unit)? = null
+
+    val batteryCallback =
+        object : BatteryController.BatteryStateChangeCallback {
+            override fun onBatteryLevelChanged(level: Int, pluggedIn: Boolean, charging: Boolean) {
+                retryFn?.invoke()
+            }
+        }
+
+    override fun canRestartNow(retryFn: () -> Unit): Boolean {
+        if (!listenersAdded) {
+            listenersAdded = true
+            batteryController.addCallback(batteryCallback)
+        }
+
+        this.retryFn = retryFn
+
+        return batteryController.isPluggedIn
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/RestartDozeListener.kt b/packages/SystemUI/src/com/android/systemui/flags/RestartDozeListener.kt
index bd74f4e..dc0de2c 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/RestartDozeListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/RestartDozeListener.kt
@@ -20,7 +20,9 @@
 import android.util.Log
 import com.android.internal.annotations.VisibleForTesting
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.util.concurrency.DelayableExecutor
 import com.android.systemui.util.settings.SecureSettings
 import com.android.systemui.util.time.SystemClock
 import javax.inject.Inject
@@ -33,18 +35,19 @@
     private val statusBarStateController: StatusBarStateController,
     private val powerManager: PowerManager,
     private val systemClock: SystemClock,
+    @Background val bgExecutor: DelayableExecutor,
 ) {
 
     companion object {
-        @VisibleForTesting val RESTART_NAP_KEY = "restart_nap_after_start"
+        @VisibleForTesting val RESTART_SLEEP_KEY = "restart_nap_after_start"
     }
 
     private var inited = false
 
     val listener =
         object : StatusBarStateController.StateListener {
-            override fun onDreamingChanged(isDreaming: Boolean) {
-                settings.putBool(RESTART_NAP_KEY, isDreaming)
+            override fun onDozingChanged(isDozing: Boolean) {
+                storeSleepState(isDozing)
             }
         }
 
@@ -62,11 +65,23 @@
     }
 
     fun maybeRestartSleep() {
-        if (settings.getBool(RESTART_NAP_KEY, false)) {
-            Log.d("RestartDozeListener", "Restarting sleep state")
-            powerManager.wakeUp(systemClock.uptimeMillis())
-            powerManager.goToSleep(systemClock.uptimeMillis())
-            settings.putBool(RESTART_NAP_KEY, false)
-        }
+        bgExecutor.executeDelayed(
+            {
+                if (settings.getBool(RESTART_SLEEP_KEY, false)) {
+                    Log.d("RestartDozeListener", "Restarting sleep state")
+                    powerManager.wakeUp(
+                        systemClock.uptimeMillis(),
+                        PowerManager.WAKE_REASON_APPLICATION,
+                        "RestartDozeListener"
+                    )
+                    powerManager.goToSleep(systemClock.uptimeMillis())
+                }
+            },
+            1000
+        )
+    }
+
+    private fun storeSleepState(sleeping: Boolean) {
+        bgExecutor.execute { settings.putBool(RESTART_SLEEP_KEY, sleeping) }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/flags/ScreenIdleCondition.kt b/packages/SystemUI/src/com/android/systemui/flags/ScreenIdleCondition.kt
new file mode 100644
index 0000000..49e61af
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/flags/ScreenIdleCondition.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.flags
+
+import com.android.systemui.keyguard.WakefulnessLifecycle
+import javax.inject.Inject
+
+/** Returns true when the device is "asleep" as defined by the [WakefullnessLifecycle]. */
+class ScreenIdleCondition
+@Inject
+constructor(
+    private val wakefulnessLifecycle: WakefulnessLifecycle,
+) : ConditionalRestarter.Condition {
+
+    var listenersAdded = false
+    var retryFn: (() -> Unit)? = null
+
+    val observer =
+        object : WakefulnessLifecycle.Observer {
+            override fun onFinishedGoingToSleep() {
+                retryFn?.invoke()
+            }
+        }
+
+    override fun canRestartNow(retryFn: () -> Unit): Boolean {
+        if (!listenersAdded) {
+            listenersAdded = true
+            wakefulnessLifecycle.addObserver(observer)
+        }
+
+        this.retryFn = retryFn
+
+        return wakefulnessLifecycle.wakefulness == WakefulnessLifecycle.WAKEFULNESS_ASLEEP
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/ServerFlagReader.kt b/packages/SystemUI/src/com/android/systemui/flags/ServerFlagReader.kt
index 9b748d0..eaf5eac 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/ServerFlagReader.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/ServerFlagReader.kt
@@ -37,7 +37,7 @@
     fun listenForChanges(values: Collection<Flag<*>>, listener: ChangeListener)
 
     interface ChangeListener {
-        fun onChange(flag: Flag<*>)
+        fun onChange(flag: Flag<*>, value: String?)
     }
 }
 
@@ -67,7 +67,7 @@
                 propLoop@ for (propName in properties.keyset) {
                     for (flag in flags) {
                         if (propName == flag.name) {
-                            listener.onChange(flag)
+                            listener.onChange(flag, properties.getString(propName, null))
                             break@propLoop
                         }
                     }
@@ -144,7 +144,7 @@
         for ((listener, flags) in listeners) {
             flagLoop@ for (flag in flags) {
                 if (name == flag.name) {
-                    listener.onChange(flag)
+                    listener.onChange(flag, if (value) "true" else "false")
                     break@flagLoop
                 }
             }
@@ -159,5 +159,6 @@
         flags: Collection<Flag<*>>,
         listener: ServerFlagReader.ChangeListener
     ) {
+        listeners.add(Pair(listener, flags))
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/PhysicalKeyboardCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/keyboard/PhysicalKeyboardCoreStartable.kt
index b0f9c4e..d078688 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/PhysicalKeyboardCoreStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/PhysicalKeyboardCoreStartable.kt
@@ -21,6 +21,7 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
+import com.android.systemui.keyboard.backlight.ui.KeyboardBacklightDialogCoordinator
 import javax.inject.Inject
 
 /** A [CoreStartable] that launches components interested in physical keyboard interaction. */
@@ -28,11 +29,12 @@
 class PhysicalKeyboardCoreStartable
 @Inject
 constructor(
+    private val keyboardBacklightDialogCoordinator: KeyboardBacklightDialogCoordinator,
     private val featureFlags: FeatureFlags,
 ) : CoreStartable {
     override fun start() {
         if (featureFlags.isEnabled(Flags.KEYBOARD_BACKLIGHT_INDICATOR)) {
-            // TODO(b/268645743) start listening for keyboard backlight brightness
+            keyboardBacklightDialogCoordinator.startListening()
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractor.kt
new file mode 100644
index 0000000..65e70b3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractor.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyboard.backlight.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyboard.data.repository.KeyboardRepository
+import com.android.systemui.keyboard.shared.model.BacklightModel
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
+
+/** Allows listening to changes to keyboard backlight level */
+@SysUISingleton
+class KeyboardBacklightInteractor
+@Inject
+constructor(
+    private val keyboardRepository: KeyboardRepository,
+) {
+
+    /** Emits current backlight level as [BacklightModel] or null if keyboard is not connected */
+    val backlight: Flow<BacklightModel?> =
+        keyboardRepository.keyboardConnected.flatMapLatest { connected ->
+            if (connected) keyboardRepository.backlight else flowOf(null)
+        }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/KeyboardBacklightDialogCoordinator.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/KeyboardBacklightDialogCoordinator.kt
new file mode 100644
index 0000000..5e806b6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/KeyboardBacklightDialogCoordinator.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyboard.backlight.ui
+
+import android.content.Context
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.keyboard.backlight.ui.view.KeyboardBacklightDialog
+import com.android.systemui.keyboard.backlight.ui.viewmodel.BacklightDialogViewModel
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+/**
+ * Based on the state produced from [BacklightDialogViewModel] shows or hides keyboard backlight
+ * indicator
+ */
+@SysUISingleton
+class KeyboardBacklightDialogCoordinator
+@Inject
+constructor(
+    @Application private val applicationScope: CoroutineScope,
+    private val context: Context,
+    private val viewModel: BacklightDialogViewModel,
+) {
+
+    var dialog: KeyboardBacklightDialog? = null
+
+    fun startListening() {
+        applicationScope.launch {
+            viewModel.dialogContent.collect { dialogViewModel ->
+                if (dialogViewModel != null) {
+                    if (dialog == null) {
+                        dialog =
+                            KeyboardBacklightDialog(
+                                context,
+                                initialCurrentLevel = dialogViewModel.currentValue,
+                                initialMaxLevel = dialogViewModel.maxValue
+                            )
+                        dialog?.show()
+                    } else {
+                        dialog?.updateState(dialogViewModel.currentValue, dialogViewModel.maxValue)
+                    }
+                } else {
+                    dialog?.dismiss()
+                    dialog = null
+                }
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt
new file mode 100644
index 0000000..a173f8b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyboard.backlight.ui.view
+
+import android.annotation.ColorInt
+import android.app.Dialog
+import android.content.Context
+import android.graphics.drawable.ShapeDrawable
+import android.graphics.drawable.shapes.RoundRectShape
+import android.os.Bundle
+import android.view.Gravity
+import android.view.Window
+import android.view.WindowManager
+import android.widget.FrameLayout
+import android.widget.ImageView
+import android.widget.LinearLayout
+import android.widget.LinearLayout.LayoutParams
+import android.widget.LinearLayout.LayoutParams.WRAP_CONTENT
+import com.android.systemui.R
+import com.android.systemui.util.children
+
+class KeyboardBacklightDialog(
+    context: Context,
+    initialCurrentLevel: Int,
+    initialMaxLevel: Int,
+) : Dialog(context) {
+
+    private data class RootProperties(
+        val cornerRadius: Float,
+        val verticalPadding: Int,
+        val horizontalPadding: Int,
+    )
+
+    private data class BacklightIconProperties(
+        val width: Int,
+        val height: Int,
+        val leftMargin: Int,
+    )
+
+    private data class StepViewProperties(
+        val width: Int,
+        val height: Int,
+        val horizontalMargin: Int,
+        val smallRadius: Float,
+        val largeRadius: Float,
+    )
+
+    private var currentLevel: Int = 0
+    private var maxLevel: Int = 0
+
+    private lateinit var rootView: LinearLayout
+
+    private var dialogBottomMargin = 208
+    private lateinit var rootProperties: RootProperties
+    private lateinit var iconProperties: BacklightIconProperties
+    private lateinit var stepProperties: StepViewProperties
+    @ColorInt var filledRectangleColor: Int = 0
+    @ColorInt var emptyRectangleColor: Int = 0
+    @ColorInt var backgroundColor: Int = 0
+
+    init {
+        currentLevel = initialCurrentLevel
+        maxLevel = initialMaxLevel
+    }
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        setUpWindowProperties(this)
+        setWindowTitle()
+        updateResources()
+        rootView = buildRootView()
+        setContentView(rootView)
+        super.onCreate(savedInstanceState)
+        updateState(currentLevel, maxLevel, forceRefresh = true)
+    }
+
+    private fun updateResources() {
+        context.resources.apply {
+            filledRectangleColor = getColor(R.color.backlight_indicator_step_filled)
+            emptyRectangleColor = getColor(R.color.backlight_indicator_step_empty)
+            backgroundColor = getColor(R.color.backlight_indicator_background)
+            rootProperties =
+                RootProperties(
+                    cornerRadius =
+                        getDimensionPixelSize(R.dimen.backlight_indicator_root_corner_radius)
+                            .toFloat(),
+                    verticalPadding =
+                        getDimensionPixelSize(R.dimen.backlight_indicator_root_vertical_padding),
+                    horizontalPadding =
+                        getDimensionPixelSize(R.dimen.backlight_indicator_root_horizontal_padding)
+                )
+            iconProperties =
+                BacklightIconProperties(
+                    width = getDimensionPixelSize(R.dimen.backlight_indicator_icon_width),
+                    height = getDimensionPixelSize(R.dimen.backlight_indicator_icon_height),
+                    leftMargin =
+                        getDimensionPixelSize(R.dimen.backlight_indicator_icon_left_margin),
+                )
+            stepProperties =
+                StepViewProperties(
+                    width = getDimensionPixelSize(R.dimen.backlight_indicator_step_width),
+                    height = getDimensionPixelSize(R.dimen.backlight_indicator_step_height),
+                    horizontalMargin =
+                        getDimensionPixelSize(R.dimen.backlight_indicator_step_horizontal_margin),
+                    smallRadius =
+                        getDimensionPixelSize(R.dimen.backlight_indicator_step_small_radius)
+                            .toFloat(),
+                    largeRadius =
+                        getDimensionPixelSize(R.dimen.backlight_indicator_step_large_radius)
+                            .toFloat(),
+                )
+        }
+    }
+
+    fun updateState(current: Int, max: Int, forceRefresh: Boolean = false) {
+        if (maxLevel != max || forceRefresh) {
+            maxLevel = max
+            rootView.removeAllViews()
+            buildStepViews().forEach { rootView.addView(it) }
+        }
+        currentLevel = current
+        updateLevel()
+    }
+
+    private fun updateLevel() {
+        rootView.children.forEachIndexed(
+            action = { index, v ->
+                val drawable = v.background as ShapeDrawable
+                if (index <= currentLevel) {
+                    updateColor(drawable, filledRectangleColor)
+                } else {
+                    updateColor(drawable, emptyRectangleColor)
+                }
+            }
+        )
+    }
+
+    private fun updateColor(drawable: ShapeDrawable, @ColorInt color: Int) {
+        if (drawable.paint.color != color) {
+            drawable.paint.color = color
+            drawable.invalidateSelf()
+        }
+    }
+
+    private fun buildRootView(): LinearLayout {
+        val linearLayout =
+            LinearLayout(context).apply {
+                orientation = LinearLayout.HORIZONTAL
+                layoutParams = LayoutParams(WRAP_CONTENT, WRAP_CONTENT)
+                setPadding(
+                    /* left= */ rootProperties.horizontalPadding,
+                    /* top= */ rootProperties.verticalPadding,
+                    /* right= */ rootProperties.horizontalPadding,
+                    /* bottom= */ rootProperties.verticalPadding
+                )
+            }
+        val drawable =
+            ShapeDrawable(
+                RoundRectShape(
+                    /* outerRadii= */ FloatArray(8) { rootProperties.cornerRadius },
+                    /* inset= */ null,
+                    /* innerRadii= */ null
+                )
+            )
+        drawable.paint.color = backgroundColor
+        linearLayout.background = drawable
+        return linearLayout
+    }
+
+    private fun buildStepViews(): List<FrameLayout> {
+        val stepViews = (0..maxLevel).map { i -> createStepViewAt(i) }
+        stepViews[0].addView(createBacklightIconView())
+        return stepViews
+    }
+
+    private fun createStepViewAt(i: Int): FrameLayout {
+        return FrameLayout(context).apply {
+            layoutParams =
+                FrameLayout.LayoutParams(stepProperties.width, stepProperties.height).apply {
+                    setMargins(
+                        /* left= */ stepProperties.horizontalMargin,
+                        /* top= */ 0,
+                        /* right= */ stepProperties.horizontalMargin,
+                        /* bottom= */ 0
+                    )
+                }
+            val drawable =
+                ShapeDrawable(
+                    RoundRectShape(
+                        /* outerRadii= */ radiiForIndex(i, maxLevel),
+                        /* inset= */ null,
+                        /* innerRadii= */ null
+                    )
+                )
+            drawable.paint.color = emptyRectangleColor
+            background = drawable
+        }
+    }
+
+    private fun createBacklightIconView(): ImageView {
+        return ImageView(context).apply {
+            setImageResource(R.drawable.ic_keyboard_backlight)
+            layoutParams =
+                FrameLayout.LayoutParams(iconProperties.width, iconProperties.height).apply {
+                    gravity = Gravity.CENTER
+                    leftMargin = iconProperties.leftMargin
+                }
+        }
+    }
+
+    private fun setWindowTitle() {
+        val attrs = window.attributes
+        // TODO(b/271796169): check if title needs to be a translatable resource.
+        attrs.title = "KeyboardBacklightDialog"
+        attrs?.y = dialogBottomMargin
+        window.attributes = attrs
+    }
+
+    private fun setUpWindowProperties(dialog: Dialog) {
+        val window = dialog.window
+        window.requestFeature(Window.FEATURE_NO_TITLE) // otherwise fails while creating actionBar
+        window.setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL)
+        window.addFlags(
+            WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM or
+                WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
+        )
+        window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
+        window.setBackgroundDrawableResource(android.R.color.transparent)
+        window.setGravity(Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL)
+        setCanceledOnTouchOutside(true)
+    }
+
+    private fun radiiForIndex(i: Int, last: Int): FloatArray {
+        val smallRadius = stepProperties.smallRadius
+        val largeRadius = stepProperties.largeRadius
+        return when (i) {
+            0 -> // left radii bigger
+            floatArrayOf(
+                    largeRadius,
+                    largeRadius,
+                    smallRadius,
+                    smallRadius,
+                    smallRadius,
+                    smallRadius,
+                    largeRadius,
+                    largeRadius
+                )
+            last -> // right radii bigger
+            floatArrayOf(
+                    smallRadius,
+                    smallRadius,
+                    largeRadius,
+                    largeRadius,
+                    largeRadius,
+                    largeRadius,
+                    smallRadius,
+                    smallRadius
+                )
+            else -> FloatArray(8) { smallRadius } // all radii equal
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/data/model/BacklightModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogContentViewModel.kt
similarity index 68%
copy from packages/SystemUI/src/com/android/systemui/keyboard/data/model/BacklightModel.kt
copy to packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogContentViewModel.kt
index ea15a9f..3ef0ca3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/data/model/BacklightModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogContentViewModel.kt
@@ -15,10 +15,6 @@
  *
  */
 
-package com.android.systemui.keyboard.data.model
+package com.android.systemui.keyboard.backlight.ui.viewmodel
 
-/**
- * Model for current state of keyboard backlight brightness. [level] indicates current level of
- * backlight brightness and [maxLevel] its max possible value.
- */
-data class BacklightModel(val level: Int, val maxLevel: Int)
+data class BacklightDialogContentViewModel(val currentValue: Int, val maxValue: Int)
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModel.kt
new file mode 100644
index 0000000..86abca5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModel.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyboard.backlight.ui.viewmodel
+
+import android.view.accessibility.AccessibilityManager
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyboard.backlight.domain.interactor.KeyboardBacklightInteractor
+import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper
+import javax.inject.Inject
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.flow.map
+
+/**
+ * Responsible for dialog visibility and content - emits [BacklightDialogContentViewModel] if dialog
+ * should be shown and hidden otherwise
+ */
+@SysUISingleton
+class BacklightDialogViewModel
+@Inject
+constructor(
+    interactor: KeyboardBacklightInteractor,
+    private val accessibilityManagerWrapper: AccessibilityManagerWrapper,
+) {
+
+    private val timeoutMillis: Long
+        get() =
+            accessibilityManagerWrapper
+                .getRecommendedTimeoutMillis(
+                    DEFAULT_DIALOG_TIMEOUT_MILLIS,
+                    AccessibilityManager.FLAG_CONTENT_ICONS
+                )
+                .toLong()
+
+    val dialogContent: Flow<BacklightDialogContentViewModel?> =
+        interactor.backlight
+            .filterNotNull()
+            .map { BacklightDialogContentViewModel(it.level, it.maxLevel) }
+            .timeout(timeoutMillis, emitAfterTimeout = null)
+
+    private fun <T> Flow<T>.timeout(timeoutMillis: Long, emitAfterTimeout: T): Flow<T> {
+        return flatMapLatest {
+            flow {
+                emit(it)
+                delay(timeoutMillis)
+                emit(emitAfterTimeout)
+            }
+        }
+    }
+
+    private companion object {
+        const val DEFAULT_DIALOG_TIMEOUT_MILLIS = 3000
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/data/repository/KeyboardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyboard/data/repository/KeyboardRepository.kt
index 70faf40..9449ece 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/data/repository/KeyboardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/data/repository/KeyboardRepository.kt
@@ -23,7 +23,7 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.keyboard.data.model.BacklightModel
+import com.android.systemui.keyboard.shared.model.BacklightModel
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/data/model/BacklightModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shared/model/BacklightModel.kt
similarity index 94%
rename from packages/SystemUI/src/com/android/systemui/keyboard/data/model/BacklightModel.kt
rename to packages/SystemUI/src/com/android/systemui/keyboard/shared/model/BacklightModel.kt
index ea15a9f..4a32f79 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/data/model/BacklightModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shared/model/BacklightModel.kt
@@ -15,7 +15,7 @@
  *
  */
 
-package com.android.systemui.keyboard.data.model
+package com.android.systemui.keyboard.shared.model
 
 /**
  * Model for current state of keyboard backlight brightness. [level] indicates current level of
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index 8ae171f..90562dc 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -380,10 +380,7 @@
                 // If the launcher is underneath, but we're about to launch an activity, don't do
                 // the animations since they won't be visible.
                 !notificationShadeWindowController.isLaunchingActivity &&
-                launcherUnlockController != null &&
-                // Temporarily disable for foldables since foldable launcher has two first pages,
-                // which breaks the in-window animation.
-                !isFoldable(context)
+                launcherUnlockController != null
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index d914bf5..8bd9673 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -117,6 +117,7 @@
 import com.android.systemui.CoreStartable;
 import com.android.systemui.DejankUtils;
 import com.android.systemui.Dumpable;
+import com.android.systemui.EventLogTags;
 import com.android.systemui.R;
 import com.android.systemui.animation.ActivityLaunchAnimator;
 import com.android.systemui.animation.Interpolators;
@@ -964,13 +965,24 @@
                 public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
                         RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
                         IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException {
+                    if (!handleOnAnimationStart(
+                                transit, apps, wallpapers, nonApps, finishedCallback)) {
+                        // Usually we rely on animation completion to synchronize occluded status,
+                        // but there was no animation to play, so just update it now.
+                        setOccluded(true /* isOccluded */, false /* animate */);
+                    }
+                }
+
+                private boolean handleOnAnimationStart(int transit, RemoteAnimationTarget[] apps,
+                        RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
+                        IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException {
                     if (apps == null || apps.length == 0 || apps[0] == null) {
                         if (DEBUG) {
                             Log.d(TAG, "No apps provided to the OccludeByDream runner; "
                                     + "skipping occluding animation.");
                         }
                         finishedCallback.onAnimationFinished();
-                        return;
+                        return false;
                     }
 
                     final RemoteAnimationTarget primary = apps[0];
@@ -980,7 +992,7 @@
                         Log.w(TAG, "The occluding app isn't Dream; "
                                 + "finishing up. Please check that the config is correct.");
                         finishedCallback.onAnimationFinished();
-                        return;
+                        return false;
                     }
 
                     final SyncRtSurfaceTransactionApplier applier =
@@ -1029,6 +1041,7 @@
 
                         mOccludeByDreamAnimator.start();
                     });
+                    return true;
                 }
             };
 
@@ -1840,6 +1853,8 @@
     private void handleSetOccluded(boolean isOccluded, boolean animate) {
         Trace.beginSection("KeyguardViewMediator#handleSetOccluded");
         Log.d(TAG, "handleSetOccluded(" + isOccluded + ")");
+        EventLogTags.writeSysuiKeyguard(isOccluded ? 1 : 0, animate ? 1 : 0);
+
         mInteractionJankMonitor.cancel(CUJ_LOCKSCREEN_TRANSITION_FROM_AOD);
 
         synchronized (KeyguardViewMediator.this) {
@@ -1920,20 +1935,24 @@
 
         // If the keyguard is already showing, see if we don't need to bother re-showing it. Check
         // flags in both files to account for the hiding animation which results in a delay and
-        // discrepancy between flags.
+        // discrepancy between flags. If we're in the middle of hiding, do not short circuit so that
+        // we explicitly re-set state.
         if (mShowing && mKeyguardStateController.isShowing()) {
-            if (mPM.isInteractive()) {
+            if (mPM.isInteractive() && !mHiding) {
                 // It's already showing, and we're not trying to show it while the screen is off.
                 // We can simply reset all of the views.
-                if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing");
+                if (DEBUG) Log.d(TAG, "doKeyguard: not showing (instead, resetting) because it is "
+                        + "already showing, we're interactive, and we were not previously hiding. "
+                        + "It should be safe to short-circuit here.");
                 resetStateLocked();
                 return;
             } else {
-                // We are trying to show the keyguard while the screen is off - this results from
-                // race conditions involving locking while unlocking. Don't short-circuit here and
-                // ensure the keyguard is fully re-shown.
+                // We are trying to show the keyguard while the screen is off or while we were in
+                // the middle of hiding - this results from race conditions involving locking while
+                // unlocking. Don't short-circuit here and ensure the keyguard is fully re-shown.
                 Log.e(TAG,
-                        "doKeyguard: already showing, but re-showing since we're not interactive");
+                        "doKeyguard: already showing, but re-showing because we're interactive or "
+                                + "were in the middle of hiding.");
             }
         }
 
@@ -2427,11 +2446,19 @@
                 if (DEBUG) Log.d(TAG, "handleShow");
             }
 
-            mHiding = false;
             mKeyguardExitAnimationRunner = null;
             mWakeAndUnlocking = false;
             setPendingLock(false);
-            setShowingLocked(true);
+
+            // Force if we we're showing in the middle of hiding, to ensure we end up in the correct
+            // state.
+            setShowingLocked(true, mHiding /* force */);
+            if (mHiding) {
+                Log.d(TAG, "Forcing setShowingLocked because mHiding=true, which means we're "
+                        + "showing in the middle of hiding.");
+            }
+            mHiding = false;
+
             mKeyguardViewControllerLazy.get().show(options);
             resetKeyguardDonePendingLocked();
             mHideAnimationRun = false;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/BouncerView.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/BouncerView.kt
index faeb485..871a3ff 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/BouncerView.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/BouncerView.kt
@@ -52,6 +52,8 @@
         cancelAction: Runnable?,
     )
     fun willDismissWithActions(): Boolean
+    fun willRunDismissFromKeyguard(): Boolean
     /** @return the {@link OnBackAnimationCallback} to animate Bouncer during a back gesture. */
     fun getBackCallback(): OnBackAnimationCallback
+    fun showPromptReason(reason: Int)
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt
index 86e5cd7..ae5b799 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt
@@ -22,7 +22,6 @@
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN
 import com.android.systemui.keyguard.shared.model.BouncerShowMessageModel
-import com.android.systemui.keyguard.shared.model.KeyguardBouncerModel
 import com.android.systemui.log.dagger.BouncerLog
 import com.android.systemui.log.table.TableLogBuffer
 import com.android.systemui.log.table.logDiffsForTable
@@ -43,10 +42,8 @@
  */
 interface KeyguardBouncerRepository {
     /** Values associated with the PrimaryBouncer (pin/pattern/password) input. */
-    val primaryBouncerVisible: StateFlow<Boolean>
-    val primaryBouncerShow: StateFlow<KeyguardBouncerModel?>
+    val primaryBouncerShow: StateFlow<Boolean>
     val primaryBouncerShowingSoon: StateFlow<Boolean>
-    val primaryBouncerHide: StateFlow<Boolean>
     val primaryBouncerStartingToHide: StateFlow<Boolean>
     val primaryBouncerStartingDisappearAnimation: StateFlow<Runnable?>
     /** Determines if we want to instantaneously show the primary bouncer instead of translating. */
@@ -76,14 +73,10 @@
 
     fun setPrimaryScrimmed(isScrimmed: Boolean)
 
-    fun setPrimaryVisible(isVisible: Boolean)
-
-    fun setPrimaryShow(keyguardBouncerModel: KeyguardBouncerModel?)
+    fun setPrimaryShow(isShowing: Boolean)
 
     fun setPrimaryShowingSoon(showingSoon: Boolean)
 
-    fun setPrimaryHide(hide: Boolean)
-
     fun setPrimaryStartingToHide(startingToHide: Boolean)
 
     fun setPrimaryStartDisappearAnimation(runnable: Runnable?)
@@ -117,14 +110,10 @@
     @BouncerLog private val buffer: TableLogBuffer,
 ) : KeyguardBouncerRepository {
     /** Values associated with the PrimaryBouncer (pin/pattern/password) input. */
-    private val _primaryBouncerVisible = MutableStateFlow(false)
-    override val primaryBouncerVisible = _primaryBouncerVisible.asStateFlow()
-    private val _primaryBouncerShow = MutableStateFlow<KeyguardBouncerModel?>(null)
+    private val _primaryBouncerShow = MutableStateFlow(false)
     override val primaryBouncerShow = _primaryBouncerShow.asStateFlow()
     private val _primaryBouncerShowingSoon = MutableStateFlow(false)
     override val primaryBouncerShowingSoon = _primaryBouncerShowingSoon.asStateFlow()
-    private val _primaryBouncerHide = MutableStateFlow(false)
-    override val primaryBouncerHide = _primaryBouncerHide.asStateFlow()
     private val _primaryBouncerStartingToHide = MutableStateFlow(false)
     override val primaryBouncerStartingToHide = _primaryBouncerStartingToHide.asStateFlow()
     private val _primaryBouncerDisappearAnimation = MutableStateFlow<Runnable?>(null)
@@ -177,10 +166,6 @@
         _primaryBouncerScrimmed.value = isScrimmed
     }
 
-    override fun setPrimaryVisible(isVisible: Boolean) {
-        _primaryBouncerVisible.value = isVisible
-    }
-
     override fun setAlternateVisible(isVisible: Boolean) {
         if (isVisible && !_alternateBouncerVisible.value) {
             lastAlternateBouncerVisibleTime = clock.uptimeMillis()
@@ -194,18 +179,14 @@
         _alternateBouncerUIAvailable.value = isAvailable
     }
 
-    override fun setPrimaryShow(keyguardBouncerModel: KeyguardBouncerModel?) {
-        _primaryBouncerShow.value = keyguardBouncerModel
+    override fun setPrimaryShow(isShowing: Boolean) {
+        _primaryBouncerShow.value = isShowing
     }
 
     override fun setPrimaryShowingSoon(showingSoon: Boolean) {
         _primaryBouncerShowingSoon.value = showingSoon
     }
 
-    override fun setPrimaryHide(hide: Boolean) {
-        _primaryBouncerHide.value = hide
-    }
-
     override fun setPrimaryStartingToHide(startingToHide: Boolean) {
         _primaryBouncerStartingToHide.value = startingToHide
     }
@@ -248,19 +229,12 @@
             return
         }
 
-        primaryBouncerVisible
-            .logDiffsForTable(buffer, "", "PrimaryBouncerVisible", false)
-            .launchIn(applicationScope)
         primaryBouncerShow
-            .map { it != null }
             .logDiffsForTable(buffer, "", "PrimaryBouncerShow", false)
             .launchIn(applicationScope)
         primaryBouncerShowingSoon
             .logDiffsForTable(buffer, "", "PrimaryBouncerShowingSoon", false)
             .launchIn(applicationScope)
-        primaryBouncerHide
-            .logDiffsForTable(buffer, "", "PrimaryBouncerHide", false)
-            .launchIn(applicationScope)
         primaryBouncerStartingToHide
             .logDiffsForTable(buffer, "", "PrimaryBouncerStartingToHide", false)
             .launchIn(applicationScope)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt
index eae40d6..9a90bb3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt
@@ -23,6 +23,7 @@
 import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
 import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
 import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
+import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager.LegacyAlternateBouncer
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.time.SystemClock
@@ -34,6 +35,7 @@
 class AlternateBouncerInteractor
 @Inject
 constructor(
+    private val statusBarStateController: StatusBarStateController,
     private val keyguardStateController: KeyguardStateController,
     private val bouncerRepository: KeyguardBouncerRepository,
     private val biometricSettingsRepository: BiometricSettingsRepository,
@@ -48,6 +50,17 @@
 
     val isVisible: Flow<Boolean> = bouncerRepository.alternateBouncerVisible
 
+    private val keyguardStateControllerCallback: KeyguardStateController.Callback =
+        object : KeyguardStateController.Callback {
+            override fun onUnlockedChanged() {
+                maybeHide()
+            }
+        }
+
+    init {
+        keyguardStateController.addCallback(keyguardStateControllerCallback)
+    }
+
     /**
      * Sets the correct bouncer states to show the alternate bouncer if it can show.
      *
@@ -107,7 +120,8 @@
                 biometricSettingsRepository.isStrongBiometricAllowed.value &&
                 biometricSettingsRepository.isFingerprintEnabledByDevicePolicy.value &&
                 !deviceEntryFingerprintAuthRepository.isLockedOut.value &&
-                !keyguardStateController.isUnlocked
+                !keyguardStateController.isUnlocked &&
+                !statusBarStateController.isDozing
         } else {
             legacyAlternateBouncer != null &&
                 keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(true)
@@ -127,6 +141,12 @@
         }
     }
 
+    private fun maybeHide() {
+        if (isVisibleState() && !canShowAlternateBouncerForFingerprint()) {
+            hide()
+        }
+    }
+
     companion object {
         private const val MIN_VISIBILITY_DURATION_UNTIL_TOUCHES_DISMISS_ALTERNATE_BOUNCER_MS = 200L
         private const val NOT_VISIBLE = -1L
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index 911861d..28cc697 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -64,7 +64,11 @@
                 .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
                 .collect { pair ->
                     val (isAbleToDream, lastStartedTransition) = pair
-                    if (isAbleToDream && lastStartedTransition.to == KeyguardState.LOCKSCREEN) {
+                    if (
+                        isAbleToDream &&
+                            lastStartedTransition.to == KeyguardState.LOCKSCREEN &&
+                            lastStartedTransition.from != KeyguardState.AOD
+                    ) {
                         keyguardTransitionRepository.startTransition(
                             TransitionInfo(
                                 name,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
index 2dc8fee..1fbfff9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
@@ -47,6 +47,7 @@
         listenForOccludedToLockscreen()
         listenForOccludedToDreaming()
         listenForOccludedToAodOrDozing()
+        listenForOccludedToGone()
     }
 
     private fun listenForOccludedToDreaming() {
@@ -72,11 +73,22 @@
     private fun listenForOccludedToLockscreen() {
         scope.launch {
             keyguardInteractor.isKeyguardOccluded
-                .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
-                .collect { (isOccluded, lastStartedKeyguardState) ->
+                .sample(
+                    combine(
+                        keyguardInteractor.isKeyguardShowing,
+                        keyguardTransitionInteractor.startedKeyguardTransitionStep,
+                        ::Pair
+                    ),
+                    ::toTriple
+                )
+                .collect { (isOccluded, isShowing, lastStartedKeyguardState) ->
                     // Occlusion signals come from the framework, and should interrupt any
                     // existing transition
-                    if (!isOccluded && lastStartedKeyguardState.to == KeyguardState.OCCLUDED) {
+                    if (
+                        !isOccluded &&
+                            isShowing &&
+                            lastStartedKeyguardState.to == KeyguardState.OCCLUDED
+                    ) {
                         keyguardTransitionRepository.startTransition(
                             TransitionInfo(
                                 name,
@@ -90,6 +102,38 @@
         }
     }
 
+    private fun listenForOccludedToGone() {
+        scope.launch {
+            keyguardInteractor.isKeyguardOccluded
+                .sample(
+                    combine(
+                        keyguardInteractor.isKeyguardShowing,
+                        keyguardTransitionInteractor.startedKeyguardTransitionStep,
+                        ::Pair
+                    ),
+                    ::toTriple
+                )
+                .collect { (isOccluded, isShowing, lastStartedKeyguardState) ->
+                    // Occlusion signals come from the framework, and should interrupt any
+                    // existing transition
+                    if (
+                        !isOccluded &&
+                            !isShowing &&
+                            lastStartedKeyguardState.to == KeyguardState.OCCLUDED
+                    ) {
+                        keyguardTransitionRepository.startTransition(
+                            TransitionInfo(
+                                name,
+                                KeyguardState.OCCLUDED,
+                                KeyguardState.GONE,
+                                getAnimator(),
+                            )
+                        )
+                    }
+                }
+        }
+    }
+
     private fun listenForOccludedToAodOrDozing() {
         scope.launch {
             keyguardInteractor.wakefulnessModel
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index ec99049..1ac0c52 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -137,11 +137,13 @@
     /** Whether the keyguard is going away. */
     val isKeyguardGoingAway: Flow<Boolean> = repository.isKeyguardGoingAway
     /** Whether the primary bouncer is showing or not. */
-    val primaryBouncerShowing: Flow<Boolean> = bouncerRepository.primaryBouncerVisible
+    val primaryBouncerShowing: Flow<Boolean> = bouncerRepository.primaryBouncerShow
     /** Whether the alternate bouncer is showing or not. */
     val alternateBouncerShowing: Flow<Boolean> = bouncerRepository.alternateBouncerVisible
     /** Observable for the [StatusBarState] */
     val statusBarState: Flow<StatusBarState> = repository.statusBarState
+    /** Whether or not quick settings or quick quick settings are showing. */
+    val isQuickSettingsVisible: Flow<Boolean> = repository.isQuickSettingsVisible
     /**
      * Observable for [BiometricUnlockModel] when biometrics like face or any fingerprint (rear,
      * side, under display) is used to unlock the device.
@@ -157,7 +159,7 @@
         if (featureFlags.isEnabled(Flags.FACE_AUTH_REFACTOR)) {
             combine(
                     isKeyguardVisible,
-                    bouncerRepository.primaryBouncerVisible,
+                    primaryBouncerShowing,
                     onCameraLaunchDetected,
                 ) { isKeyguardVisible, isPrimaryBouncerShowing, cameraLaunchEvent ->
                     when {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
index 568cc0f..e31771a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
@@ -93,8 +93,9 @@
             quickAffordanceAlwaysVisible(position),
             keyguardInteractor.isDozing,
             keyguardInteractor.isKeyguardShowing,
-        ) { affordance, isDozing, isKeyguardShowing ->
-            if (!isDozing && isKeyguardShowing) {
+            keyguardInteractor.isQuickSettingsVisible
+        ) { affordance, isDozing, isKeyguardShowing, isQuickSettingsVisible ->
+            if (!isDozing && isKeyguardShowing && !isQuickSettingsVisible) {
                 affordance
             } else {
                 KeyguardQuickAffordanceModel.Hidden
@@ -406,6 +407,10 @@
             KeyguardPickerFlag(
                 name = Contract.FlagsTable.FLAG_NAME_MONOCHROMATIC_THEME,
                 value = featureFlags.isEnabled(Flags.MONOCHROMATIC_THEME)
+            ),
+            KeyguardPickerFlag(
+                name = Contract.FlagsTable.FLAG_NAME_WALLPAPER_PICKER_UI_FOR_AIWP,
+                value = featureFlags.isEnabled(Flags.WALLPAPER_PICKER_UI_FOR_AIWP)
             )
         )
     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt
index c709fd1..0a3b3d3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt
@@ -23,12 +23,13 @@
 import android.os.Trace
 import android.os.UserHandle
 import android.os.UserManager
-import android.view.View
 import android.util.Log
+import android.view.View
 import com.android.keyguard.KeyguardConstants
 import com.android.keyguard.KeyguardSecurityModel
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.keyguard.KeyguardUpdateMonitorCallback
+import com.android.settingslib.Utils
 import com.android.systemui.DejankUtils
 import com.android.systemui.R
 import com.android.systemui.classifier.FalsingCollector
@@ -39,7 +40,6 @@
 import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
 import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants
 import com.android.systemui.keyguard.shared.model.BouncerShowMessageModel
-import com.android.systemui.keyguard.shared.model.KeyguardBouncerModel
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.shared.system.SysUiStatsLog
 import com.android.systemui.statusbar.phone.KeyguardBypassController
@@ -83,23 +83,21 @@
 
     /** Runnable to show the primary bouncer. */
     val showRunnable = Runnable {
-        repository.setPrimaryVisible(true)
-        repository.setPrimaryShow(
-            KeyguardBouncerModel(
-                promptReason = repository.bouncerPromptReason ?: 0,
-                errorMessage = repository.bouncerErrorMessage,
-                expansionAmount = repository.panelExpansionAmount.value
+        repository.setPrimaryShow(true)
+        primaryBouncerView.delegate?.showPromptReason(repository.bouncerPromptReason)
+        (repository.bouncerErrorMessage as? String)?.let {
+            repository.setShowMessage(
+                BouncerShowMessageModel(message = it, Utils.getColorError(context))
             )
-        )
+        }
         repository.setPrimaryShowingSoon(false)
         primaryBouncerCallbackInteractor.dispatchVisibilityChanged(View.VISIBLE)
     }
 
     val keyguardAuthenticated: Flow<Boolean> = repository.keyguardAuthenticated.filterNotNull()
-    val show: Flow<KeyguardBouncerModel> = repository.primaryBouncerShow.filterNotNull()
-    val hide: Flow<Unit> = repository.primaryBouncerHide.filter { it }.map {}
+    val show: Flow<Unit> = repository.primaryBouncerShow.filter { it }.map {}
+    val hide: Flow<Unit> = repository.primaryBouncerShow.filter { !it }.map {}
     val startingToHide: Flow<Unit> = repository.primaryBouncerStartingToHide.filter { it }.map {}
-    val isVisible: Flow<Boolean> = repository.primaryBouncerVisible
     val isBackButtonEnabled: Flow<Boolean> = repository.isBackButtonEnabled.filterNotNull()
     val showMessage: Flow<BouncerShowMessageModel> = repository.showMessage.filterNotNull()
     val startingDisappearAnimation: Flow<Runnable> =
@@ -109,10 +107,11 @@
     val panelExpansionAmount: Flow<Float> = repository.panelExpansionAmount
     /** 0f = bouncer fully hidden. 1f = bouncer fully visible. */
     val bouncerExpansion: Flow<Float> =
-        combine(repository.panelExpansionAmount, repository.primaryBouncerVisible) {
-            panelExpansion,
-            primaryBouncerVisible ->
-            if (primaryBouncerVisible) {
+        combine(
+            repository.panelExpansionAmount,
+            repository.primaryBouncerShow
+        ) { panelExpansion, primaryBouncerIsShowing ->
+            if (primaryBouncerIsShowing) {
                 1f - panelExpansion
             } else {
                 0f
@@ -122,21 +121,23 @@
     val isInteractable: Flow<Boolean> = bouncerExpansion.map { it > 0.9 }
     val sideFpsShowing: Flow<Boolean> = repository.sideFpsShowing
 
-    init {
-        keyguardUpdateMonitor.registerCallback(
-            object : KeyguardUpdateMonitorCallback() {
-                override fun onBiometricRunningStateChanged(
-                    running: Boolean,
-                    biometricSourceType: BiometricSourceType?
-                ) {
-                    updateSideFpsVisibility()
-                }
-
-                override fun onStrongAuthStateChanged(userId: Int) {
-                    updateSideFpsVisibility()
-                }
+    /** This callback needs to be a class field so it does not get garbage collected. */
+    val keyguardUpdateMonitorCallback =
+        object : KeyguardUpdateMonitorCallback() {
+            override fun onBiometricRunningStateChanged(
+                running: Boolean,
+                biometricSourceType: BiometricSourceType?
+            ) {
+                updateSideFpsVisibility()
             }
-        )
+
+            override fun onStrongAuthStateChanged(userId: Int) {
+                updateSideFpsVisibility()
+            }
+        }
+
+    init {
+        keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
     }
 
     // TODO(b/243685699): Move isScrimmed logic to data layer.
@@ -146,14 +147,13 @@
     fun show(isScrimmed: Boolean) {
         // Reset some states as we show the bouncer.
         repository.setKeyguardAuthenticated(null)
-        repository.setPrimaryHide(false)
         repository.setPrimaryStartingToHide(false)
 
         val resumeBouncer =
-            (repository.primaryBouncerVisible.value ||
-                repository.primaryBouncerShowingSoon.value) && needsFullscreenBouncer()
+            (isBouncerShowing() || repository.primaryBouncerShowingSoon.value) &&
+                needsFullscreenBouncer()
 
-        if (!resumeBouncer && repository.primaryBouncerShow.value != null) {
+        if (!resumeBouncer && isBouncerShowing()) {
             // If bouncer is visible, the bouncer is already showing.
             return
         }
@@ -206,9 +206,7 @@
         keyguardStateController.notifyPrimaryBouncerShowing(false /* showing */)
         cancelShowRunnable()
         repository.setPrimaryShowingSoon(false)
-        repository.setPrimaryVisible(false)
-        repository.setPrimaryHide(true)
-        repository.setPrimaryShow(null)
+        repository.setPrimaryShow(false)
         primaryBouncerCallbackInteractor.dispatchVisibilityChanged(View.INVISIBLE)
         Trace.endSection()
     }
@@ -311,6 +309,10 @@
 
     /** Tell the bouncer to start the pre hide animation. */
     fun startDisappearAnimation(runnable: Runnable) {
+        if (willRunDismissFromKeyguard()) {
+            runnable.run()
+            return
+        }
         val finishRunnable = Runnable {
             runnable.run()
             repository.setPrimaryStartDisappearAnimation(null)
@@ -325,9 +327,8 @@
         val fpsDetectionRunning: Boolean = keyguardUpdateMonitor.isFingerprintDetectionRunning
         val isUnlockingWithFpAllowed: Boolean =
             keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed
-        val bouncerVisible = repository.primaryBouncerVisible.value
         val toShow =
-            (repository.primaryBouncerVisible.value &&
+            (isBouncerShowing() &&
                 sfpsEnabled &&
                 fpsDetectionRunning &&
                 isUnlockingWithFpAllowed &&
@@ -337,7 +338,7 @@
             Log.d(
                 TAG,
                 ("sideFpsToShow=$toShow\n" +
-                    "bouncerVisible=$bouncerVisible\n" +
+                    "isBouncerShowing=${isBouncerShowing()}\n" +
                     "configEnabled=$sfpsEnabled\n" +
                     "fpsDetectionRunning=$fpsDetectionRunning\n" +
                     "isUnlockingWithFpAllowed=$isUnlockingWithFpAllowed\n" +
@@ -349,8 +350,7 @@
 
     /** Returns whether bouncer is fully showing. */
     fun isFullyShowing(): Boolean {
-        return (repository.primaryBouncerShowingSoon.value ||
-            repository.primaryBouncerVisible.value) &&
+        return (repository.primaryBouncerShowingSoon.value || isBouncerShowing()) &&
             repository.panelExpansionAmount.value == KeyguardBouncerConstants.EXPANSION_VISIBLE &&
             repository.primaryBouncerStartingDisappearAnimation.value == null
     }
@@ -377,6 +377,11 @@
         return primaryBouncerView.delegate?.willDismissWithActions() == true
     }
 
+    /** Will the dismissal run from the keyguard layout (instead of from bouncer) */
+    fun willRunDismissFromKeyguard(): Boolean {
+        return primaryBouncerView.delegate?.willRunDismissFromKeyguard() == true
+    }
+
     /** Returns whether the bouncer should be full screen. */
     private fun needsFullscreenBouncer(): Boolean {
         val mode: KeyguardSecurityModel.SecurityMode =
@@ -391,6 +396,10 @@
         mainHandler.removeCallbacks(showRunnable)
     }
 
+    private fun isBouncerShowing(): Boolean {
+        return repository.primaryBouncerShow.value
+    }
+
     companion object {
         private const val TAG = "PrimaryBouncerInteractor"
     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardBouncerModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/ScrimAlpha.kt
similarity index 70%
rename from packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardBouncerModel.kt
rename to packages/SystemUI/src/com/android/systemui/keyguard/shared/model/ScrimAlpha.kt
index ad783da..1db7733 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardBouncerModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/ScrimAlpha.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,12 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License
  */
-
 package com.android.systemui.keyguard.shared.model
 
-/** Models the state of the lock-screen bouncer */
-data class KeyguardBouncerModel(
-    val promptReason: Int = 0,
-    val errorMessage: CharSequence? = null,
-    val expansionAmount: Float = 0f,
+/** Alpha values for scrim updates */
+data class ScrimAlpha(
+    val frontAlpha: Float = 0f,
+    val behindAlpha: Float = 0f,
+    val notificationsAlpha: Float = 0f,
 )
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt
index ca1e27c..38b9d50 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt
@@ -47,6 +47,7 @@
         duration: Duration,
         onStep: (Float) -> Float,
         startTime: Duration = 0.milliseconds,
+        onStart: (() -> Unit)? = null,
         onCancel: (() -> Float)? = null,
         onFinish: (() -> Float)? = null,
         interpolator: Interpolator = LINEAR,
@@ -73,6 +74,7 @@
                 // the ViewModels of the last update
                 STARTED -> {
                     isComplete = false
+                    onStart?.invoke()
                     max(0f, min(1f, value))
                 }
                 // Always send a final value of 1. Because of rounding, [value] may never be
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt
index 2337ffc..5fcf105 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt
@@ -27,7 +27,6 @@
 import com.android.keyguard.KeyguardSecurityView
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.keyguard.dagger.KeyguardBouncerComponent
-import com.android.settingslib.Utils
 import com.android.systemui.keyguard.data.BouncerViewDelegate
 import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel
@@ -35,7 +34,6 @@
 import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.plugins.ActivityStarter
 import kotlinx.coroutines.awaitCancellation
-import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.flow.filter
 import kotlinx.coroutines.launch
 
@@ -97,6 +95,14 @@
                 override fun willDismissWithActions(): Boolean {
                     return securityContainerController.hasDismissActions()
                 }
+
+                override fun willRunDismissFromKeyguard(): Boolean {
+                    return securityContainerController.willRunDismissFromKeyguard()
+                }
+
+                override fun showPromptReason(reason: Int) {
+                    securityContainerController.showPromptReason(reason)
+                }
             }
         view.repeatWhenAttached {
             repeatOnLifecycle(Lifecycle.State.CREATED) {
@@ -105,26 +111,30 @@
                     launch {
                         viewModel.show.collect {
                             // Reset Security Container entirely.
-                            securityContainerController.reinflateViewFlipper()
-                            securityContainerController.showPromptReason(it.promptReason)
-                            it.errorMessage?.let { errorMessage ->
-                                securityContainerController.showMessage(
-                                    errorMessage,
-                                    Utils.getColorError(view.context)
+                            securityContainerController.reinflateViewFlipper {
+                                // Reset Security Container entirely.
+                                view.visibility = View.VISIBLE
+                                securityContainerController.onBouncerVisibilityChanged(
+                                    /* isVisible= */ true
                                 )
+                                securityContainerController.showPrimarySecurityScreen(
+                                    /* turningOff= */ false
+                                )
+                                securityContainerController.appear()
+                                securityContainerController.onResume(KeyguardSecurityView.SCREEN_ON)
                             }
-                            securityContainerController.showPrimarySecurityScreen(
-                                /* turningOff= */ false
-                            )
-                            securityContainerController.appear()
-                            securityContainerController.onResume(KeyguardSecurityView.SCREEN_ON)
                         }
                     }
 
                     launch {
                         viewModel.hide.collect {
+                            view.visibility = View.INVISIBLE
+                            securityContainerController.onBouncerVisibilityChanged(
+                                /* isVisible= */ false
+                            )
                             securityContainerController.cancelDismissAction()
                             securityContainerController.reset()
+                            securityContainerController.onPause()
                         }
                     }
 
@@ -162,19 +172,6 @@
                     }
 
                     launch {
-                        viewModel.isBouncerVisible.collect { isVisible ->
-                            view.visibility = if (isVisible) View.VISIBLE else View.INVISIBLE
-                            securityContainerController.onBouncerVisibilityChanged(isVisible)
-                        }
-                    }
-
-                    launch {
-                        viewModel.isBouncerVisible
-                            .filter { !it }
-                            .collect { securityContainerController.onPause() }
-                    }
-
-                    launch {
                         viewModel.isInteractable.collect { isInteractable ->
                             securityContainerController.setInteractable(isInteractable)
                         }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManager.kt
index 50722d5..6d95882 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManager.kt
@@ -26,18 +26,21 @@
 import android.util.Log
 import androidx.annotation.VisibleForTesting
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.shared.quickaffordance.shared.model.KeyguardQuickAffordancePreviewConstants
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
 
 @SysUISingleton
 class KeyguardRemotePreviewManager
 @Inject
 constructor(
     private val previewRendererFactory: KeyguardPreviewRendererFactory,
+    @Application private val applicationScope: CoroutineScope,
     @Main private val mainDispatcher: CoroutineDispatcher,
     @Background private val backgroundHandler: Handler,
 ) {
@@ -55,7 +58,13 @@
 
             // Destroy any previous renderer associated with this token.
             activePreviews[renderer.hostToken]?.let { destroyObserver(it) }
-            observer = PreviewLifecycleObserver(renderer, mainDispatcher, ::destroyObserver)
+            observer =
+                PreviewLifecycleObserver(
+                    renderer,
+                    applicationScope,
+                    mainDispatcher,
+                    ::destroyObserver,
+                )
             activePreviews[renderer.hostToken] = observer
             renderer.render()
             renderer.hostToken?.linkToDeath(observer, 0)
@@ -92,13 +101,18 @@
 
     private class PreviewLifecycleObserver(
         private val renderer: KeyguardPreviewRenderer,
+        private val scope: CoroutineScope,
         private val mainDispatcher: CoroutineDispatcher,
         private val requestDestruction: (PreviewLifecycleObserver) -> Unit,
     ) : Handler.Callback, IBinder.DeathRecipient {
 
-        private var isDestroyed = false
+        private var isDestroyedOrDestroying = false
 
         override fun handleMessage(message: Message): Boolean {
+            if (isDestroyedOrDestroying) {
+                return true
+            }
+
             when (message.what) {
                 KeyguardQuickAffordancePreviewConstants.MESSAGE_ID_SLOT_SELECTED -> {
                     message.data
@@ -118,14 +132,14 @@
         }
 
         fun onDestroy(): IBinder? {
-            if (isDestroyed) {
+            if (isDestroyedOrDestroying) {
                 return null
             }
 
-            isDestroyed = true
+            isDestroyedOrDestroying = true
             val hostToken = renderer.hostToken
             hostToken?.unlinkToDeath(this, 0)
-            runBlocking(mainDispatcher) { renderer.destroy() }
+            scope.launch(mainDispatcher) { renderer.destroy() }
             return hostToken
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModel.kt
index 97e94d8f3..0656c9b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModel.kt
@@ -21,7 +21,6 @@
 import com.android.systemui.keyguard.data.BouncerViewDelegate
 import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor
 import com.android.systemui.keyguard.shared.model.BouncerShowMessageModel
-import com.android.systemui.keyguard.shared.model.KeyguardBouncerModel
 import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.filterNotNull
@@ -38,14 +37,11 @@
     /** Observe on bouncer expansion amount. */
     val bouncerExpansionAmount: Flow<Float> = interactor.panelExpansionAmount
 
-    /** Observe on bouncer visibility. */
-    val isBouncerVisible: Flow<Boolean> = interactor.isVisible
-
     /** Can the user interact with the view? */
     val isInteractable: Flow<Boolean> = interactor.isInteractable
 
     /** Observe whether bouncer is showing. */
-    val show: Flow<KeyguardBouncerModel> = interactor.show
+    val show: Flow<Unit> = interactor.show
 
     /** Observe whether bouncer is hiding. */
     val hide: Flow<Unit> = interactor.hide
@@ -74,8 +70,8 @@
     /** Observe whether we should update fps is showing. */
     val shouldUpdateSideFps: Flow<Unit> =
         merge(
-            interactor.startingToHide,
-            interactor.isVisible.map {},
+            interactor.hide,
+            interactor.show,
             interactor.startingDisappearAnimation.filterNotNull().map {}
         )
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
index 0890791..df93d23 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
@@ -20,10 +20,14 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor.Companion.TO_GONE_DURATION
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.keyguard.shared.model.ScrimAlpha
 import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.statusbar.SysuiStatusBarStateController
 import javax.inject.Inject
 import kotlin.time.Duration.Companion.milliseconds
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
 
 /**
  * Breaks down PRIMARY_BOUNCER->GONE transition into discrete steps for corresponding views to
@@ -34,6 +38,8 @@
 @Inject
 constructor(
     private val interactor: KeyguardTransitionInteractor,
+    private val statusBarStateController: SysuiStatusBarStateController,
+    private val primaryBouncerInteractor: PrimaryBouncerInteractor,
 ) {
     private val transitionAnimation =
         KeyguardTransitionAnimationFlow(
@@ -41,18 +47,48 @@
             transitionFlow = interactor.primaryBouncerToGoneTransition,
         )
 
+    private var leaveShadeOpen: Boolean = false
+    private var willRunDismissFromKeyguard: Boolean = false
+
     /** Bouncer container alpha */
     val bouncerAlpha: Flow<Float> =
         transitionAnimation.createFlow(
             duration = 200.milliseconds,
-            onStep = { 1f - it },
+            onStart = {
+                willRunDismissFromKeyguard = primaryBouncerInteractor.willRunDismissFromKeyguard()
+            },
+            onStep = {
+                if (willRunDismissFromKeyguard) {
+                    0f
+                } else {
+                    1f - it
+                }
+            },
         )
 
-    /** Scrim alpha */
-    val scrimAlpha: Flow<Float> =
-        transitionAnimation.createFlow(
-            duration = TO_GONE_DURATION,
-            interpolator = EMPHASIZED_ACCELERATE,
-            onStep = { 1f - it },
-        )
+    /** Scrim alpha values */
+    val scrimAlpha: Flow<ScrimAlpha> =
+        transitionAnimation
+            .createFlow(
+                duration = TO_GONE_DURATION,
+                interpolator = EMPHASIZED_ACCELERATE,
+                onStart = {
+                    leaveShadeOpen = statusBarStateController.leaveOpenOnKeyguardHide()
+                    willRunDismissFromKeyguard =
+                        primaryBouncerInteractor.willRunDismissFromKeyguard()
+                },
+                onStep = { 1f - it },
+            )
+            .map {
+                if (willRunDismissFromKeyguard) {
+                    ScrimAlpha()
+                } else if (leaveShadeOpen) {
+                    ScrimAlpha(
+                        behindAlpha = 1f,
+                        notificationsAlpha = 1f,
+                    )
+                } else {
+                    ScrimAlpha(behindAlpha = it)
+                }
+            }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/data/model/BacklightModel.kt b/packages/SystemUI/src/com/android/systemui/log/dagger/DeviceStateAutoRotationLog.java
similarity index 66%
copy from packages/SystemUI/src/com/android/systemui/keyboard/data/model/BacklightModel.kt
copy to packages/SystemUI/src/com/android/systemui/log/dagger/DeviceStateAutoRotationLog.java
index ea15a9f..beb725e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/data/model/BacklightModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/DeviceStateAutoRotationLog.java
@@ -12,13 +12,19 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
- *
  */
 
-package com.android.systemui.keyboard.data.model
+package com.android.systemui.log.dagger;
 
-/**
- * Model for current state of keyboard backlight brightness. [level] indicates current level of
- * backlight brightness and [maxLevel] its max possible value.
- */
-data class BacklightModel(val level: Int, val maxLevel: Int)
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface DeviceStateAutoRotationLog {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index 642c9f7..60192b8 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -152,6 +152,14 @@
         return factory.create("QSLog", 700 /* maxSize */, false /* systrace */);
     }
 
+    /** Provides a logging buffer for logs related to Quick Settings configuration. */
+    @Provides
+    @SysUISingleton
+    @QSConfigLog
+    public static LogBuffer provideQSConfigLogBuffer(LogBufferFactory factory) {
+        return factory.create("QSConfigLog", 100 /* maxSize */, true /* systrace */);
+    }
+
     /** Provides a logging buffer for {@link com.android.systemui.broadcast.BroadcastDispatcher} */
     @Provides
     @SysUISingleton
@@ -370,6 +378,16 @@
     }
 
     /**
+     * Provides a {@link LogBuffer} for Device State Auto-Rotation logs.
+     */
+    @Provides
+    @SysUISingleton
+    @DeviceStateAutoRotationLog
+    public static LogBuffer provideDeviceStateAutoRotationLogBuffer(LogBufferFactory factory) {
+        return factory.create("DeviceStateAutoRotationLog", 100);
+    }
+
+    /**
      * Provides a {@link LogBuffer} for bluetooth-related logs.
      */
     @Provides
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/QSConfigLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/QSConfigLog.java
new file mode 100644
index 0000000..295bf88
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/QSConfigLog.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.log.dagger;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.android.systemui.plugins.log.LogBuffer;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+/** A {@link LogBuffer} for QS configuration changed messages. */
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface QSConfigLog {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/log/table/TableChange.kt b/packages/SystemUI/src/com/android/systemui/log/table/TableChange.kt
index 4880f80..b73ddc5 100644
--- a/packages/SystemUI/src/com/android/systemui/log/table/TableChange.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/table/TableChange.kt
@@ -59,6 +59,17 @@
         int = value
     }
 
+    /** Updates this to store the same value as [change]. */
+    fun updateTo(change: TableChange) {
+        reset(change.timestamp, change.columnPrefix, change.columnName)
+        when (change.type) {
+            DataType.STRING -> set(change.str)
+            DataType.INT -> set(change.int)
+            DataType.BOOLEAN -> set(change.bool)
+            DataType.EMPTY -> {}
+        }
+    }
+
     /** Returns true if this object has a change. */
     fun hasData(): Boolean {
         return columnName.isNotBlank() && type != DataType.EMPTY
diff --git a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt
index 29f273a..a0f1c95 100644
--- a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt
@@ -16,13 +16,13 @@
 
 package com.android.systemui.log.table
 
+import android.os.Trace
 import com.android.systemui.Dumpable
 import com.android.systemui.plugins.util.RingBuffer
 import com.android.systemui.util.time.SystemClock
 import java.io.PrintWriter
 import java.text.SimpleDateFormat
 import java.util.Locale
-import kotlinx.coroutines.flow.Flow
 
 /**
  * A logger that logs changes in table format.
@@ -82,6 +82,19 @@
 
     private val buffer = RingBuffer(maxSize) { TableChange() }
 
+    // Stores the most recently evicted value for each column name (indexed on column name).
+    //
+    // Why it's necessary: Because we use a RingBuffer of a fixed size, it's possible that a column
+    // that's logged infrequently will eventually get pushed out by a different column that's
+    // logged more frequently. Then, that infrequently-logged column isn't present in the RingBuffer
+    // at all and we have no logs that the column ever existed. This is a problem because the
+    // column's information is still relevant, valid, and may be critical to debugging issues.
+    //
+    // Fix: When a change is being evicted from the RingBuffer, we store it in this map (based on
+    // its [TableChange.getName()]. This ensures that we always have at least one value for every
+    // column ever logged. See b/272016422 for more details.
+    private val lastEvictedValues = mutableMapOf<String, TableChange>()
+
     // A [TableRowLogger] object, re-used each time [logDiffs] is called.
     // (Re-used to avoid object allocation.)
     private val tempRow = TableRowLoggerImpl(0, columnPrefix = "", this)
@@ -138,18 +151,24 @@
     // timestamps.)
 
     private fun logChange(timestamp: Long, prefix: String, columnName: String, value: String?) {
+        Trace.beginSection("TableLogBuffer#logChange(string)")
         val change = obtain(timestamp, prefix, columnName)
         change.set(value)
+        Trace.endSection()
     }
 
     private fun logChange(timestamp: Long, prefix: String, columnName: String, value: Boolean) {
+        Trace.beginSection("TableLogBuffer#logChange(boolean)")
         val change = obtain(timestamp, prefix, columnName)
         change.set(value)
+        Trace.endSection()
     }
 
     private fun logChange(timestamp: Long, prefix: String, columnName: String, value: Int?) {
+        Trace.beginSection("TableLogBuffer#logChange(int)")
         val change = obtain(timestamp, prefix, columnName)
         change.set(value)
+        Trace.endSection()
     }
 
     // TODO(b/259454430): Add additional change types here.
@@ -158,6 +177,9 @@
     private fun obtain(timestamp: Long, prefix: String, columnName: String): TableChange {
         verifyValidName(prefix, columnName)
         val tableChange = buffer.advance()
+        if (tableChange.hasData()) {
+            saveEvictedValue(tableChange)
+        }
         tableChange.reset(timestamp, prefix, columnName)
         return tableChange
     }
@@ -173,10 +195,23 @@
         }
     }
 
+    private fun saveEvictedValue(change: TableChange) {
+        Trace.beginSection("TableLogBuffer#saveEvictedValue")
+        val name = change.getName()
+        val previouslyEvicted =
+            lastEvictedValues[name] ?: TableChange().also { lastEvictedValues[name] = it }
+        // For recycling purposes, update the existing object in the map with the new information
+        // instead of creating a new object.
+        previouslyEvicted.updateTo(change)
+        Trace.endSection()
+    }
+
     @Synchronized
     override fun dump(pw: PrintWriter, args: Array<out String>) {
         pw.println(HEADER_PREFIX + name)
         pw.println("version $VERSION")
+
+        lastEvictedValues.values.sortedBy { it.timestamp }.forEach { it.dump(pw) }
         for (i in 0 until buffer.size) {
             buffer[i].dump(pw)
         }
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt
index 6023bc2..525b2fc 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt
@@ -1343,13 +1343,9 @@
     fun onNotificationRemoved(key: String) {
         Assert.isMainThread()
         val removed = mediaEntries.remove(key) ?: return
-        val isEligibleForResume =
-            removed.isLocalSession() ||
-                (mediaFlags.isRemoteResumeAllowed() &&
-                    removed.playbackLocation != MediaData.PLAYBACK_CAST_REMOTE)
         if (keyguardUpdateMonitor.isUserInLockdown(removed.userId)) {
             logger.logMediaRemoved(removed.appUid, removed.packageName, removed.instanceId)
-        } else if (useMediaResumption && removed.resumeAction != null && isEligibleForResume) {
+        } else if (isAbleToResume(removed)) {
             convertToResumePlayer(key, removed)
         } else if (mediaFlags.isRetainingPlayersEnabled()) {
             handlePossibleRemoval(key, removed, notificationRemoved = true)
@@ -1369,6 +1365,14 @@
         handlePossibleRemoval(key, updated)
     }
 
+    private fun isAbleToResume(data: MediaData): Boolean {
+        val isEligibleForResume =
+            data.isLocalSession() ||
+                (mediaFlags.isRemoteResumeAllowed() &&
+                    data.playbackLocation != MediaData.PLAYBACK_CAST_REMOTE)
+        return useMediaResumption && data.resumeAction != null && isEligibleForResume
+    }
+
     /**
      * Convert to resume state if the player is no longer valid and active, then notify listeners
      * that the data was updated. Does not convert to resume state if the player is still valid, or
@@ -1391,8 +1395,9 @@
             if (DEBUG) Log.d(TAG, "Session destroyed but using notification actions $key")
             mediaEntries.put(key, removed)
             notifyMediaDataLoaded(key, key, removed)
-        } else if (removed.active) {
-            // This player was still active - it didn't last long enough to time out: remove
+        } else if (removed.active && !isAbleToResume(removed)) {
+            // This player was still active - it didn't last long enough to time out,
+            // and its app doesn't normally support resume: remove
             if (DEBUG) Log.d(TAG, "Removing still-active player $key")
             notifyMediaDataRemoved(key)
             logger.logMediaRemoved(removed.appUid, removed.packageName, removed.instanceId)
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt b/packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt
index 92e0c85..b0389b5 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt
@@ -239,6 +239,8 @@
                         data.playbackLocation != MediaData.PLAYBACK_CAST_REMOTE)
             if (data.resumeAction == null && !data.hasCheckedForResume && isEligibleForResume) {
                 // TODO also check for a media button receiver intended for restarting (b/154127084)
+                // Set null action to prevent additional attempts to connect
+                mediaDataManager.setResumeAction(key, null)
                 Log.d(TAG, "Checking for service component for " + data.packageName)
                 val pm = context.packageManager
                 val serviceIntent = Intent(MediaBrowserService.SERVICE_INTERFACE)
@@ -249,9 +251,6 @@
                     backgroundExecutor.execute {
                         tryUpdateResumptionList(key, inf!!.get(0).componentInfo.componentName)
                     }
-                } else {
-                    // No service found
-                    mediaDataManager.setResumeAction(key, null)
                 }
             }
         }
@@ -263,8 +262,6 @@
      */
     private fun tryUpdateResumptionList(key: String, componentName: ComponentName) {
         Log.d(TAG, "Testing if we can connect to $componentName")
-        // Set null action to prevent additional attempts to connect
-        mediaDataManager.setResumeAction(key, null)
         mediaBrowser =
             mediaBrowserFactory.create(
                 object : ResumeMediaBrowser.Callback() {
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowser.java b/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowser.java
index 3493b24..d460b5b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowser.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowser.java
@@ -85,16 +85,13 @@
      * ResumeMediaBrowser#disconnect will be called automatically with this function.
      */
     public void findRecentMedia() {
-        disconnect();
         Bundle rootHints = new Bundle();
         rootHints.putBoolean(MediaBrowserService.BrowserRoot.EXTRA_RECENT, true);
-        mMediaBrowser = mBrowserFactory.create(
+        MediaBrowser browser = mBrowserFactory.create(
                 mComponentName,
                 mConnectionCallback,
                 rootHints);
-        updateMediaController();
-        mLogger.logConnection(mComponentName, "findRecentMedia");
-        mMediaBrowser.connect();
+        connectBrowser(browser, "findRecentMedia");
     }
 
     private final MediaBrowser.SubscriptionCallback mSubscriptionCallback =
@@ -202,6 +199,21 @@
     };
 
     /**
+     * Connect using a new media browser. Disconnects the existing browser first, if it exists.
+     * @param browser media browser to connect
+     * @param reason Reason to log for connection
+     */
+    private void connectBrowser(MediaBrowser browser, String reason) {
+        mLogger.logConnection(mComponentName, reason);
+        disconnect();
+        mMediaBrowser = browser;
+        if (browser != null) {
+            browser.connect();
+        }
+        updateMediaController();
+    }
+
+    /**
      * Disconnect the media browser. This should be done after callbacks have completed to
      * disconnect from the media browser service.
      */
@@ -222,10 +234,9 @@
      * getting a media update from the app
      */
     public void restart() {
-        disconnect();
         Bundle rootHints = new Bundle();
         rootHints.putBoolean(MediaBrowserService.BrowserRoot.EXTRA_RECENT, true);
-        mMediaBrowser = mBrowserFactory.create(mComponentName,
+        MediaBrowser browser = mBrowserFactory.create(mComponentName,
                 new MediaBrowser.ConnectionCallback() {
                     @Override
                     public void onConnected() {
@@ -265,9 +276,7 @@
                         disconnect();
                     }
                 }, rootHints);
-        updateMediaController();
-        mLogger.logConnection(mComponentName, "restart");
-        mMediaBrowser.connect();
+        connectBrowser(browser, "restart");
     }
 
     @VisibleForTesting
@@ -305,16 +314,13 @@
      * ResumeMediaBrowser#disconnect should be called after this to ensure the connection is closed.
      */
     public void testConnection() {
-        disconnect();
         Bundle rootHints = new Bundle();
         rootHints.putBoolean(MediaBrowserService.BrowserRoot.EXTRA_RECENT, true);
-        mMediaBrowser = mBrowserFactory.create(
+        MediaBrowser browser = mBrowserFactory.create(
                 mComponentName,
                 mConnectionCallback,
                 rootHints);
-        updateMediaController();
-        mLogger.logConnection(mComponentName, "testConnection");
-        mMediaBrowser.connect();
+        connectBrowser(browser, "testConnection");
     }
 
     /** Updates mMediaController based on our current browser values. */
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
index 680a8b6..0176c42 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
@@ -39,7 +39,6 @@
 import com.android.systemui.R
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
@@ -69,7 +68,6 @@
 import com.android.systemui.util.traceSection
 import java.io.PrintWriter
 import java.util.TreeMap
-import java.util.concurrent.Executor
 import javax.inject.Inject
 import javax.inject.Provider
 import kotlinx.coroutines.CoroutineScope
@@ -95,8 +93,7 @@
     private val mediaHostStatesManager: MediaHostStatesManager,
     private val activityStarter: ActivityStarter,
     private val systemClock: SystemClock,
-    @Main private val mainExecutor: DelayableExecutor,
-    @Background private val backgroundExecutor: Executor,
+    @Main executor: DelayableExecutor,
     private val mediaManager: MediaDataManager,
     configurationController: ConfigurationController,
     falsingCollector: FalsingCollector,
@@ -197,7 +194,6 @@
 
     private val configListener =
         object : ConfigurationController.ConfigurationListener {
-            var lastOrientation = -1
 
             override fun onDensityOrFontScaleChanged() {
                 // System font changes should only happen when UMO is offscreen or a flicker may
@@ -214,13 +210,6 @@
             override fun onConfigChanged(newConfig: Configuration?) {
                 if (newConfig == null) return
                 isRtl = newConfig.layoutDirection == View.LAYOUT_DIRECTION_RTL
-                val newOrientation = newConfig.orientation
-                if (lastOrientation != newOrientation) {
-                    // The players actually depend on the orientation possibly, so we have to
-                    // recreate them (at least on large screen devices)
-                    lastOrientation = newOrientation
-                    updatePlayers(recreateMedia = true)
-                }
             }
 
             override fun onUiModeChanged() {
@@ -233,8 +222,10 @@
         object : KeyguardUpdateMonitorCallback() {
             override fun onStrongAuthStateChanged(userId: Int) {
                 if (keyguardUpdateMonitor.isUserInLockdown(userId)) {
+                    debugLogger.logCarouselHidden()
                     hideMediaCarousel()
                 } else if (keyguardUpdateMonitor.isUserUnlocked(userId)) {
+                    debugLogger.logCarouselVisible()
                     showMediaCarousel()
                 }
             }
@@ -259,7 +250,7 @@
             MediaCarouselScrollHandler(
                 mediaCarousel,
                 pageIndicator,
-                mainExecutor,
+                executor,
                 this::onSwipeToDismiss,
                 this::updatePageIndicatorLocation,
                 this::updateSeekbarListening,
@@ -306,7 +297,7 @@
                     receivedSmartspaceCardLatency: Int,
                     isSsReactivated: Boolean
                 ) {
-                    debugLogger.logMediaLoaded(key)
+                    debugLogger.logMediaLoaded(key, data.active)
                     if (addOrUpdatePlayer(key, oldKey, data, isSsReactivated)) {
                         // Log card received if a new resumable media card is added
                         MediaPlayerData.getMediaPlayer(key)?.let {
@@ -621,50 +612,10 @@
                 MediaPlayerData.visiblePlayerKeys()
                     .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex)
             if (existingPlayer == null) {
-                setupNewPlayer(key, data, isSsReactivated, curVisibleMediaKey)
-            } else {
-                existingPlayer.bindPlayer(data, key)
-                MediaPlayerData.addMediaPlayer(
-                    key,
-                    data,
-                    existingPlayer,
-                    systemClock,
-                    isSsReactivated,
-                    debugLogger
-                )
-                val packageName = MediaPlayerData.smartspaceMediaData?.packageName ?: String()
-                // In case of recommendations hits.
-                // Check the playing status of media player and the package name.
-                // To make sure we scroll to the right app's media player.
-                if (
-                    isReorderingAllowed ||
-                        shouldScrollToKey &&
-                            data.isPlaying == true &&
-                            packageName == data.packageName
-                ) {
-                    reorderAllPlayers(curVisibleMediaKey, key)
-                } else {
-                    needsReordering = true
-                }
-                updatePageIndicator()
-                mediaCarouselScrollHandler.onPlayersChanged()
-                mediaFrame.requiresRemeasuring = true
-            }
-            return existingPlayer == null
-        }
-
-    private fun setupNewPlayer(
-        key: String,
-        data: MediaData,
-        isSsReactivated: Boolean,
-        curVisibleMediaKey: MediaPlayerData.MediaSortKey?,
-    ) {
-        backgroundExecutor.execute {
-            val mediaViewHolder = createMediaViewHolderInBg()
-            // Add the new player in the main thread.
-            mainExecutor.execute {
                 val newPlayer = mediaControlPanelFactory.get()
-                newPlayer.attachPlayer(mediaViewHolder)
+                newPlayer.attachPlayer(
+                    MediaViewHolder.create(LayoutInflater.from(context), mediaContent)
+                )
                 newPlayer.mediaViewController.sizeChangedListener = this::updateCarouselDimensions
                 val lp =
                     LinearLayout.LayoutParams(
@@ -694,16 +645,36 @@
                 } else {
                     needsReordering = true
                 }
-                updatePageIndicator()
-                mediaCarouselScrollHandler.onPlayersChanged()
-                mediaFrame.requiresRemeasuring = true
+            } else {
+                existingPlayer.bindPlayer(data, key)
+                MediaPlayerData.addMediaPlayer(
+                    key,
+                    data,
+                    existingPlayer,
+                    systemClock,
+                    isSsReactivated,
+                    debugLogger
+                )
+                val packageName = MediaPlayerData.smartspaceMediaData?.packageName ?: String()
+                // In case of recommendations hits.
+                // Check the playing status of media player and the package name.
+                // To make sure we scroll to the right app's media player.
+                if (
+                    isReorderingAllowed ||
+                        shouldScrollToKey &&
+                            data.isPlaying == true &&
+                            packageName == data.packageName
+                ) {
+                    reorderAllPlayers(curVisibleMediaKey, key)
+                } else {
+                    needsReordering = true
+                }
             }
+            updatePageIndicator()
+            mediaCarouselScrollHandler.onPlayersChanged()
+            mediaFrame.requiresRemeasuring = true
+            return existingPlayer == null
         }
-    }
-
-    private fun createMediaViewHolderInBg(): MediaViewHolder {
-        return MediaViewHolder.create(LayoutInflater.from(context), mediaContent)
-    }
 
     private fun addSmartspaceMediaRecommendations(
         key: String,
@@ -737,14 +708,15 @@
                     debugLogger.logPotentialMemoryLeak(existingSmartspaceMediaKey)
                 }
             }
+
             val newRecs = mediaControlPanelFactory.get()
-            val recommendationViewHolder =
+            newRecs.attachRecommendation(
                 RecommendationViewHolder.create(
                     LayoutInflater.from(context),
                     mediaContent,
                     mediaFlags.isRecommendationCardUpdateEnabled()
                 )
-            newRecs.attachRecommendation(recommendationViewHolder)
+            )
             newRecs.mediaViewController.sizeChangedListener = this::updateCarouselDimensions
             val lp =
                 LinearLayout.LayoutParams(
@@ -768,6 +740,17 @@
             reorderAllPlayers(curVisibleMediaKey)
             updatePageIndicator()
             mediaFrame.requiresRemeasuring = true
+            // Check postcondition: mediaContent should have the same number of children as there
+            // are
+            // elements in mediaPlayers.
+            if (MediaPlayerData.players().size != mediaContent.childCount) {
+                Log.e(
+                    TAG,
+                    "Size of players list and number of views in carousel are out of sync. " +
+                        "Players size is ${MediaPlayerData.players().size}. " +
+                        "View count is ${mediaContent.childCount}."
+                )
+            }
         }
 
     fun removePlayer(
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselControllerLogger.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselControllerLogger.kt
index 35bda15..9af11b9 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselControllerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselControllerLogger.kt
@@ -42,8 +42,16 @@
             }
         )
 
-    fun logMediaLoaded(key: String) =
-        buffer.log(TAG, LogLevel.DEBUG, { str1 = key }, { "add player $str1" })
+    fun logMediaLoaded(key: String, active: Boolean) =
+        buffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            {
+                str1 = key
+                bool1 = active
+            },
+            { "add player $str1, active: $bool1" }
+        )
 
     fun logMediaRemoved(key: String) =
         buffer.log(TAG, LogLevel.DEBUG, { str1 = key }, { "removing player $str1" })
@@ -69,6 +77,10 @@
             },
             { "removing recommendation $str1, immediate=$bool1" }
         )
+
+    fun logCarouselHidden() = buffer.log(TAG, LogLevel.DEBUG, {}, { "hiding carousel" })
+
+    fun logCarouselVisible() = buffer.log(TAG, LogLevel.DEBUG, {}, { "showing carousel" })
 }
 
 private const val TAG = "MediaCarouselCtlrLog"
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
index 4ab93da..36eab39 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
@@ -31,12 +31,15 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.ColorStateList;
+import android.graphics.Bitmap;
 import android.graphics.BlendMode;
 import android.graphics.Color;
 import android.graphics.ColorMatrix;
 import android.graphics.ColorMatrixColorFilter;
+import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.graphics.drawable.Animatable;
+import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.GradientDrawable;
@@ -62,7 +65,6 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.UiThread;
-import androidx.appcompat.content.res.AppCompatResources;
 import androidx.constraintlayout.widget.ConstraintSet;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -145,6 +147,12 @@
     private static final int SMARTSPACE_CARD_CLICK_EVENT = 760;
     protected static final int SMARTSPACE_CARD_DISMISS_EVENT = 761;
 
+    private static final float REC_MEDIA_COVER_SCALE_FACTOR = 1.25f;
+    private static final float MEDIA_SCRIM_START_ALPHA = 0.25f;
+    private static final float MEDIA_REC_SCRIM_START_ALPHA = 0.15f;
+    private static final float MEDIA_PLAYER_SCRIM_END_ALPHA = 1.0f;
+    private static final float MEDIA_REC_SCRIM_END_ALPHA = 1.0f;
+
     private static final Intent SETTINGS_INTENT = new Intent(ACTION_MEDIA_CONTROLS_SETTINGS);
 
     // Buttons to show in small player when using semantic actions
@@ -510,16 +518,15 @@
                 mLogger.logTapContentView(mUid, mPackageName, mInstanceId);
                 logSmartspaceCardReported(SMARTSPACE_CARD_CLICK_EVENT);
 
-                // See StatusBarNotificationActivityStarter#onNotificationClicked
                 boolean showOverLockscreen = mKeyguardStateController.isShowing()
-                        && mActivityIntentHelper.wouldShowOverLockscreen(clickIntent.getIntent(),
+                        && mActivityIntentHelper.wouldPendingShowOverLockscreen(clickIntent,
                         mLockscreenUserManager.getCurrentUserId());
-
                 if (showOverLockscreen) {
-                    mActivityStarter.startActivity(clickIntent.getIntent(),
-                            /* dismissShade */ true,
-                            /* animationController */ null,
-                            /* showOverLockscreenWhenLocked */ true);
+                    try {
+                        clickIntent.send();
+                    } catch (PendingIntent.CanceledException e) {
+                        Log.e(TAG, "Pending intent for " + key + " was cancelled");
+                    }
                 } else {
                     mActivityStarter.postStartActivityDismissingKeyguard(clickIntent,
                             buildLaunchAnimatorController(mMediaViewHolder.getPlayer()));
@@ -639,12 +646,15 @@
                     } else {
                         mLogger.logOpenOutputSwitcher(mUid, mPackageName, mInstanceId);
                         if (device.getIntent() != null) {
-                            if (device.getIntent().isActivity()) {
-                                mActivityStarter.startActivity(
-                                        device.getIntent().getIntent(), true);
+                            PendingIntent deviceIntent = device.getIntent();
+                            boolean showOverLockscreen = mKeyguardStateController.isShowing()
+                                    && mActivityIntentHelper.wouldPendingShowOverLockscreen(
+                                        deviceIntent, mLockscreenUserManager.getCurrentUserId());
+                            if (deviceIntent.isActivity() && !showOverLockscreen) {
+                                mActivityStarter.postStartActivityDismissingKeyguard(deviceIntent);
                             } else {
                                 try {
-                                    device.getIntent().send();
+                                    deviceIntent.send();
                                 } catch (PendingIntent.CanceledException e) {
                                     Log.e(TAG, "Device pending intent was canceled");
                                 }
@@ -776,7 +786,7 @@
             WallpaperColors wallpaperColors = getWallpaperColor(artworkIcon);
             if (wallpaperColors != null) {
                 mutableColorScheme = new ColorScheme(wallpaperColors, true, Style.CONTENT);
-                artwork = addGradientToIcon(artworkIcon, mutableColorScheme, width, height);
+                artwork = addGradientToPlayerAlbum(artworkIcon, mutableColorScheme, width, height);
                 isArtworkBound = true;
             } else {
                 // If there's no artwork, use colors from the app icon
@@ -866,8 +876,9 @@
         Trace.beginAsyncSection(traceName, traceCookie);
 
         // Capture width & height from views in foreground for artwork scaling in background
-        int width = mRecommendationViewHolder.getMediaCoverContainers().get(0).getMeasuredWidth();
-        int height = mRecommendationViewHolder.getMediaCoverContainers().get(0).getMeasuredHeight();
+        int width = mContext.getResources().getDimensionPixelSize(R.dimen.qs_media_rec_album_width);
+        int height = mContext.getResources().getDimensionPixelSize(
+                R.dimen.qs_media_rec_album_height_expanded);
 
         mBackgroundExecutor.execute(() -> {
             // Album art
@@ -877,7 +888,8 @@
             WallpaperColors wallpaperColors = getWallpaperColor(artworkIcon);
             if (wallpaperColors != null) {
                 mutableColorScheme = new ColorScheme(wallpaperColors, true, Style.CONTENT);
-                artwork = addGradientToIcon(artworkIcon, mutableColorScheme, width, height);
+                artwork = addGradientToRecommendationAlbum(artworkIcon, mutableColorScheme, width,
+                        height);
             } else {
                 artwork = new ColorDrawable(Color.TRANSPARENT);
             }
@@ -886,6 +898,11 @@
                 // Bind the artwork drawable to media cover.
                 ImageView mediaCover =
                         mRecommendationViewHolder.getMediaCoverItems().get(itemIndex);
+                // Rescale media cover
+                Matrix coverMatrix = new Matrix(mediaCover.getImageMatrix());
+                coverMatrix.postScale(REC_MEDIA_COVER_SCALE_FACTOR, REC_MEDIA_COVER_SCALE_FACTOR,
+                        0.5f * width, 0.5f * height);
+                mediaCover.setImageMatrix(coverMatrix);
                 mediaCover.setImageDrawable(artwork);
 
                 // Set up the app icon.
@@ -907,40 +924,62 @@
     // This method should be called from a background thread. WallpaperColors.fromBitmap takes a
     // good amount of time. We do that work on the background executor to avoid stalling animations
     // on the UI Thread.
-    private WallpaperColors getWallpaperColor(Icon artworkIcon) {
+    @VisibleForTesting
+    protected WallpaperColors getWallpaperColor(Icon artworkIcon) {
         if (artworkIcon != null) {
             if (artworkIcon.getType() == Icon.TYPE_BITMAP
                     || artworkIcon.getType() == Icon.TYPE_ADAPTIVE_BITMAP) {
                 // Avoids extra processing if this is already a valid bitmap
-                return WallpaperColors
-                        .fromBitmap(artworkIcon.getBitmap());
+                Bitmap artworkBitmap = artworkIcon.getBitmap();
+                if (artworkBitmap.isRecycled()) {
+                    Log.d(TAG, "Cannot load wallpaper color from a recycled bitmap");
+                    return null;
+                }
+                return WallpaperColors.fromBitmap(artworkBitmap);
             } else {
                 Drawable artworkDrawable = artworkIcon.loadDrawable(mContext);
                 if (artworkDrawable != null) {
-                    return WallpaperColors
-                            .fromDrawable(artworkIcon.loadDrawable(mContext));
+                    return WallpaperColors.fromDrawable(artworkDrawable);
                 }
             }
         }
         return null;
     }
 
-    private LayerDrawable addGradientToIcon(
-            Icon artworkIcon,
-            ColorScheme mutableColorScheme,
-            int width,
-            int height
-    ) {
+    @VisibleForTesting
+    protected LayerDrawable addGradientToPlayerAlbum(Icon artworkIcon,
+            ColorScheme mutableColorScheme, int width, int height) {
         Drawable albumArt = getScaledBackground(artworkIcon, width, height);
-        GradientDrawable gradient = (GradientDrawable) AppCompatResources
-                .getDrawable(mContext, R.drawable.qs_media_scrim);
+        GradientDrawable gradient = (GradientDrawable) mContext.getDrawable(
+                R.drawable.qs_media_scrim).mutate();
+        return setupGradientColorOnDrawable(albumArt, gradient, mutableColorScheme,
+                MEDIA_SCRIM_START_ALPHA, MEDIA_PLAYER_SCRIM_END_ALPHA);
+    }
+
+    @VisibleForTesting
+    protected LayerDrawable addGradientToRecommendationAlbum(Icon artworkIcon,
+            ColorScheme mutableColorScheme, int width, int height) {
+        // First try scaling rec card using bitmap drawable.
+        // If returns null, set drawable bounds.
+        Drawable albumArt = getScaledRecommendationCover(artworkIcon, width, height);
+        if (albumArt == null) {
+            albumArt = getScaledBackground(artworkIcon, width, height);
+        }
+        GradientDrawable gradient = (GradientDrawable) mContext.getDrawable(
+                R.drawable.qs_media_rec_scrim).mutate();
+        return setupGradientColorOnDrawable(albumArt, gradient, mutableColorScheme,
+                MEDIA_REC_SCRIM_START_ALPHA, MEDIA_REC_SCRIM_END_ALPHA);
+    }
+
+    private LayerDrawable setupGradientColorOnDrawable(Drawable albumArt, GradientDrawable gradient,
+            ColorScheme mutableColorScheme, float startAlpha, float endAlpha) {
         gradient.setColors(new int[] {
                 ColorUtilKt.getColorWithAlpha(
                         MediaColorSchemesKt.backgroundStartFromScheme(mutableColorScheme),
-                        0.25f),
+                        startAlpha),
                 ColorUtilKt.getColorWithAlpha(
                         MediaColorSchemesKt.backgroundEndFromScheme(mutableColorScheme),
-                        0.9f),
+                        endAlpha),
         });
         return new LayerDrawable(new Drawable[] { albumArt, gradient });
     }
@@ -1334,7 +1373,8 @@
                         itemIndex
                 );
             } else {
-                mediaCoverImageView.setImageIcon(recommendation.getIcon());
+                mediaCoverImageView.post(
+                        () -> mediaCoverImageView.setImageIcon(recommendation.getIcon()));
             }
 
             // Set up the media item's click listener if applicable.
@@ -1586,6 +1626,29 @@
     }
 
     /**
+     * Scale artwork to fill the background of media covers in recommendation card.
+     */
+    @UiThread
+    private Drawable getScaledRecommendationCover(Icon artworkIcon, int width, int height) {
+        if (width == 0 || height == 0) {
+            return null;
+        }
+        if (artworkIcon != null) {
+            Bitmap bitmap;
+            if (artworkIcon.getType() == Icon.TYPE_BITMAP
+                    || artworkIcon.getType() == Icon.TYPE_ADAPTIVE_BITMAP) {
+                Bitmap artworkBitmap = artworkIcon.getBitmap();
+                if (artworkBitmap != null) {
+                    bitmap = Bitmap.createScaledBitmap(artworkIcon.getBitmap(), width,
+                            height, false);
+                    return new BitmapDrawable(mContext.getResources(), bitmap);
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
      * Get the current media controller
      *
      * @return the controller
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
index 7fc7bdb..e10d74d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
@@ -639,7 +639,9 @@
     ) =
         traceSection("MediaHierarchyManager#updateDesiredLocation") {
             val desiredLocation = calculateLocation()
-            if (desiredLocation != this.desiredLocation || forceStateUpdate) {
+            if (
+                desiredLocation != this.desiredLocation || forceStateUpdate && !blockLocationChanges
+            ) {
                 if (this.desiredLocation >= 0 && desiredLocation != this.desiredLocation) {
                     // Only update previous location when it actually changes
                     previousLocation = this.desiredLocation
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt
index 0788e61..7a1302c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt
@@ -89,6 +89,9 @@
                 R.id.turbulence_noise_view,
                 R.id.touch_ripple_view,
             )
+
+        // Sizing view id for recommendation card view.
+        val recSizingViewId = R.id.sizing_view
     }
 
     /** A listener when the current dimensions of the player change */
@@ -154,9 +157,11 @@
             return transitionLayout?.translationY ?: 0.0f
         }
 
-    /** A callback for RTL config changes */
+    /** A callback for config changes */
     private val configurationListener =
         object : ConfigurationController.ConfigurationListener {
+            var lastOrientation = -1
+
             override fun onConfigChanged(newConfig: Configuration?) {
                 // Because the TransitionLayout is not always attached (and calculates/caches layout
                 // results regardless of attach state), we have to force the layoutDirection of the
@@ -169,6 +174,27 @@
                         transitionLayout?.layoutDirection = layoutDirection
                         refreshState()
                     }
+                    val newOrientation = newConfig.orientation
+                    if (lastOrientation != newOrientation) {
+                        // Layout dimensions are possibly changing, so we need to update them. (at
+                        // least on large screen devices)
+                        lastOrientation = newOrientation
+                        // Update the height of media controls for the expanded layout. it is needed
+                        // for large screen devices.
+                        if (type == TYPE.PLAYER) {
+                            backgroundIds.forEach { id ->
+                                expandedLayout.getConstraint(id).layout.mHeight =
+                                    context.resources.getDimensionPixelSize(
+                                        R.dimen.qs_media_session_height_expanded
+                                    )
+                            }
+                        } else {
+                            expandedLayout.getConstraint(recSizingViewId).layout.mHeight =
+                                context.resources.getDimensionPixelSize(
+                                    R.dimen.qs_media_session_height_expanded
+                                )
+                        }
+                    }
                 }
             }
         }
@@ -195,13 +221,14 @@
      * The expanded constraint set used to render a expanded player. If it is modified, make sure to
      * call [refreshState]
      */
-    val collapsedLayout = ConstraintSet()
-
+    var collapsedLayout = ConstraintSet()
+        @VisibleForTesting set
     /**
      * The expanded constraint set used to render a collapsed player. If it is modified, make sure
      * to call [refreshState]
      */
-    val expandedLayout = ConstraintSet()
+    var expandedLayout = ConstraintSet()
+        @VisibleForTesting set
 
     /** Whether the guts are visible for the associated player. */
     var isGutsVisible = false
@@ -483,7 +510,7 @@
      */
     fun attach(transitionLayout: TransitionLayout, type: TYPE) =
         traceSection("MediaViewController#attach") {
-            updateMediaViewControllerType(type)
+            loadLayoutForType(type)
             logger.logMediaLocation("attach $type", currentStartLocation, currentEndLocation)
             this.transitionLayout = transitionLayout
             layoutController.attach(transitionLayout)
@@ -592,7 +619,11 @@
                         tmpState
                     )
             }
-            logger.logMediaSize("setCurrentState", result.width, result.height)
+            logger.logMediaSize(
+                "setCurrentState (progress $transitionProgress)",
+                result.width,
+                result.height
+            )
             layoutController.setState(
                 result,
                 applyImmediately,
@@ -641,7 +672,7 @@
         return result
     }
 
-    private fun updateMediaViewControllerType(type: TYPE) {
+    private fun loadLayoutForType(type: TYPE) {
         this.type = type
 
         // These XML resources contain ConstraintSets that will apply to this player type's layout
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt
index ee93c37..dbc2a5e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt
@@ -19,12 +19,13 @@
 import android.content.Context
 import android.content.pm.PackageManager
 import android.graphics.drawable.Drawable
-import androidx.annotation.AttrRes
+import androidx.annotation.ColorRes
 import androidx.annotation.DrawableRes
 import com.android.systemui.R
 import com.android.systemui.common.shared.model.ContentDescription
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.common.shared.model.TintedIcon
+import com.android.systemui.temporarydisplay.chipbar.ChipbarInfo.Companion.DEFAULT_ICON_TINT
 
 /** Utility methods for media tap-to-transfer. */
 class MediaTttUtils {
@@ -78,7 +79,7 @@
                     return IconInfo(
                         contentDescription,
                         MediaTttIcon.Loaded(packageManager.getApplicationIcon(appPackageName)),
-                        tintAttr = null,
+                        tint = null,
                         isAppIcon = true
                     )
                 } catch (e: PackageManager.NameNotFoundException) {
@@ -96,7 +97,7 @@
                     )
                 },
                 MediaTttIcon.Resource(R.drawable.ic_cast),
-                tintAttr = android.R.attr.textColorPrimary,
+                tint = DEFAULT_ICON_TINT,
                 isAppIcon = false
             )
         }
@@ -107,7 +108,7 @@
 data class IconInfo(
     val contentDescription: ContentDescription,
     val icon: MediaTttIcon,
-    @AttrRes val tintAttr: Int?,
+    @ColorRes val tint: Int?,
     /**
      * True if [drawable] is the app's icon, and false if [drawable] is some generic default icon.
      */
@@ -120,7 +121,7 @@
                 is MediaTttIcon.Loaded -> Icon.Loaded(icon.drawable, contentDescription)
                 is MediaTttIcon.Resource -> Icon.Resource(icon.res, contentDescription)
             }
-        return TintedIcon(iconOutput, tintAttr)
+        return TintedIcon(iconOutput, tint)
     }
 }
 
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 fab8c06..78082c3 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
@@ -225,8 +225,10 @@
         val iconRippleView: ReceiverChipRippleView = view.requireViewById(R.id.icon_glow_ripple)
         val rippleView: ReceiverChipRippleView = view.requireViewById(R.id.ripple)
         val translationYBy = getTranslationAmount()
+        // Expand ripple before translating icon container to make sure both views have same bounds.
+        rippleController.expandToInProgressState(rippleView, iconRippleView)
         // Make the icon container view starts animation from bottom of the screen.
-        iconContainerView.translationY += rippleController.getReceiverIconSize()
+        iconContainerView.translationY = rippleController.getReceiverIconSize().toFloat()
         animateViewTranslationAndFade(
             iconContainerView,
             translationYBy = -1 * translationYBy,
@@ -235,7 +237,6 @@
         ) {
             animateBouncingView(iconContainerView, translationYBy * BOUNCE_TRANSLATION_RATIO)
         }
-        rippleController.expandToInProgressState(rippleView, iconRippleView)
     }
 
     override fun animateViewOut(view: ViewGroup, removalReason: String?, onAnimationEnd: Runnable) {
@@ -293,7 +294,7 @@
 
     /** Returns the amount that the chip will be translated by in its intro animation. */
     private fun getTranslationAmount(): Float {
-        return rippleController.getRippleSize() * 0.5f
+        return rippleController.getReceiverIconSize() * 2f
     }
 
     private fun View.getAppIconView(): CachingIconView {
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
index 537dbb9..d3efae4 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
@@ -23,7 +23,6 @@
 import com.android.internal.logging.UiEventLogger
 import com.android.systemui.R
 import com.android.systemui.common.shared.model.Text
-import com.android.systemui.temporarydisplay.DEFAULT_TIMEOUT_MILLIS
 
 /**
  * A class enumerating all the possible states of the media tap-to-transfer chip on the sender
@@ -34,8 +33,8 @@
  *   state should not have the chip be displayed.
  * @property transferStatus the transfer status that the chip state represents.
  * @property endItem the item that should be displayed in the end section of the chip.
- * @property timeout the amount of time this chip should display on the screen before it times out
- *   and disappears.
+ * @property timeoutLength how long the chip should display on the screen before it times out and
+ *   disappears.
  */
 enum class ChipStateSender(
     @StatusBarManager.MediaTransferSenderState val stateInt: Int,
@@ -43,7 +42,7 @@
     @StringRes val stringResId: Int?,
     val transferStatus: TransferStatus,
     val endItem: SenderEndItem?,
-    val timeout: Int = DEFAULT_TIMEOUT_MILLIS,
+    val timeoutLength: TimeoutLength = TimeoutLength.DEFAULT,
 ) {
     /**
      * A state representing that the two devices are close but not close enough to *start* a cast to
@@ -56,6 +55,9 @@
         R.string.media_move_closer_to_start_cast,
         transferStatus = TransferStatus.NOT_STARTED,
         endItem = null,
+        // Give this view more time in case the loading view takes a bit to come in. (We don't want
+        // this view to disappear and then the loading view to appear quickly afterwards.)
+        timeoutLength = TimeoutLength.LONG,
     ) {
         override fun isValidNextState(nextState: ChipStateSender): Boolean {
             return nextState == FAR_FROM_RECEIVER ||
@@ -75,6 +77,7 @@
         R.string.media_move_closer_to_end_cast,
         transferStatus = TransferStatus.NOT_STARTED,
         endItem = null,
+        timeoutLength = TimeoutLength.LONG,
     ) {
         override fun isValidNextState(nextState: ChipStateSender): Boolean {
             return nextState == FAR_FROM_RECEIVER ||
@@ -92,7 +95,9 @@
         R.string.media_transfer_playing_different_device,
         transferStatus = TransferStatus.IN_PROGRESS,
         endItem = SenderEndItem.Loading,
-        timeout = TRANSFER_TRIGGERED_TIMEOUT_MILLIS
+        // Give this view more time in case the succeeded/failed view takes a bit to come in. (We
+        // don't want this view to disappear and then the next view to appear quickly afterwards.)
+        timeoutLength = TimeoutLength.LONG,
     ) {
         override fun isValidNextState(nextState: ChipStateSender): Boolean {
             return nextState == FAR_FROM_RECEIVER ||
@@ -111,7 +116,7 @@
         R.string.media_transfer_playing_this_device,
         transferStatus = TransferStatus.IN_PROGRESS,
         endItem = SenderEndItem.Loading,
-        timeout = TRANSFER_TRIGGERED_TIMEOUT_MILLIS
+        timeoutLength = TimeoutLength.LONG,
     ) {
         override fun isValidNextState(nextState: ChipStateSender): Boolean {
             return nextState == FAR_FROM_RECEIVER ||
@@ -325,9 +330,16 @@
     ) : SenderEndItem()
 }
 
-// Give the Transfer*Triggered states a longer timeout since those states represent an active
-// process and we should keep the user informed about it as long as possible (but don't allow it to
-// continue indefinitely).
-private const val TRANSFER_TRIGGERED_TIMEOUT_MILLIS = 30000
+/** Represents how long the chip should be visible before it times out. */
+enum class TimeoutLength {
+    /** A default timeout used for temporary displays at the top of the screen. */
+    DEFAULT,
+    /**
+     * A longer timeout. Should be used when the status is pending (e.g. loading), so that the user
+     * remains informed about the process for longer and so that the UI has more time to resolve the
+     * pending state before disappearing.
+     */
+    LONG,
+}
 
 private const val TAG = "ChipStateSender"
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt
index 6bb6906..c7c72a9 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt
@@ -56,6 +56,9 @@
     private val uiEventLogger: MediaTttSenderUiEventLogger,
 ) : CoreStartable, Dumpable {
 
+    // Since the media transfer display is similar to a heads-up notification, use the same timeout.
+    private val defaultTimeout = context.resources.getInteger(R.integer.heads_up_notification_decay)
+
     // A map to store current chip state per id.
     private var stateMap: MutableMap<String, ChipStateSender> = mutableMapOf()
 
@@ -165,6 +168,12 @@
                 logger.logPackageNotFound(packageName)
             }
 
+        val timeout =
+            when (chipStateSender.timeoutLength) {
+                TimeoutLength.DEFAULT -> defaultTimeout
+                TimeoutLength.LONG -> 2 * defaultTimeout
+            }
+
         return ChipbarInfo(
             // Display the app's icon as the start icon
             startIcon = icon.toTintedIcon(),
@@ -191,7 +200,7 @@
             allowSwipeToDismiss = true,
             windowTitle = MediaTttUtils.WINDOW_TITLE_SENDER,
             wakeReason = MediaTttUtils.WAKE_REASON_SENDER,
-            timeoutMs = chipStateSender.timeout,
+            timeoutMs = timeout,
             id = routeInfo.id,
             priority = ViewPriority.NORMAL,
         )
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProvider.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProvider.kt
index 1c90154..89f66b7 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProvider.kt
@@ -19,8 +19,8 @@
 import android.content.Context
 import android.content.res.Configuration
 import android.graphics.Rect
+import android.view.WindowInsets.Type
 import android.view.WindowManager
-import com.android.internal.R as AndroidR
 import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorScope
 import com.android.systemui.mediaprojection.appselector.view.TaskPreviewSizeProvider.TaskPreviewSizeListener
 import com.android.systemui.shared.recents.utilities.Utilities.isLargeScreen
@@ -64,7 +64,9 @@
         val isLargeScreen = isLargeScreen(context)
         if (isLargeScreen) {
             val taskbarSize =
-                context.resources.getDimensionPixelSize(AndroidR.dimen.taskbar_frame_height)
+                windowManager.currentWindowMetrics.windowInsets
+                    .getInsets(Type.tappableElement())
+                    .bottom
             height -= taskbarSize
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
index 1121e160..1da8718 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
@@ -41,11 +41,17 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.provider.Settings.Secure;
+import android.util.Log;
+import android.view.IRotationWatcher;
+import android.view.IWallpaperVisibilityListener;
+import android.view.IWindowManager;
 import android.view.View;
 import android.view.WindowInsets;
+import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityManager;
 
 import androidx.annotation.NonNull;
@@ -57,7 +63,9 @@
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler;
 import com.android.systemui.recents.OverviewProxyService;
+import com.android.systemui.settings.DisplayTracker;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.statusbar.CommandQueue;
@@ -90,6 +98,9 @@
         AccessibilityButtonTargetsObserver.TargetsChangedListener,
         OverviewProxyService.OverviewProxyListener, NavigationModeController.ModeChangedListener,
         Dumpable, CommandQueue.Callbacks {
+    private static final String TAG = NavBarHelper.class.getSimpleName();
+
+    private final Handler mHandler = new Handler(Looper.getMainLooper());
     private final AccessibilityManager mAccessibilityManager;
     private final Lazy<AssistManager> mAssistManagerLazy;
     private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy;
@@ -98,28 +109,60 @@
     private final SystemActions mSystemActions;
     private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
     private final AccessibilityButtonTargetsObserver mAccessibilityButtonTargetsObserver;
-    private final List<NavbarTaskbarStateUpdater> mA11yEventListeners = new ArrayList<>();
+    private final List<NavbarTaskbarStateUpdater> mStateListeners = new ArrayList<>();
     private final Context mContext;
     private final CommandQueue mCommandQueue;
     private final ContentResolver mContentResolver;
+    private final EdgeBackGestureHandler mEdgeBackGestureHandler;
+    private final IWindowManager mWm;
+    private final int mDefaultDisplayId;
     private boolean mAssistantAvailable;
     private boolean mLongPressHomeEnabled;
     private boolean mAssistantTouchGestureEnabled;
     private int mNavBarMode;
     private int mA11yButtonState;
+    private int mRotationWatcherRotation;
+    private boolean mTogglingNavbarTaskbar;
+    private boolean mWallpaperVisible;
 
     // Attributes used in NavBarHelper.CurrentSysuiState
     private int mWindowStateDisplayId;
     private @WindowVisibleState int mWindowState;
 
-    private final ContentObserver mAssistContentObserver = new ContentObserver(
-            new Handler(Looper.getMainLooper())) {
+    // Listens for changes to the assistant
+    private final ContentObserver mAssistContentObserver = new ContentObserver(mHandler) {
         @Override
         public void onChange(boolean selfChange, Uri uri) {
             updateAssistantAvailability();
         }
     };
 
+    // Listens for changes to the wallpaper visibility
+    private final IWallpaperVisibilityListener mWallpaperVisibilityListener =
+            new IWallpaperVisibilityListener.Stub() {
+                @Override
+                public void onWallpaperVisibilityChanged(boolean visible,
+                        int displayId) throws RemoteException {
+                    mHandler.post(() -> {
+                        mWallpaperVisible = visible;
+                        dispatchWallpaperVisibilityChanged(visible, displayId);
+                    });
+                }
+            };
+
+    // Listens for changes to display rotation
+    private final IRotationWatcher mRotationWatcher = new IRotationWatcher.Stub() {
+        @Override
+        public void onRotationChanged(final int rotation) {
+            // We need this to be scheduled as early as possible to beat the redrawing of
+            // window in response to the orientation change.
+            mHandler.postAtFrontOfQueue(() -> {
+                mRotationWatcherRotation = rotation;
+                dispatchRotationChanged(rotation);
+            });
+        }
+    };
+
     /**
      * @param context This is not display specific, then again neither is any of the code in
      *                this class. Once there's display specific code, we may want to create an
@@ -135,7 +178,10 @@
             Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
             KeyguardStateController keyguardStateController,
             NavigationModeController navigationModeController,
+            EdgeBackGestureHandler.Factory edgeBackGestureHandlerFactory,
+            IWindowManager wm,
             UserTracker userTracker,
+            DisplayTracker displayTracker,
             DumpManager dumpManager,
             CommandQueue commandQueue) {
         mContext = context;
@@ -147,18 +193,36 @@
         mKeyguardStateController = keyguardStateController;
         mUserTracker = userTracker;
         mSystemActions = systemActions;
-        accessibilityManager.addAccessibilityServicesStateChangeListener(this);
         mAccessibilityButtonModeObserver = accessibilityButtonModeObserver;
         mAccessibilityButtonTargetsObserver = accessibilityButtonTargetsObserver;
+        mWm = wm;
+        mDefaultDisplayId = displayTracker.getDefaultDisplayId();
+        mEdgeBackGestureHandler = edgeBackGestureHandlerFactory.create(context);
 
-        mAccessibilityButtonModeObserver.addListener(this);
-        mAccessibilityButtonTargetsObserver.addListener(this);
         mNavBarMode = navigationModeController.addListener(this);
+        mCommandQueue.addCallback(this);
         overviewProxyService.addCallback(this);
         dumpManager.registerDumpable(this);
     }
 
-    public void init() {
+    /**
+     * Hints to the helper that bars are being replaced, which is a signal to potentially suppress
+     * normal setup/cleanup when no bars are present.
+     */
+    public void setTogglingNavbarTaskbar(boolean togglingNavbarTaskbar) {
+        mTogglingNavbarTaskbar = togglingNavbarTaskbar;
+    }
+
+    /**
+     * Called when the first (non-replacing) bar is registered.
+     */
+    private void setupOnFirstBar() {
+        // Setup accessibility listeners
+        mAccessibilityManager.addAccessibilityServicesStateChangeListener(this);
+        mAccessibilityButtonModeObserver.addListener(this);
+        mAccessibilityButtonTargetsObserver.addListener(this);
+
+        // Setup assistant listener
         mContentResolver.registerContentObserver(
                 Settings.Secure.getUriFor(Settings.Secure.ASSISTANT),
                 false /* notifyForDescendants */, mAssistContentObserver, UserHandle.USER_ALL);
@@ -168,59 +232,114 @@
         mContentResolver.registerContentObserver(
                 Settings.Secure.getUriFor(Settings.Secure.ASSIST_TOUCH_GESTURE_ENABLED),
                 false, mAssistContentObserver, UserHandle.USER_ALL);
-        updateAssistantAvailability();
-        updateA11yState();
-        mCommandQueue.addCallback(this);
 
-    }
+        // Setup display rotation watcher
+        try {
+            mWm.watchRotation(mRotationWatcher, mDefaultDisplayId);
+        } catch (Exception e) {
+            Log.w(TAG, "Failed to register rotation watcher", e);
+        }
 
-    public void destroy() {
-        mContentResolver.unregisterContentObserver(mAssistContentObserver);
-        mCommandQueue.removeCallback(this);
+        // Setup wallpaper visibility listener
+        try {
+            mWallpaperVisible = mWm.registerWallpaperVisibilityListener(
+                    mWallpaperVisibilityListener, mDefaultDisplayId);
+        } catch (Exception e) {
+            Log.w(TAG, "Failed to register wallpaper visibility listener", e);
+        }
+
+        // Attach the back handler only when the first bar is registered
+        mEdgeBackGestureHandler.onNavBarAttached();
     }
 
     /**
+     * Called after the last (non-replacing) bar is unregistered.
+     */
+    private void cleanupAfterLastBar() {
+        // Clean up accessibility listeners
+        mAccessibilityManager.removeAccessibilityServicesStateChangeListener(this);
+        mAccessibilityButtonModeObserver.removeListener(this);
+        mAccessibilityButtonTargetsObserver.removeListener(this);
+
+        // Clean up assistant listeners
+        mContentResolver.unregisterContentObserver(mAssistContentObserver);
+
+        // Clean up display rotation watcher
+        try {
+            mWm.removeRotationWatcher(mRotationWatcher);
+        } catch (Exception e) {
+            Log.w(TAG, "Failed to unregister rotation watcher", e);
+        }
+
+        // Clean up wallpaper visibility listener
+        try {
+            mWm.unregisterWallpaperVisibilityListener(mWallpaperVisibilityListener,
+                    mDefaultDisplayId);
+        } catch (Exception e) {
+            Log.w(TAG, "Failed to register wallpaper visibility listener", e);
+        }
+
+        // No more bars, detach the back handler for now
+        mEdgeBackGestureHandler.onNavBarDetached();
+    }
+
+    /**
+     * Registers a listener for future updates to the shared navbar/taskbar state.
      * @param listener Will immediately get callbacks based on current state
      */
     public void registerNavTaskStateUpdater(NavbarTaskbarStateUpdater listener) {
-        mA11yEventListeners.add(listener);
-        listener.updateAccessibilityServicesState();
-        listener.updateAssistantAvailable(mAssistantAvailable, mLongPressHomeEnabled);
+        mStateListeners.add(listener);
+        if (!mTogglingNavbarTaskbar && mStateListeners.size() == 1) {
+            setupOnFirstBar();
+
+            // Update the state once the first bar is registered
+            updateAssistantAvailability();
+            updateA11yState();
+            mCommandQueue.recomputeDisableFlags(mContext.getDisplayId(), false /* animate */);
+        } else {
+            listener.updateAccessibilityServicesState();
+            listener.updateAssistantAvailable(mAssistantAvailable, mLongPressHomeEnabled);
+        }
+        listener.updateWallpaperVisibility(mWallpaperVisible, mDefaultDisplayId);
+        listener.updateRotationWatcherState(mRotationWatcherRotation);
     }
 
+    /**
+     * Removes a previously registered listener.
+     */
     public void removeNavTaskStateUpdater(NavbarTaskbarStateUpdater listener) {
-        mA11yEventListeners.remove(listener);
+        mStateListeners.remove(listener);
+        if (!mTogglingNavbarTaskbar && mStateListeners.isEmpty()) {
+            cleanupAfterLastBar();
+        }
     }
 
     private void dispatchA11yEventUpdate() {
-        for (NavbarTaskbarStateUpdater listener : mA11yEventListeners) {
+        for (NavbarTaskbarStateUpdater listener : mStateListeners) {
             listener.updateAccessibilityServicesState();
         }
     }
 
     private void dispatchAssistantEventUpdate(boolean assistantAvailable,
             boolean longPressHomeEnabled) {
-        for (NavbarTaskbarStateUpdater listener : mA11yEventListeners) {
+        for (NavbarTaskbarStateUpdater listener : mStateListeners) {
             listener.updateAssistantAvailable(assistantAvailable, longPressHomeEnabled);
         }
     }
 
     @Override
     public void onAccessibilityServicesStateChanged(AccessibilityManager manager) {
-        dispatchA11yEventUpdate();
         updateA11yState();
     }
 
     @Override
     public void onAccessibilityButtonModeChanged(int mode) {
         updateA11yState();
-        dispatchA11yEventUpdate();
     }
 
     @Override
     public void onAccessibilityButtonTargetsChanged(String targets) {
         updateA11yState();
-        dispatchA11yEventUpdate();
     }
 
     /**
@@ -262,6 +381,8 @@
             updateSystemAction(clickable, SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON);
             updateSystemAction(longClickable, SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON_CHOOSER);
         }
+
+        dispatchA11yEventUpdate();
     }
 
     /**
@@ -319,6 +440,10 @@
         return mLongPressHomeEnabled;
     }
 
+    public EdgeBackGestureHandler getEdgeBackGestureHandler() {
+        return mEdgeBackGestureHandler;
+    }
+
     @Override
     public void startAssistant(Bundle bundle) {
         mAssistManagerLazy.get().startAssist(bundle);
@@ -357,6 +482,18 @@
         mWindowState = state;
     }
 
+    private void dispatchWallpaperVisibilityChanged(boolean visible, int displayId) {
+        for (NavbarTaskbarStateUpdater listener : mStateListeners) {
+            listener.updateWallpaperVisibility(visible, displayId);
+        }
+    }
+
+    private void dispatchRotationChanged(int rotation) {
+        for (NavbarTaskbarStateUpdater listener : mStateListeners) {
+            listener.updateRotationWatcherState(rotation);
+        }
+    }
+
     public CurrentSysuiState getCurrentSysuiState() {
         return new CurrentSysuiState();
     }
@@ -368,6 +505,8 @@
     public interface NavbarTaskbarStateUpdater {
         void updateAccessibilityServicesState();
         void updateAssistantAvailable(boolean available, boolean longPressHomeEnabled);
+        default void updateWallpaperVisibility(boolean visible, int displayId) {}
+        default void updateRotationWatcherState(int rotation) {}
     }
 
     /** Data class to help Taskbar/Navbar initiate state correctly when switching between the two.*/
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index f817439..941770c 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -164,7 +164,6 @@
 import java.util.Map;
 import java.util.Optional;
 import java.util.concurrent.Executor;
-import java.util.function.Consumer;
 
 import javax.inject.Inject;
 
@@ -209,7 +208,6 @@
     private final Optional<Recents> mRecentsOptional;
     private final DeviceConfigProxy mDeviceConfigProxy;
     private final NavigationBarTransitions mNavigationBarTransitions;
-    private final EdgeBackGestureHandler mEdgeBackGestureHandler;
     private final Optional<BackAnimation> mBackAnimation;
     private final Handler mHandler;
     private final UiEventLogger mUiEventLogger;
@@ -221,6 +219,7 @@
     private final DisplayTracker mDisplayTracker;
     private final RegionSamplingHelper mRegionSamplingHelper;
     private final int mNavColorSampleMargin;
+    private EdgeBackGestureHandler mEdgeBackGestureHandler;
     private NavigationBarFrame mFrame;
 
     private @WindowVisibleState int mNavigationBarWindowState = WINDOW_STATE_SHOWING;
@@ -350,6 +349,21 @@
                     mLongPressHomeEnabled = longPressHomeEnabled;
                     updateAssistantEntrypoints(available, longPressHomeEnabled);
                 }
+
+                @Override
+                public void updateWallpaperVisibility(boolean visible, int displayId) {
+                    mNavigationBarTransitions.setWallpaperVisibility(visible);
+                }
+
+                @Override
+                public void updateRotationWatcherState(int rotation) {
+                    if (mIsOnDefaultDisplay && mView != null) {
+                        mView.getRotationButtonController().onRotationWatcherChanged(rotation);
+                        if (mView.needsReorient(rotation)) {
+                            repositionNavigationBar(rotation);
+                        }
+                    }
+                }
             };
 
     private final OverviewProxyListener mOverviewProxyListener = new OverviewProxyListener() {
@@ -543,7 +557,6 @@
             DeadZone deadZone,
             DeviceConfigProxy deviceConfigProxy,
             NavigationBarTransitions navigationBarTransitions,
-            EdgeBackGestureHandler edgeBackGestureHandler,
             Optional<BackAnimation> backAnimation,
             UserContextProvider userContextProvider,
             WakefulnessLifecycle wakefulnessLifecycle,
@@ -573,7 +586,6 @@
         mDeadZone = deadZone;
         mDeviceConfigProxy = deviceConfigProxy;
         mNavigationBarTransitions = navigationBarTransitions;
-        mEdgeBackGestureHandler = edgeBackGestureHandler;
         mBackAnimation = backAnimation;
         mHandler = mainHandler;
         mUiEventLogger = uiEventLogger;
@@ -589,6 +601,7 @@
         mWakefulnessLifecycle = wakefulnessLifecycle;
         mTaskStackChangeListeners = taskStackChangeListeners;
         mDisplayTracker = displayTracker;
+        mEdgeBackGestureHandler = navBarHelper.getEdgeBackGestureHandler();
 
         mNavColorSampleMargin = getResources()
                 .getDimensionPixelSize(R.dimen.navigation_handle_sample_horizontal_margin);
@@ -677,13 +690,14 @@
         // start firing, since the latter is source of truth
         parseCurrentSysuiState();
         mCommandQueue.addCallback(this);
-        mLongPressHomeEnabled = mNavBarHelper.getLongPressHomeEnabled();
-        mNavBarHelper.init();
         mHomeButtonLongPressDurationMs = Optional.of(mDeviceConfigProxy.getLong(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 HOME_BUTTON_LONG_PRESS_DURATION_MS,
                 /* defaultValue = */ 0
         )).filter(duration -> duration != 0);
+        // This currently MUST be called after mHomeButtonLongPressDurationMs is initialized since
+        // the registration callbacks will trigger code that uses it
+        mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
         mDeviceConfigProxy.addOnPropertiesChangedListener(
                 DeviceConfig.NAMESPACE_SYSTEMUI, mHandler::post, mOnPropertiesChangedListener);
 
@@ -707,9 +721,9 @@
         mCommandQueue.removeCallback(this);
         mWindowManager.removeViewImmediate(mView.getRootView());
         mNavigationModeController.removeListener(mModeChangedListener);
+        mEdgeBackGestureHandler.setStateChangeCallback(null);
 
         mNavBarHelper.removeNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
-        mNavBarHelper.destroy();
         mNotificationShadeDepthController.removeListener(mDepthListener);
 
         mDeviceConfigProxy.removeOnPropertiesChangedListener(mOnPropertiesChangedListener);
@@ -746,8 +760,6 @@
         mView.getViewRootImpl().addSurfaceChangedCallback(mSurfaceChangedCallback);
         notifyNavigationBarSurface();
 
-        mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
-
         mPipOptional.ifPresent(mView::addPipExclusionBoundsChangeListener);
         mBackAnimation.ifPresent(mView::registerBackAnimation);
 
@@ -765,7 +777,6 @@
         if (mIsOnDefaultDisplay) {
             final RotationButtonController rotationButtonController =
                     mView.getRotationButtonController();
-            rotationButtonController.setRotationCallback(mRotationWatcher);
 
             // Reset user rotation pref to match that of the WindowManager if starting in locked
             // mode. This will automatically happen when switching from auto-rotate to locked mode.
@@ -799,9 +810,6 @@
 
     @Override
     public void onViewDetached() {
-        final RotationButtonController rotationButtonController =
-                mView.getRotationButtonController();
-        rotationButtonController.setRotationCallback(null);
         mView.setUpdateActiveTouchRegionsCallback(null);
         getBarTransitions().destroy();
         mOverviewProxyService.removeCallback(mOverviewProxyListener);
@@ -1487,6 +1495,7 @@
     }
 
     void updateAccessibilityStateFlags() {
+        mLongPressHomeEnabled = mNavBarHelper.getLongPressHomeEnabled();
         if (mView != null) {
             int a11yFlags = mNavBarHelper.getA11yButtonState();
             boolean clickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
@@ -1702,12 +1711,6 @@
         return mNavBarMode == NAV_BAR_MODE_GESTURAL && mOrientationHandle != null;
     }
 
-    private final Consumer<Integer> mRotationWatcher = rotation -> {
-        if (mView != null && mView.needsReorient(rotation)) {
-            repositionNavigationBar(rotation);
-        }
-    };
-
     private final UserTracker.Callback mUserChangedCallback =
             new UserTracker.Callback() {
                 @Override
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index 153d5a6..21398e2 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -90,6 +90,7 @@
     private final DisplayTracker mDisplayTracker;
     private final DisplayManager mDisplayManager;
     private final TaskbarDelegate mTaskbarDelegate;
+    private final NavBarHelper mNavBarHelper;
     private int mNavMode;
     @VisibleForTesting boolean mIsLargeScreen;
 
@@ -133,6 +134,7 @@
         configurationController.addCallback(this);
         mConfigChanges.applyNewConfig(mContext.getResources());
         mNavMode = navigationModeController.addListener(this);
+        mNavBarHelper = navBarHelper;
         mTaskbarDelegate = taskbarDelegate;
         mTaskbarDelegate.setDependencies(commandQueue, overviewProxyService,
                 navBarHelper, navigationModeController, sysUiFlagsContainer,
@@ -241,10 +243,15 @@
 
         if (taskbarEnabled) {
             Trace.beginSection("NavigationBarController#initializeTaskbarIfNecessary");
+            final int displayId = mContext.getDisplayId();
+            // Hint to NavBarHelper if we are replacing an existing bar to skip extra work
+            mNavBarHelper.setTogglingNavbarTaskbar(mNavigationBars.contains(displayId));
             // Remove navigation bar when taskbar is showing
-            removeNavigationBar(mContext.getDisplayId());
-            mTaskbarDelegate.init(mContext.getDisplayId());
+            removeNavigationBar(displayId);
+            mTaskbarDelegate.init(displayId);
+            mNavBarHelper.setTogglingNavbarTaskbar(false);
             Trace.endSection();
+
         } else {
             mTaskbarDelegate.destroy();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java
index a4de9ff..1d73bc20 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java
@@ -21,11 +21,7 @@
 import static com.android.systemui.util.Utils.isGesturalModeOnDefaultDisplay;
 
 import android.graphics.Rect;
-import android.os.Handler;
-import android.os.RemoteException;
 import android.util.SparseArray;
-import android.view.IWallpaperVisibilityListener;
-import android.view.IWindowManager;
 import android.view.View;
 
 import com.android.systemui.R;
@@ -62,8 +58,6 @@
     }
 
     private final NavigationBarView mView;
-    @org.jetbrains.annotations.NotNull
-    private final IWindowManager mWindowManagerService;
     private final LightBarTransitionsController mLightTransitionsController;
     private final DisplayTracker mDisplayTracker;
     private final boolean mAllowAutoDimWallpaperNotVisible;
@@ -75,37 +69,20 @@
     private int mNavBarMode = NAV_BAR_MODE_3BUTTON;
     private List<DarkIntensityListener> mDarkIntensityListeners;
 
-    private final Handler mHandler = Handler.getMain();
-    private final IWallpaperVisibilityListener mWallpaperVisibilityListener =
-            new IWallpaperVisibilityListener.Stub() {
-        @Override
-        public void onWallpaperVisibilityChanged(boolean newVisibility,
-        int displayId) throws RemoteException {
-            mWallpaperVisible = newVisibility;
-            mHandler.post(() -> applyLightsOut(true, false));
-        }
-    };
-
     @Inject
     public NavigationBarTransitions(
             NavigationBarView view,
-            IWindowManager windowManagerService,
             LightBarTransitionsController.Factory lightBarTransitionsControllerFactory,
             DisplayTracker displayTracker) {
         super(view, R.drawable.nav_background);
+
         mView = view;
-        mWindowManagerService = windowManagerService;
         mLightTransitionsController = lightBarTransitionsControllerFactory.create(this);
         mDisplayTracker = displayTracker;
         mAllowAutoDimWallpaperNotVisible = view.getContext().getResources()
                 .getBoolean(R.bool.config_navigation_bar_enable_auto_dim_no_visible_wallpaper);
         mDarkIntensityListeners = new ArrayList();
 
-        try {
-            mWallpaperVisible = mWindowManagerService.registerWallpaperVisibilityListener(
-                    mWallpaperVisibilityListener, mDisplayTracker.getDefaultDisplayId());
-        } catch (RemoteException e) {
-        }
         mView.addOnLayoutChangeListener(
                 (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
                     View currentView = mView.getCurrentView();
@@ -127,14 +104,14 @@
 
     @Override
     public void destroy() {
-        try {
-            mWindowManagerService.unregisterWallpaperVisibilityListener(mWallpaperVisibilityListener,
-                    mDisplayTracker.getDefaultDisplayId());
-        } catch (RemoteException e) {
-        }
         mLightTransitionsController.destroy();
     }
 
+    void setWallpaperVisibility(boolean visible) {
+        mWallpaperVisible = visible;
+        applyLightsOut(true, false);
+    }
+
     @Override
     public void setAutoDim(boolean autoDim) {
         // Ensure we aren't in gestural nav if we are triggering auto dim
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 63fb499..5d598e8 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -1093,13 +1093,10 @@
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
-        // This needs to happen first as it can changed the enabled state which can affect whether
-        // the back button is visible
-        mEdgeBackGestureHandler.onNavBarAttached();
         requestApplyInsets();
         reorient();
         if (mRotationButtonController != null) {
-            mRotationButtonController.registerListeners();
+            mRotationButtonController.registerListeners(false /* registerRotationWatcher */);
         }
 
         updateNavButtonIcons();
@@ -1115,8 +1112,6 @@
             mFloatingRotationButton.hide();
             mRotationButtonController.unregisterListeners();
         }
-
-        mEdgeBackGestureHandler.onNavBarDetached();
     }
 
     void dump(PrintWriter pw) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
index 5b02aaf..85d0ce5 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -93,7 +93,7 @@
         Dumpable {
     private static final String TAG = TaskbarDelegate.class.getSimpleName();
 
-    private final EdgeBackGestureHandler mEdgeBackGestureHandler;
+    private EdgeBackGestureHandler mEdgeBackGestureHandler;
     private final LightBarTransitionsController.Factory mLightBarTransitionsControllerFactory;
     private boolean mInitialized;
     private CommandQueue mCommandQueue;
@@ -171,15 +171,15 @@
     private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
     @Inject
     public TaskbarDelegate(Context context,
-            EdgeBackGestureHandler.Factory edgeBackGestureHandlerFactory,
             LightBarTransitionsController.Factory lightBarTransitionsControllerFactory,
             StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
         mLightBarTransitionsControllerFactory = lightBarTransitionsControllerFactory;
-        mEdgeBackGestureHandler = edgeBackGestureHandlerFactory.create(context);
 
         mContext = context;
         mDisplayManager = mContext.getSystemService(DisplayManager.class);
-        mPipListener = mEdgeBackGestureHandler::setPipStashExclusionBounds;
+        mPipListener = (bounds) -> {
+            mEdgeBackGestureHandler.setPipStashExclusionBounds(bounds);
+        };
         mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
         mStatusBarKeyguardViewManager.setTaskbarDelegate(this);
     }
@@ -207,6 +207,7 @@
         mBackAnimation = backAnimation;
         mLightBarTransitionsController = createLightBarTransitionsController();
         mTaskStackChangeListeners = taskStackChangeListeners;
+        mEdgeBackGestureHandler = navBarHelper.getEdgeBackGestureHandler();
     }
 
     // Separated into a method to keep setDependencies() clean/readable.
@@ -239,8 +240,6 @@
         mOverviewProxyService.addCallback(this);
         onNavigationModeChanged(mNavigationModeController.addListener(this));
         mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
-        mNavBarHelper.init();
-        mEdgeBackGestureHandler.onNavBarAttached();
         // Initialize component callback
         Display display = mDisplayManager.getDisplay(displayId);
         mWindowContext = mContext.createWindowContext(display, TYPE_APPLICATION, null);
@@ -264,8 +263,6 @@
         mOverviewProxyService.removeCallback(this);
         mNavigationModeController.removeListener(this);
         mNavBarHelper.removeNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
-        mNavBarHelper.destroy();
-        mEdgeBackGestureHandler.onNavBarDetached();
         mScreenPinningNotify = null;
         mWindowContext = null;
         mAutoHideController.setNavigationBar(null);
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanel.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanel.kt
index f335733..c76cfbd 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanel.kt
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanel.kt
@@ -2,19 +2,15 @@
 
 import android.content.Context
 import android.content.res.Configuration
-import android.content.res.TypedArray
 import android.graphics.Canvas
 import android.graphics.Paint
 import android.graphics.Path
 import android.graphics.RectF
 import android.util.MathUtils.min
-import android.util.TypedValue
 import android.view.View
-import androidx.appcompat.view.ContextThemeWrapper
 import androidx.dynamicanimation.animation.FloatPropertyCompat
 import androidx.dynamicanimation.animation.SpringAnimation
 import androidx.dynamicanimation.animation.SpringForce
-import com.android.internal.R.style.Theme_DeviceDefault
 import com.android.internal.util.LatencyTracker
 import com.android.settingslib.Utils
 import com.android.systemui.navigationbar.gestural.BackPanelController.DelayedOnAnimationEndListener
@@ -159,26 +155,21 @@
         val isDeviceInNightTheme = resources.configuration.uiMode and
                 Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
 
-        val colorControlActivated = ContextThemeWrapper(context, Theme_DeviceDefault)
-                .run {
-                    val typedValue = TypedValue()
-                    val a: TypedArray = obtainStyledAttributes(typedValue.data,
-                            intArrayOf(android.R.attr.colorControlActivated))
-                    val color = a.getColor(0, 0)
-                    a.recycle()
-                    color
-                }
+        arrowPaint.color = Utils.getColorAttrDefaultColor(context,
+            if (isDeviceInNightTheme) {
+                com.android.internal.R.attr.colorAccentPrimary
+            } else {
+                com.android.internal.R.attr.textColorPrimary
+            }
+        )
 
-        val colorPrimary =
-                Utils.getColorAttrDefaultColor(context, com.android.internal.R.attr.colorPrimary)
-
-        arrowPaint.color = Utils.getColorAccentDefaultColor(context)
-
-        arrowBackgroundPaint.color = if (isDeviceInNightTheme) {
-            colorPrimary
-        } else {
-            colorControlActivated
-        }
+        arrowBackgroundPaint.color = Utils.getColorAttrDefaultColor(context,
+            if (isDeviceInNightTheme) {
+                com.android.internal.R.attr.colorSurface
+            } else {
+                com.android.internal.R.attr.colorAccentSecondary
+            }
+        )
     }
 
     inner class AnimatedFloat(
@@ -414,9 +405,9 @@
     ) {
         horizontalTranslation.updateRestingPosition(restingParams.horizontalTranslation)
         scale.updateRestingPosition(restingParams.scale)
-        arrowAlpha.updateRestingPosition(restingParams.arrowDimens.alpha)
         backgroundAlpha.updateRestingPosition(restingParams.backgroundDimens.alpha)
 
+        arrowAlpha.updateRestingPosition(restingParams.arrowDimens.alpha, animate)
         arrowLength.updateRestingPosition(restingParams.arrowDimens.length, animate)
         arrowHeight.updateRestingPosition(restingParams.arrowDimens.height, animate)
         scalePivotX.updateRestingPosition(restingParams.backgroundDimens.width, animate)
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt
index 367d125..ce1c8da 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt
@@ -55,12 +55,12 @@
 
 internal const val MIN_DURATION_ACTIVE_ANIMATION = 300L
 private const val MIN_DURATION_CANCELLED_ANIMATION = 200L
-private const val MIN_DURATION_COMMITTED_ANIMATION = 200L
+private const val MIN_DURATION_COMMITTED_ANIMATION = 120L
 private const val MIN_DURATION_INACTIVE_BEFORE_FLUNG_ANIMATION = 50L
 private const val MIN_DURATION_CONSIDERED_AS_FLING = 100L
 
 private const val FAILSAFE_DELAY_MS = 350L
-private const val POP_ON_FLING_DELAY = 160L
+private const val POP_ON_FLING_DELAY = 140L
 
 internal val VIBRATE_ACTIVATED_EFFECT =
         VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK)
@@ -148,8 +148,6 @@
     private var gestureSinceActionDown = 0L
     private var gestureEntryTime = 0L
     private var gestureActiveTime = 0L
-    private var gestureInactiveOrEntryTime = 0L
-    private var gestureArrowStrokeVisibleTime = 0L
 
     private val elapsedTimeSinceActionDown
         get() = SystemClock.uptimeMillis() - gestureSinceActionDown
@@ -441,34 +439,44 @@
 
         updateArrowStateOnMove(yTranslation, xTranslation)
 
-        when (currentState) {
-            GestureState.ACTIVE -> {
-                stretchActiveBackIndicator(fullScreenProgress(xTranslation))
-            }
-            GestureState.ENTRY -> {
-                val progress = staticThresholdProgress(xTranslation)
-                stretchEntryBackIndicator(progress)
-
-                params.arrowStrokeAlphaSpring.get(progress).takeIf { it.isNewState }?.let {
-                    mView.popArrowAlpha(0f, it.value)
-                }
-            }
-            GestureState.INACTIVE -> {
-                val progress = reactivationThresholdProgress(totalTouchDelta)
-                stretchInactiveBackIndicator(progress)
-
-                params.arrowStrokeAlphaSpring.get(progress).takeIf { it.isNewState }?.let {
-                    gestureArrowStrokeVisibleTime = SystemClock.uptimeMillis()
-                    mView.popArrowAlpha(0f, it.value)
-                }
-            }
-            else -> {}
+        val gestureProgress = when (currentState) {
+            GestureState.ACTIVE -> fullScreenProgress(xTranslation)
+            GestureState.ENTRY -> staticThresholdProgress(xTranslation)
+            GestureState.INACTIVE -> reactivationThresholdProgress(totalTouchDelta)
+            else -> null
         }
 
-        // set y translation
+        gestureProgress?.let {
+            when (currentState) {
+                GestureState.ACTIVE -> stretchActiveBackIndicator(gestureProgress)
+                GestureState.ENTRY -> stretchEntryBackIndicator(gestureProgress)
+                GestureState.INACTIVE -> stretchInactiveBackIndicator(gestureProgress)
+                else -> {}
+            }
+        }
+
+        setArrowStrokeAlpha(gestureProgress)
         setVerticalTranslation(yOffset)
     }
 
+    private fun setArrowStrokeAlpha(gestureProgress: Float?) {
+        val strokeAlphaProgress = when (currentState) {
+            GestureState.ENTRY -> gestureProgress
+            GestureState.INACTIVE -> gestureProgress
+            GestureState.ACTIVE,
+            GestureState.FLUNG,
+            GestureState.COMMITTED -> 1f
+            GestureState.CANCELLED,
+            GestureState.GONE -> 0f
+        }
+
+        strokeAlphaProgress?.let { progress ->
+            params.arrowStrokeAlphaSpring.get(progress).takeIf { it.isNewState }?.let {
+                mView.popArrowAlpha(0f, it.value)
+            }
+        }
+    }
+
     private fun setVerticalTranslation(yOffset: Float) {
         val yTranslation = abs(yOffset)
         val maxYOffset = (mView.height - params.entryIndicator.backgroundDimens.height) / 2f
@@ -599,7 +607,7 @@
 
     private fun isFlungAwayFromEdge(endX: Float, startX: Float = touchDeltaStartX): Boolean {
         val minDistanceConsideredForFling = ViewConfiguration.get(context).scaledTouchSlop
-        val flingDistance = abs(endX - startX)
+        val flingDistance = if (mView.isLeftPanel) endX - startX else startX - endX
         val isPastFlingVelocity = isDragAwayFromEdge(
                 velocityPxPerSecThreshold =
                 ViewConfiguration.get(context).scaledMinimumFlingVelocity)
@@ -764,7 +772,7 @@
                             GestureState.ENTRY,
                             GestureState.INACTIVE -> params.entryIndicator.arrowDimens
                             GestureState.ACTIVE -> params.activeIndicator.arrowDimens
-                            GestureState.FLUNG,
+                            GestureState.FLUNG -> params.flungIndicator.arrowDimens
                             GestureState.COMMITTED -> params.committedIndicator.arrowDimens
                             GestureState.CANCELLED -> params.cancelledIndicator.arrowDimens
                         },
@@ -825,7 +833,6 @@
 
                 updateRestingArrowDimens()
                 gestureEntryTime = SystemClock.uptimeMillis()
-                gestureInactiveOrEntryTime = SystemClock.uptimeMillis()
             }
             GestureState.ACTIVE -> {
                 previousXTranslationOnActiveOffset = previousXTranslation
@@ -857,7 +864,13 @@
             }
 
             GestureState.INACTIVE -> {
-                gestureInactiveOrEntryTime = SystemClock.uptimeMillis()
+
+                // Typically entering INACTIVE means
+                // totalTouchDelta <= deactivationSwipeTriggerThreshold
+                // but because we can also independently enter this state
+                // if touch Y >> touch X, we force it to deactivationSwipeTriggerThreshold
+                // so that gesture progress in this state is consistent regardless of entry
+                totalTouchDelta = params.deactivationSwipeTriggerThreshold
 
                 val startingVelocity = convertVelocityToSpringStartingVelocity(
                         valueOnFastVelocity = -1.05f,
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index eea0e4c..c6f3968 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -453,7 +453,7 @@
     }
 
     /**
-     * @see NavigationBarView#onAttachedToWindow()
+     * Called when the nav/task bar is attached.
      */
     public void onNavBarAttached() {
         mIsAttached = true;
@@ -465,7 +465,7 @@
     }
 
     /**
-     * @see NavigationBarView#onDetachedFromWindow()
+     * Called when the nav/task bar is detached.
      */
     public void onNavBarDetached() {
         mIsAttached = false;
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgePanelParams.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgePanelParams.kt
index 0c00022..d46333a 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgePanelParams.kt
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgePanelParams.kt
@@ -9,8 +9,8 @@
 data class EdgePanelParams(private var resources: Resources) {
 
     data class ArrowDimens(
-            val length: Float = 0f,
-            val height: Float = 0f,
+            val length: Float? = 0f,
+            val height: Float? = 0f,
             val alpha: Float = 0f,
             var alphaSpring: SpringForce? = null,
             val heightSpring: SpringForce? = null,
@@ -139,17 +139,17 @@
 
         entryWidthInterpolator = PathInterpolator(.19f, 1.27f, .71f, .86f)
         entryWidthTowardsEdgeInterpolator = PathInterpolator(1f, -3f, 1f, 1.2f)
-        activeWidthInterpolator = PathInterpolator(.15f, .48f, .46f, .89f)
+        activeWidthInterpolator = PathInterpolator(.32f, 0f, .16f, .94f)
         arrowAngleInterpolator = entryWidthInterpolator
         translationInterpolator = PathInterpolator(0.2f, 1.0f, 1.0f, 1.0f)
         farCornerInterpolator = PathInterpolator(.03f, .19f, .14f, 1.09f)
         edgeCornerInterpolator = PathInterpolator(0f, 1.11f, .85f, .84f)
         heightInterpolator = PathInterpolator(1f, .05f, .9f, -0.29f)
 
-        val showArrowOnProgressValue = .2f
+        val showArrowOnProgressValue = .23f
         val showArrowOnProgressValueFactor = 1.05f
 
-        val entryActiveHorizontalTranslationSpring = createSpring(675f, 0.8f)
+        val entryActiveHorizontalTranslationSpring = createSpring(800f, 0.8f)
         val activeCommittedArrowLengthSpring = createSpring(1500f, 0.29f)
         val activeCommittedArrowHeightSpring = createSpring(1500f, 0.29f)
         val flungCommittedEdgeCornerSpring = createSpring(10000f, 1f)
@@ -178,7 +178,7 @@
                         height = getDimen(R.dimen.navigation_edge_entry_background_height),
                         edgeCornerRadius = getDimen(R.dimen.navigation_edge_entry_edge_corners),
                         farCornerRadius = getDimen(R.dimen.navigation_edge_entry_far_corners),
-                        alphaSpring = createSpring(900f, 1f),
+                        alphaSpring = createSpring(1100f, 1f),
                         widthSpring = createSpring(450f, 0.65f),
                         heightSpring = createSpring(1500f, 0.45f),
                         farCornerRadiusSpring = createSpring(300f, 0.5f),
@@ -232,7 +232,7 @@
                                 getDimen(R.dimen.navigation_edge_pre_threshold_edge_corners),
                         farCornerRadius =
                                 getDimen(R.dimen.navigation_edge_pre_threshold_far_corners),
-                        widthSpring = createSpring(200f, 0.65f),
+                        widthSpring = createSpring(250f, 0.65f),
                         heightSpring = createSpring(1500f, 0.45f),
                         farCornerRadiusSpring = createSpring(200f, 1f),
                         edgeCornerRadiusSpring = createSpring(150f, 0.5f),
@@ -244,6 +244,8 @@
                 arrowDimens = activeIndicator.arrowDimens.copy(
                         lengthSpring = activeCommittedArrowLengthSpring,
                         heightSpring = activeCommittedArrowHeightSpring,
+                        length = null,
+                        height = null,
                 ),
                 backgroundDimens = activeIndicator.backgroundDimens.copy(
                         alpha = 0f,
@@ -255,13 +257,15 @@
                         farCornerRadiusSpring = flungCommittedFarCornerSpring,
                 ),
                 scale = 0.85f,
-                scaleSpring = createSpring(650f, 1f),
+                scaleSpring = createSpring(1150f, 1f),
         )
 
         flungIndicator = committedIndicator.copy(
                 arrowDimens = committedIndicator.arrowDimens.copy(
                         lengthSpring = createSpring(850f, 0.46f),
                         heightSpring = createSpring(850f, 0.46f),
+                        length = activeIndicator.arrowDimens.length,
+                        height = activeIndicator.arrowDimens.height
                 ),
                 backgroundDimens = committedIndicator.backgroundDimens.copy(
                         widthSpring = flungCommittedWidthSpring,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 9d34df8..a8022bc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -51,6 +51,8 @@
 import com.android.systemui.animation.ShadeInterpolation;
 import com.android.systemui.compose.ComposeFacade;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.media.controls.ui.MediaHost;
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.plugins.qs.QSContainerController;
@@ -60,6 +62,7 @@
 import com.android.systemui.qs.footer.ui.binder.FooterActionsViewBinder;
 import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel;
 import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
@@ -112,6 +115,8 @@
     private final MediaHost mQqsMediaHost;
     private final QSFragmentComponent.Factory mQsComponentFactory;
     private final QSFragmentDisableFlagsLogger mQsFragmentDisableFlagsLogger;
+    private final LargeScreenShadeInterpolator mLargeScreenShadeInterpolator;
+    private final FeatureFlags mFeatureFlags;
     private final QSLogger mLogger;
     private final FooterActionsController mFooterActionsController;
     private final FooterActionsViewModel.Factory mFooterActionsViewModelFactory;
@@ -159,12 +164,7 @@
     // visible;
     private boolean mQsVisible;
 
-    /**
-     * Whether the notification panel uses the full width of the screen.
-     *
-     * Usually {@code true} on small screens, and {@code false} on large screens.
-     */
-    private boolean mIsNotificationPanelFullWidth;
+    private boolean mIsSmallScreen;
 
     @Inject
     public QSFragment(RemoteInputQuickSettingsDisabler remoteInputQsDisabler,
@@ -176,13 +176,17 @@
             QSFragmentDisableFlagsLogger qsFragmentDisableFlagsLogger,
             DumpManager dumpManager, QSLogger qsLogger,
             FooterActionsController footerActionsController,
-            FooterActionsViewModel.Factory footerActionsViewModelFactory) {
+            FooterActionsViewModel.Factory footerActionsViewModelFactory,
+            LargeScreenShadeInterpolator largeScreenShadeInterpolator,
+            FeatureFlags featureFlags) {
         mRemoteInputQuickSettingsDisabler = remoteInputQsDisabler;
         mQsMediaHost = qsMediaHost;
         mQqsMediaHost = qqsMediaHost;
         mQsComponentFactory = qsComponentFactory;
         mQsFragmentDisableFlagsLogger = qsFragmentDisableFlagsLogger;
         mLogger = qsLogger;
+        mLargeScreenShadeInterpolator = largeScreenShadeInterpolator;
+        mFeatureFlags = featureFlags;
         commandQueue.observe(getLifecycle(), this);
         mBypassController = keyguardBypassController;
         mStatusBarStateController = statusBarStateController;
@@ -607,7 +611,7 @@
 
     @Override
     public void setIsNotificationPanelFullWidth(boolean isFullWidth) {
-        mIsNotificationPanelFullWidth = isFullWidth;
+        mIsSmallScreen = isFullWidth;
     }
 
     @Override
@@ -632,7 +636,8 @@
                 && mLastKeyguardAndExpanded == onKeyguardAndExpanded
                 && mLastViewHeight == currentHeight
                 && mLastHeaderTranslation == headerTranslation
-                && mSquishinessFraction == squishinessFraction) {
+                && mSquishinessFraction == squishinessFraction
+                && mLastPanelFraction == panelExpansionFraction) {
             return;
         }
         mLastHeaderTranslation = headerTranslation;
@@ -710,7 +715,7 @@
     }
 
     private float calculateAlphaProgress(float panelExpansionFraction) {
-        if (mIsNotificationPanelFullWidth) {
+        if (mIsSmallScreen) {
             // Small screens. QS alpha is not animated.
             return 1;
         }
@@ -745,7 +750,12 @@
             // Alpha progress should be linear on lockscreen shade expansion.
             return progress;
         }
-        return ShadeInterpolation.getContentAlpha(progress);
+        if (mIsSmallScreen || !mFeatureFlags.isEnabled(
+                Flags.LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION)) {
+            return ShadeInterpolation.getContentAlpha(progress);
+        } else {
+            return mLargeScreenShadeInterpolator.getQsAlpha(progress);
+        }
     }
 
     @VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index 2668d2e..fdab9b1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -91,16 +91,19 @@
             new QSPanel.OnConfigurationChangedListener() {
                 @Override
                 public void onConfigurationChange(Configuration newConfig) {
-                    mQSLogger.logOnConfigurationChanged(
-                        /* lastOrientation= */ mLastOrientation,
-                        /* newOrientation= */ newConfig.orientation,
-                        /* containerName= */ mView.getDumpableTag());
-
-                    boolean previousSplitShadeState = mShouldUseSplitNotificationShade;
+                    final boolean previousSplitShadeState = mShouldUseSplitNotificationShade;
+                    final int previousOrientation = mLastOrientation;
                     mShouldUseSplitNotificationShade =
-                        LargeScreenUtils.shouldUseSplitNotificationShade(getResources());
+                            LargeScreenUtils.shouldUseSplitNotificationShade(getResources());
                     mLastOrientation = newConfig.orientation;
 
+                    mQSLogger.logOnConfigurationChanged(
+                        /* oldOrientation= */ previousOrientation,
+                        /* newOrientation= */ mLastOrientation,
+                        /* oldShouldUseSplitShade= */ previousSplitShadeState,
+                        /* newShouldUseSplitShade= */ mShouldUseSplitNotificationShade,
+                        /* containerName= */ mView.getDumpableTag());
+
                     switchTileLayoutIfNeeded();
                     onConfigurationChanged();
                     if (previousSplitShadeState != mShouldUseSplitNotificationShade) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index 7c2536d..d4854e1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -328,7 +328,7 @@
             if (listening) {
                 updateDefaultTileAndIcon();
                 refreshState();
-                if (!mServiceManager.isActiveTile()) {
+                if (!mServiceManager.isActiveTile() || !isTileReady()) {
                     mServiceManager.setBindRequested(true);
                     mService.onStartListening();
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
index adc7165..91ecaea 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -132,9 +132,8 @@
             mServices.remove(tile);
             mTokenMap.remove(service.getToken());
             mTiles.remove(tile.getComponent());
-            final String slot = tile.getComponent().getClassName();
-            // TileServices doesn't know how to add more than 1 icon per slot, so remove all
-            mMainHandler.post(() -> mStatusBarIconController.removeAllIconsForSlot(slot));
+            final String slot = getStatusBarIconSlotName(tile.getComponent());
+            mMainHandler.post(() -> mStatusBarIconController.removeIconForTile(slot));
         }
     }
 
@@ -308,12 +307,11 @@
                             ? new StatusBarIcon(userHandle, packageName, icon, 0, 0,
                                     contentDescription)
                             : null;
+                    final String slot = getStatusBarIconSlotName(componentName);
                     mMainHandler.post(new Runnable() {
                         @Override
                         public void run() {
-                            StatusBarIconController iconController = mStatusBarIconController;
-                            iconController.setIcon(componentName.getClassName(), statusIcon);
-                            iconController.setExternalIcon(componentName.getClassName());
+                            mStatusBarIconController.setIconFromTile(slot, statusIcon);
                         }
                     });
                 }
@@ -373,6 +371,12 @@
         mCommandQueue.removeCallback(mRequestListeningCallback);
     }
 
+    /** Returns the slot name that should be used when adding or removing status bar icons. */
+    private String getStatusBarIconSlotName(ComponentName componentName) {
+        return componentName.getClassName();
+    }
+
+
     private final CommandQueue.Callbacks mRequestListeningCallback = new CommandQueue.Callbacks() {
         @Override
         public void requestTileServiceListeningState(@NonNull ComponentName componentName) {
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 23c41db..5b461a6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt
@@ -16,8 +16,12 @@
 
 package com.android.systemui.qs.logging
 
+import android.content.res.Configuration.ORIENTATION_LANDSCAPE
+import android.content.res.Configuration.ORIENTATION_PORTRAIT
+import android.content.res.Configuration.Orientation
 import android.service.quicksettings.Tile
 import android.view.View
+import com.android.systemui.log.dagger.QSConfigLog
 import com.android.systemui.log.dagger.QSLog
 import com.android.systemui.plugins.log.ConstantStringsLogger
 import com.android.systemui.plugins.log.ConstantStringsLoggerImpl
@@ -32,8 +36,12 @@
 
 private const val TAG = "QSLog"
 
-class QSLogger @Inject constructor(@QSLog private val buffer: LogBuffer) :
-    ConstantStringsLogger by ConstantStringsLoggerImpl(buffer, TAG) {
+class QSLogger
+@Inject
+constructor(
+    @QSLog private val buffer: LogBuffer,
+    @QSConfigLog private val configChangedBuffer: LogBuffer,
+) : ConstantStringsLogger by ConstantStringsLoggerImpl(buffer, TAG) {
 
     fun logException(@CompileTimeConstant logMsg: String, ex: Exception) {
         buffer.log(TAG, ERROR, {}, { logMsg }, exception = ex)
@@ -264,19 +272,28 @@
     }
 
     fun logOnConfigurationChanged(
-        lastOrientation: Int,
-        newOrientation: Int,
+        @Orientation oldOrientation: Int,
+        @Orientation newOrientation: Int,
+        newShouldUseSplitShade: Boolean,
+        oldShouldUseSplitShade: Boolean,
         containerName: String
     ) {
-        buffer.log(
+        configChangedBuffer.log(
             TAG,
             DEBUG,
             {
                 str1 = containerName
-                int1 = lastOrientation
+                int1 = oldOrientation
                 int2 = newOrientation
+                bool1 = oldShouldUseSplitShade
+                bool2 = newShouldUseSplitShade
             },
-            { "configuration change: $str1 orientation was $int1, now $int2" }
+            {
+                "config change: " +
+                    "$str1 orientation=${toOrientationString(int2)} " +
+                    "(was ${toOrientationString(int1)}), " +
+                    "splitShade=$bool2 (was $bool1)"
+            }
         )
     }
 
@@ -353,3 +370,11 @@
         }
     }
 }
+
+private inline fun toOrientationString(@Orientation orientation: Int): String {
+    return when (orientation) {
+        ORIENTATION_LANDSCAPE -> "land"
+        ORIENTATION_PORTRAIT -> "port"
+        else -> "undefined"
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
index 12e9aeb..75d0172 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
@@ -35,6 +35,7 @@
 
 import androidx.annotation.Nullable;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settingslib.graph.SignalDrawable;
@@ -71,12 +72,16 @@
     public static final String TILE_SPEC = "internet";
 
     private static final Intent WIFI_SETTINGS = new Intent(Settings.ACTION_WIFI_SETTINGS);
+    private static final int LAST_STATE_UNKNOWN = -1;
+    private static final int LAST_STATE_CELLULAR = 0;
+    private static final int LAST_STATE_WIFI = 1;
+    private static final int LAST_STATE_ETHERNET = 2;
 
     protected final NetworkController mController;
     private final AccessPointController mAccessPointController;
     private final DataUsageController mDataController;
     // The last updated tile state, 0: mobile, 1: wifi, 2: ethernet.
-    private int mLastTileState = -1;
+    private int mLastTileState = LAST_STATE_UNKNOWN;
 
     protected final InternetSignalCallback mSignalCallback = new InternetSignalCallback();
     private final InternetDialogFactory mInternetDialogFactory;
@@ -170,6 +175,15 @@
         @Nullable
         String mEthernetContentDescription;
 
+        public void copyTo(EthernetCallbackInfo ethernetCallbackInfo) {
+            if (ethernetCallbackInfo == null) {
+                throw new IllegalArgumentException();
+            }
+            ethernetCallbackInfo.mConnected = this.mConnected;
+            ethernetCallbackInfo.mEthernetSignalIconId = this.mEthernetSignalIconId;
+            ethernetCallbackInfo.mEthernetContentDescription = this.mEthernetContentDescription;
+        }
+
         @Override
         public String toString() {
             return new StringBuilder("EthernetCallbackInfo[")
@@ -196,6 +210,23 @@
         boolean mNoValidatedNetwork;
         boolean mNoNetworksAvailable;
 
+        public void copyTo(WifiCallbackInfo wifiCallbackInfo) {
+            if (wifiCallbackInfo == null) {
+                throw new IllegalArgumentException();
+            }
+            wifiCallbackInfo.mAirplaneModeEnabled = this.mAirplaneModeEnabled;
+            wifiCallbackInfo.mEnabled = this.mEnabled;
+            wifiCallbackInfo.mConnected = this.mConnected;
+            wifiCallbackInfo.mWifiSignalIconId = this.mWifiSignalIconId;
+            wifiCallbackInfo.mSsid = this.mSsid;
+            wifiCallbackInfo.mWifiSignalContentDescription = this.mWifiSignalContentDescription;
+            wifiCallbackInfo.mIsTransient = this.mIsTransient;
+            wifiCallbackInfo.mStatusLabel = this.mStatusLabel;
+            wifiCallbackInfo.mNoDefaultNetwork = this.mNoDefaultNetwork;
+            wifiCallbackInfo.mNoValidatedNetwork = this.mNoValidatedNetwork;
+            wifiCallbackInfo.mNoNetworksAvailable = this.mNoNetworksAvailable;
+        }
+
         @Override
         public String toString() {
             return new StringBuilder("WifiCallbackInfo[")
@@ -228,6 +259,23 @@
         boolean mNoValidatedNetwork;
         boolean mNoNetworksAvailable;
 
+        public void copyTo(CellularCallbackInfo cellularCallbackInfo) {
+            if (cellularCallbackInfo == null) {
+                throw new IllegalArgumentException();
+            }
+            cellularCallbackInfo.mAirplaneModeEnabled = this.mAirplaneModeEnabled;
+            cellularCallbackInfo.mDataSubscriptionName = this.mDataSubscriptionName;
+            cellularCallbackInfo.mDataContentDescription = this.mDataContentDescription;
+            cellularCallbackInfo.mMobileSignalIconId = this.mMobileSignalIconId;
+            cellularCallbackInfo.mQsTypeIcon = this.mQsTypeIcon;
+            cellularCallbackInfo.mNoSim = this.mNoSim;
+            cellularCallbackInfo.mRoaming = this.mRoaming;
+            cellularCallbackInfo.mMultipleSubs = this.mMultipleSubs;
+            cellularCallbackInfo.mNoDefaultNetwork = this.mNoDefaultNetwork;
+            cellularCallbackInfo.mNoValidatedNetwork = this.mNoValidatedNetwork;
+            cellularCallbackInfo.mNoNetworksAvailable = this.mNoNetworksAvailable;
+        }
+
         @Override
         public String toString() {
             return new StringBuilder("CellularCallbackInfo[")
@@ -247,8 +295,11 @@
     }
 
     protected final class InternetSignalCallback implements SignalCallback {
+        @GuardedBy("mWifiInfo")
         final WifiCallbackInfo mWifiInfo = new WifiCallbackInfo();
+        @GuardedBy("mCellularInfo")
         final CellularCallbackInfo mCellularInfo = new CellularCallbackInfo();
+        @GuardedBy("mEthernetInfo")
         final EthernetCallbackInfo mEthernetInfo = new EthernetCallbackInfo();
 
 
@@ -257,19 +308,23 @@
             if (DEBUG) {
                 Log.d(TAG, "setWifiIndicators: " + indicators);
             }
-            mWifiInfo.mEnabled = indicators.enabled;
-            mWifiInfo.mSsid = indicators.description;
-            mWifiInfo.mIsTransient = indicators.isTransient;
-            mWifiInfo.mStatusLabel = indicators.statusLabel;
+            synchronized (mWifiInfo) {
+                mWifiInfo.mEnabled = indicators.enabled;
+                mWifiInfo.mSsid = indicators.description;
+                mWifiInfo.mIsTransient = indicators.isTransient;
+                mWifiInfo.mStatusLabel = indicators.statusLabel;
+                if (indicators.qsIcon != null) {
+                    mWifiInfo.mConnected = indicators.qsIcon.visible;
+                    mWifiInfo.mWifiSignalIconId = indicators.qsIcon.icon;
+                    mWifiInfo.mWifiSignalContentDescription = indicators.qsIcon.contentDescription;
+                } else {
+                    mWifiInfo.mConnected = false;
+                    mWifiInfo.mWifiSignalIconId = 0;
+                    mWifiInfo.mWifiSignalContentDescription = null;
+                }
+            }
             if (indicators.qsIcon != null) {
-                mWifiInfo.mConnected = indicators.qsIcon.visible;
-                mWifiInfo.mWifiSignalIconId = indicators.qsIcon.icon;
-                mWifiInfo.mWifiSignalContentDescription = indicators.qsIcon.contentDescription;
                 refreshState(mWifiInfo);
-            } else {
-                mWifiInfo.mConnected = false;
-                mWifiInfo.mWifiSignalIconId = 0;
-                mWifiInfo.mWifiSignalContentDescription = null;
             }
         }
 
@@ -282,14 +337,16 @@
                 // Not data sim, don't display.
                 return;
             }
-            mCellularInfo.mDataSubscriptionName = indicators.qsDescription == null
+            synchronized (mCellularInfo) {
+                mCellularInfo.mDataSubscriptionName = indicators.qsDescription == null
                     ? mController.getMobileDataNetworkName() : indicators.qsDescription;
-            mCellularInfo.mDataContentDescription = indicators.qsDescription != null
+                mCellularInfo.mDataContentDescription = indicators.qsDescription != null
                     ? indicators.typeContentDescriptionHtml : null;
-            mCellularInfo.mMobileSignalIconId = indicators.qsIcon.icon;
-            mCellularInfo.mQsTypeIcon = indicators.qsType;
-            mCellularInfo.mRoaming = indicators.roaming;
-            mCellularInfo.mMultipleSubs = mController.getNumberSubscriptions() > 1;
+                mCellularInfo.mMobileSignalIconId = indicators.qsIcon.icon;
+                mCellularInfo.mQsTypeIcon = indicators.qsType;
+                mCellularInfo.mRoaming = indicators.roaming;
+                mCellularInfo.mMultipleSubs = mController.getNumberSubscriptions() > 1;
+            }
             refreshState(mCellularInfo);
         }
 
@@ -299,9 +356,11 @@
                 Log.d(TAG, "setEthernetIndicators: "
                         + "icon = " + (icon == null ? "" :  icon.toString()));
             }
-            mEthernetInfo.mConnected = icon.visible;
-            mEthernetInfo.mEthernetSignalIconId = icon.icon;
-            mEthernetInfo.mEthernetContentDescription = icon.contentDescription;
+            synchronized (mEthernetInfo) {
+                mEthernetInfo.mConnected = icon.visible;
+                mEthernetInfo.mEthernetSignalIconId = icon.icon;
+                mEthernetInfo.mEthernetContentDescription = icon.contentDescription;
+            }
             if (icon.visible) {
                 refreshState(mEthernetInfo);
             }
@@ -314,11 +373,13 @@
                         + "show = " + show + ","
                         + "simDetected = " + simDetected);
             }
-            mCellularInfo.mNoSim = show;
-            if (mCellularInfo.mNoSim) {
-                // Make sure signal gets cleared out when no sims.
-                mCellularInfo.mMobileSignalIconId = 0;
-                mCellularInfo.mQsTypeIcon = 0;
+            synchronized (mCellularInfo) {
+                mCellularInfo.mNoSim = show;
+                if (mCellularInfo.mNoSim) {
+                    // Make sure signal gets cleared out when no sims.
+                    mCellularInfo.mMobileSignalIconId = 0;
+                    mCellularInfo.mQsTypeIcon = 0;
+                }
             }
         }
 
@@ -331,8 +392,12 @@
             if (mCellularInfo.mAirplaneModeEnabled == icon.visible) {
                 return;
             }
-            mCellularInfo.mAirplaneModeEnabled = icon.visible;
-            mWifiInfo.mAirplaneModeEnabled = icon.visible;
+            synchronized (mCellularInfo) {
+                mCellularInfo.mAirplaneModeEnabled = icon.visible;
+            }
+            synchronized (mWifiInfo) {
+                mWifiInfo.mAirplaneModeEnabled = icon.visible;
+            }
             if (!mSignalCallback.mEthernetInfo.mConnected) {
                 // Always use mWifiInfo to refresh the Internet Tile if airplane mode is enabled,
                 // because Internet Tile will show different information depending on whether WiFi
@@ -359,12 +424,16 @@
                         + "noValidatedNetwork = " + noValidatedNetwork + ","
                         + "noNetworksAvailable = " + noNetworksAvailable);
             }
-            mCellularInfo.mNoDefaultNetwork = noDefaultNetwork;
-            mCellularInfo.mNoValidatedNetwork = noValidatedNetwork;
-            mCellularInfo.mNoNetworksAvailable = noNetworksAvailable;
-            mWifiInfo.mNoDefaultNetwork = noDefaultNetwork;
-            mWifiInfo.mNoValidatedNetwork = noValidatedNetwork;
-            mWifiInfo.mNoNetworksAvailable = noNetworksAvailable;
+            synchronized (mCellularInfo) {
+                mCellularInfo.mNoDefaultNetwork = noDefaultNetwork;
+                mCellularInfo.mNoValidatedNetwork = noValidatedNetwork;
+                mCellularInfo.mNoNetworksAvailable = noNetworksAvailable;
+            }
+            synchronized (mWifiInfo) {
+                mWifiInfo.mNoDefaultNetwork = noDefaultNetwork;
+                mWifiInfo.mNoValidatedNetwork = noValidatedNetwork;
+                mWifiInfo.mNoNetworksAvailable = noNetworksAvailable;
+            }
             if (!noDefaultNetwork) {
                 return;
             }
@@ -386,24 +455,36 @@
         mQSLogger.logInternetTileUpdate(
                 getTileSpec(), mLastTileState, arg == null ? "null" : arg.toString());
         if (arg instanceof CellularCallbackInfo) {
-            mLastTileState = 0;
+            mLastTileState = LAST_STATE_CELLULAR;
             handleUpdateCellularState(state, arg);
         } else if (arg instanceof WifiCallbackInfo) {
-            mLastTileState = 1;
+            mLastTileState = LAST_STATE_WIFI;
             handleUpdateWifiState(state, arg);
         } else if (arg instanceof EthernetCallbackInfo) {
-            mLastTileState = 2;
+            mLastTileState = LAST_STATE_ETHERNET;
             handleUpdateEthernetState(state, arg);
         } else {
             // handleUpdateState will be triggered when user expands the QuickSetting panel with
             // arg = null, in this case the last updated CellularCallbackInfo or WifiCallbackInfo
             // should be used to refresh the tile.
-            if (mLastTileState == 0) {
-                handleUpdateCellularState(state, mSignalCallback.mCellularInfo);
-            } else if (mLastTileState == 1) {
-                handleUpdateWifiState(state, mSignalCallback.mWifiInfo);
-            } else if (mLastTileState == 2) {
-                handleUpdateEthernetState(state, mSignalCallback.mEthernetInfo);
+            if (mLastTileState == LAST_STATE_CELLULAR) {
+                CellularCallbackInfo cellularInfo = new CellularCallbackInfo();
+                synchronized (mSignalCallback.mCellularInfo) {
+                    mSignalCallback.mCellularInfo.copyTo(cellularInfo);
+                }
+                handleUpdateCellularState(state, cellularInfo);
+            } else if (mLastTileState == LAST_STATE_WIFI) {
+                WifiCallbackInfo mifiInfo = new WifiCallbackInfo();
+                synchronized (mSignalCallback.mWifiInfo) {
+                    mSignalCallback.mWifiInfo.copyTo(mifiInfo);
+                }
+                handleUpdateWifiState(state, mifiInfo);
+            } else if (mLastTileState == LAST_STATE_ETHERNET) {
+                EthernetCallbackInfo ethernetInfo = new EthernetCallbackInfo();
+                synchronized (mSignalCallback.mEthernetInfo) {
+                    mSignalCallback.mEthernetInfo.copyTo(ethernetInfo);
+                }
+                handleUpdateEthernetState(state, ethernetInfo);
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 25ff308b..c28a40a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -21,7 +21,6 @@
 import static android.view.MotionEvent.ACTION_DOWN;
 import static android.view.MotionEvent.ACTION_UP;
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
-
 import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME;
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SUPPORTS_WINDOW_CORNERS;
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
@@ -31,6 +30,8 @@
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DOZING;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DREAMING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_ON;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_TRANSITION;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED;
@@ -121,7 +122,8 @@
 public class OverviewProxyService implements CallbackController<OverviewProxyListener>,
         NavigationModeController.ModeChangedListener, Dumpable {
 
-    private static final String ACTION_QUICKSTEP = "android.intent.action.QUICKSTEP_SERVICE";
+    @VisibleForTesting
+    static final String ACTION_QUICKSTEP = "android.intent.action.QUICKSTEP_SERVICE";
 
     public static final String TAG_OPS = "OverviewProxyService";
     private static final long BACKOFF_MILLIS = 1000;
@@ -138,7 +140,8 @@
     private final Handler mHandler;
     private final Lazy<NavigationBarController> mNavBarControllerLazy;
     private final NotificationShadeWindowController mStatusBarWinController;
-    private final Runnable mConnectionRunnable = this::internalConnectToCurrentUser;
+    private final Runnable mConnectionRunnable = () ->
+            internalConnectToCurrentUser("runnable: startConnectionToCurrentUser");
     private final ComponentName mRecentsComponentName;
     private final List<OverviewProxyListener> mConnectionCallbacks = new ArrayList<>();
     private final Intent mQuickStepIntent;
@@ -404,7 +407,7 @@
                 // Failed to link to death (process may have died between binding and connecting),
                 // just unbind the service for now and retry again
                 Log.e(TAG_OPS, "Lost connection to launcher service", e);
-                disconnectFromLauncherService();
+                disconnectFromLauncherService("Lost connection to launcher service");
                 retryConnectionWithBackoff();
                 return;
             }
@@ -499,7 +502,7 @@
                 @Override
                 public void onUserChanged(int newUser, @NonNull Context userContext) {
                     mConnectionBackoffAttempts = 0;
-                    internalConnectToCurrentUser();
+                    internalConnectToCurrentUser("User changed");
                 }
             };
 
@@ -548,6 +551,7 @@
         mUiEventLogger = uiEventLogger;
         mDisplayTracker = displayTracker;
         mUnfoldTransitionProgressForwarder = unfoldTransitionProgressForwarder;
+        mSysuiUnlockAnimationController = sysuiUnlockAnimationController;
 
         dumpManager.registerDumpable(getClass().getSimpleName(), this);
 
@@ -596,7 +600,6 @@
         // Connect to the service
         updateEnabledState();
         startConnectionToCurrentUser();
-        mSysuiUnlockAnimationController = sysuiUnlockAnimationController;
 
         // Listen for assistant changes
         assistUtils.registerVoiceInteractionSessionListener(mVoiceInteractionSessionListener);
@@ -631,7 +634,9 @@
         final NavigationBarView navBarView =
                 mNavBarControllerLazy.get().getNavigationBarView(mContext.getDisplayId());
         final NotificationPanelViewController panelController =
-                mCentralSurfacesOptionalLazy.get().get().getNotificationPanelViewController();
+                mCentralSurfacesOptionalLazy.get()
+                        .map(CentralSurfaces::getNotificationPanelViewController)
+                        .orElse(null);
         if (SysUiState.DEBUG) {
             Log.d(TAG_OPS, "Updating sysui state flags: navBarFragment=" + navBarFragment
                     + " navBarView=" + navBarView + " panelController=" + panelController);
@@ -708,15 +713,16 @@
     }
 
     public void startConnectionToCurrentUser() {
+        Log.v(TAG_OPS, "startConnectionToCurrentUser: connection is restarted");
         if (mHandler.getLooper() != Looper.myLooper()) {
             mHandler.post(mConnectionRunnable);
         } else {
-            internalConnectToCurrentUser();
+            internalConnectToCurrentUser("startConnectionToCurrentUser");
         }
     }
 
-    private void internalConnectToCurrentUser() {
-        disconnectFromLauncherService();
+    private void internalConnectToCurrentUser(String reason) {
+        disconnectFromLauncherService(reason);
 
         // If user has not setup yet or already connected, do not try to connect
         if (!isEnabled()) {
@@ -724,10 +730,8 @@
             return;
         }
         mHandler.removeCallbacks(mConnectionRunnable);
-        Intent launcherServiceIntent = new Intent(ACTION_QUICKSTEP)
-                .setPackage(mRecentsComponentName.getPackageName());
         try {
-            mBound = mContext.bindServiceAsUser(launcherServiceIntent,
+            mBound = mContext.bindServiceAsUser(mQuickStepIntent,
                     mOverviewServiceConnection,
                     Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
                     UserHandle.of(mUserTracker.getUserId()));
@@ -780,7 +784,9 @@
         return mOverviewProxy;
     }
 
-    private void disconnectFromLauncherService() {
+    private void disconnectFromLauncherService(String disconnectReason) {
+        Log.d(TAG_OPS, "disconnectFromLauncherService bound?: " + mBound +
+                " currentProxy: " + mOverviewProxy + " disconnectReason: " + disconnectReason);
         if (mBound) {
             // Always unbind the service (ie. if called through onNullBinding or onBindingDied)
             mContext.unbindService(mOverviewServiceConnection);
@@ -860,6 +866,11 @@
          */
         @Override
         public void onScreenTurnedOn() {
+            mSysUiState
+                .setFlag(SYSUI_STATE_SCREEN_ON, true)
+                .setFlag(SYSUI_STATE_SCREEN_TRANSITION, false)
+                .commitUpdate(mContext.getDisplayId());
+
             try {
                 if (mOverviewProxy != null) {
                     mOverviewProxy.onScreenTurnedOn();
@@ -872,10 +883,26 @@
         }
 
         /**
+         * Notifies the Launcher that screen turned off.
+         */
+        @Override
+        public void onScreenTurnedOff() {
+            mSysUiState
+                .setFlag(SYSUI_STATE_SCREEN_ON, false)
+                .setFlag(SYSUI_STATE_SCREEN_TRANSITION, false)
+                .commitUpdate(mContext.getDisplayId());
+        }
+
+        /**
          * Notifies the Launcher that screen is starting to turn on.
          */
         @Override
         public void onScreenTurningOff() {
+            mSysUiState
+                .setFlag(SYSUI_STATE_SCREEN_ON, false)
+                .setFlag(SYSUI_STATE_SCREEN_TRANSITION, true)
+                .commitUpdate(mContext.getDisplayId());
+
             try {
                 if (mOverviewProxy != null) {
                     mOverviewProxy.onScreenTurningOff();
@@ -892,6 +919,11 @@
          */
         @Override
         public void onScreenTurningOn() {
+            mSysUiState
+                .setFlag(SYSUI_STATE_SCREEN_ON, true)
+                .setFlag(SYSUI_STATE_SCREEN_TRANSITION, true)
+                .commitUpdate(mContext.getDisplayId());
+
             try {
                 if (mOverviewProxy != null) {
                     mOverviewProxy.onScreenTurningOn();
@@ -1003,4 +1035,21 @@
         default void onAssistantGestureCompletion(float velocity) {}
         default void startAssistant(Bundle bundle) {}
     }
+
+    /**
+     * Shuts down this service at the end of a testcase.
+     * <p>
+     * The in-production service is never shuts down, and it was not designed with testing in mind.
+     * This unregisters the mechanisms by which the service will be revived after a testcase.
+     * <p>
+     * NOTE: This is a stop-gap introduced when first added some tests to this class. It should
+     * probably be replaced by proper lifecycle management on this class.
+     */
+    @VisibleForTesting()
+    void shutdownForTest() {
+        mContext.unregisterReceiver(mLauncherStateChangedReceiver);
+        mIsEnabled = false;
+        mHandler.removeCallbacks(mConnectionRunnable);
+        disconnectFromLauncherService("Shutdown for test");
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/DraggableConstraintLayout.java b/packages/SystemUI/src/com/android/systemui/screenshot/DraggableConstraintLayout.java
index ead3b7b..0b4b7c6 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/DraggableConstraintLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/DraggableConstraintLayout.java
@@ -45,6 +45,7 @@
         implements ViewTreeObserver.OnComputeInternalInsetsListener {
 
     private static final float VELOCITY_DP_PER_MS = 1;
+    private static final int MAXIMUM_DISMISS_DISTANCE_DP = 400;
 
     private final SwipeDismissHandler mSwipeDismissHandler;
     private final GestureDetector mSwipeDetector;
@@ -347,14 +348,18 @@
             } else {
                 finalX = -1 * getBackgroundRight();
             }
-            float distance = Math.abs(finalX - startX);
+            float distance = Math.min(Math.abs(finalX - startX),
+                    FloatingWindowUtil.dpToPx(mDisplayMetrics, MAXIMUM_DISMISS_DISTANCE_DP));
+            // ensure that view dismisses in the right direction (right in LTR, left in RTL)
+            float distanceVector = Math.copySign(distance, finalX - startX);
 
             anim.addUpdateListener(animation -> {
-                float translation = MathUtils.lerp(startX, finalX, animation.getAnimatedFraction());
+                float translation = MathUtils.lerp(
+                        startX, startX + distanceVector, animation.getAnimatedFraction());
                 mView.setTranslationX(translation);
                 mView.setAlpha(1 - animation.getAnimatedFraction());
             });
-            anim.setDuration((long) (distance / Math.abs(velocity)));
+            anim.setDuration((long) (Math.abs(distance / velocity)));
             return anim;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java b/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java
index c8c1337..7cfe232 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java
@@ -57,7 +57,8 @@
 
 import javax.inject.Inject;
 
-class ImageExporter {
+/** A class to help with exporting screenshot to storage. */
+public class ImageExporter {
     private static final String TAG = LogConfig.logTag(ImageExporter.class);
 
     static final Duration PENDING_ENTRY_TTL = Duration.ofHours(24);
@@ -90,7 +91,7 @@
     private final FeatureFlags mFlags;
 
     @Inject
-    ImageExporter(ContentResolver resolver, FeatureFlags flags) {
+    public ImageExporter(ContentResolver resolver, FeatureFlags flags) {
         mResolver = resolver;
         mFlags = flags;
     }
@@ -148,7 +149,7 @@
      *
      * @return a listenable future result
      */
-    ListenableFuture<Result> export(Executor executor, UUID requestId, Bitmap bitmap,
+    public ListenableFuture<Result> export(Executor executor, UUID requestId, Bitmap bitmap,
             UserHandle owner) {
         return export(executor, requestId, bitmap, ZonedDateTime.now(), owner);
     }
@@ -181,13 +182,14 @@
         );
     }
 
-    static class Result {
-        Uri uri;
-        UUID requestId;
-        String fileName;
-        long timestamp;
-        CompressFormat format;
-        boolean published;
+    /** The result returned by the task exporting screenshots to storage. */
+    public static class Result {
+        public Uri uri;
+        public UUID requestId;
+        public String fileName;
+        public long timestamp;
+        public CompressFormat format;
+        public boolean published;
 
         @Override
         public String toString() {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
index ca8e101..02a60ad 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
@@ -481,7 +481,6 @@
             mCropView.setExtraPadding(extraPadding + mPreview.getPaddingTop(),
                     extraPadding + mPreview.getPaddingBottom());
             imageTop += (previewHeight - imageHeight) / 2;
-            mCropView.setExtraPadding(extraPadding, extraPadding);
             mCropView.setImageWidth(previewWidth);
             scale = previewWidth / (float) mPreview.getDrawable().getIntrinsicWidth();
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 8721d71..557e95c 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -419,6 +419,10 @@
             return;
         }
 
+        mScreenBitmap = screenshot.getBitmap();
+        String oldPackageName = mPackageName;
+        mPackageName = screenshot.getPackageNameString();
+
         if (!isUserSetupComplete(Process.myUserHandle())) {
             Log.w(TAG, "User setup not complete, displaying toast only");
             // User setup isn't complete, so we don't want to show any UI beyond a toast, as editing
@@ -433,10 +437,6 @@
         mScreenshotTakenInPortrait =
                 mContext.getResources().getConfiguration().orientation == ORIENTATION_PORTRAIT;
 
-        String oldPackageName = mPackageName;
-        mPackageName = screenshot.getPackageNameString();
-
-        mScreenBitmap = screenshot.getBitmap();
         // Optimizations
         mScreenBitmap.setHasAlpha(false);
         mScreenBitmap.prepareToDraw();
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java
index fc94aed..7a62bae 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java
@@ -93,13 +93,7 @@
     @UiEvent(doc = "User has discarded the result of a long screenshot")
     SCREENSHOT_LONG_SCREENSHOT_EXIT(911),
     @UiEvent(doc = "A screenshot has been taken and saved to work profile")
-    SCREENSHOT_SAVED_TO_WORK_PROFILE(1240),
-    @UiEvent(doc = "Notes application triggered the screenshot for notes")
-    SCREENSHOT_FOR_NOTE_TRIGGERED(1308),
-    @UiEvent(doc = "User accepted the screenshot to be sent to the notes app")
-    SCREENSHOT_FOR_NOTE_ACCEPTED(1309),
-    @UiEvent(doc = "User cancelled the screenshot for notes app flow")
-    SCREENSHOT_FOR_NOTE_CANCELLED(1310);
+    SCREENSHOT_SAVED_TO_WORK_PROFILE(1240);
 
     private final int mId;
 
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index e53eea9..3541aaf 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -23,6 +23,7 @@
 import static androidx.constraintlayout.widget.ConstraintSet.END;
 import static androidx.constraintlayout.widget.ConstraintSet.PARENT_ID;
 
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION;
 import static com.android.keyguard.KeyguardClockSwitch.LARGE;
 import static com.android.keyguard.KeyguardClockSwitch.SMALL;
 import static com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE;
@@ -71,6 +72,7 @@
 import android.provider.Settings;
 import android.transition.ChangeBounds;
 import android.transition.Transition;
+import android.transition.TransitionListenerAdapter;
 import android.transition.TransitionManager;
 import android.transition.TransitionSet;
 import android.transition.TransitionValues;
@@ -98,6 +100,7 @@
 import androidx.constraintlayout.widget.ConstraintSet;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.policy.SystemBarUtils;
@@ -116,6 +119,7 @@
 import com.android.keyguard.dagger.KeyguardUserSwitcherComponent;
 import com.android.systemui.DejankUtils;
 import com.android.systemui.Dumpable;
+import com.android.systemui.Gefingerpoken;
 import com.android.systemui.R;
 import com.android.systemui.animation.ActivityLaunchAnimator;
 import com.android.systemui.animation.Interpolators;
@@ -154,19 +158,18 @@
 import com.android.systemui.navigationbar.NavigationBarController;
 import com.android.systemui.navigationbar.NavigationBarView;
 import com.android.systemui.navigationbar.NavigationModeController;
+import com.android.systemui.plugins.ClockAnimations;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.FalsingManager.FalsingTapListener;
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
-import com.android.systemui.screenrecord.RecordingController;
 import com.android.systemui.shade.transition.ShadeTransitionController;
 import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.GestureRecorder;
 import com.android.systemui.statusbar.KeyguardIndicationController;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
-import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationShadeDepthController;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.NotificationShelfController;
@@ -353,6 +356,8 @@
     private final NotificationGutsManager mGutsManager;
     private final AlternateBouncerInteractor mAlternateBouncerInteractor;
     private final QuickSettingsController mQsController;
+    private final InteractionJankMonitor mInteractionJankMonitor;
+    private final TouchHandler mTouchHandler = new TouchHandler();
 
     private long mDownTime;
     private boolean mTouchSlopExceededBeforeDown;
@@ -537,7 +542,7 @@
     private final KeyguardBottomAreaViewModel mKeyguardBottomAreaViewModel;
     private final KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor;
     private float mMinExpandHeight;
-    private ShadeHeightLogger mShadeHeightLogger;
+    private final ShadeHeightLogger mShadeHeightLogger;
     private boolean mPanelUpdateWhenAnimatorEnds;
     private boolean mHasVibratedOnOpen = false;
     private int mFixedDuration = NO_FIXED_DURATION;
@@ -582,15 +587,15 @@
     private boolean mGestureWaitForTouchSlop;
     private boolean mIgnoreXTouchSlop;
     private boolean mExpandLatencyTracking;
-    private DreamingToLockscreenTransitionViewModel mDreamingToLockscreenTransitionViewModel;
-    private OccludedToLockscreenTransitionViewModel mOccludedToLockscreenTransitionViewModel;
-    private LockscreenToDreamingTransitionViewModel mLockscreenToDreamingTransitionViewModel;
-    private GoneToDreamingTransitionViewModel mGoneToDreamingTransitionViewModel;
-    private LockscreenToOccludedTransitionViewModel mLockscreenToOccludedTransitionViewModel;
+    private final DreamingToLockscreenTransitionViewModel mDreamingToLockscreenTransitionViewModel;
+    private final OccludedToLockscreenTransitionViewModel mOccludedToLockscreenTransitionViewModel;
+    private final LockscreenToDreamingTransitionViewModel mLockscreenToDreamingTransitionViewModel;
+    private final GoneToDreamingTransitionViewModel mGoneToDreamingTransitionViewModel;
+    private final LockscreenToOccludedTransitionViewModel mLockscreenToOccludedTransitionViewModel;
 
-    private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
+    private final KeyguardTransitionInteractor mKeyguardTransitionInteractor;
     private final KeyguardInteractor mKeyguardInteractor;
-    private CoroutineDispatcher mMainDispatcher;
+    private final CoroutineDispatcher mMainDispatcher;
     private boolean mIsOcclusionTransitionRunning = false;
     private int mDreamingToLockscreenTransitionTranslationY;
     private int mOccludedToLockscreenTransitionTranslationY;
@@ -642,6 +647,19 @@
                     step.getTransitionState() == TransitionState.RUNNING;
             };
 
+    private final TransitionListenerAdapter mKeyguardStatusAlignmentTransitionListener =
+            new TransitionListenerAdapter() {
+                @Override
+                public void onTransitionCancel(Transition transition) {
+                    mInteractionJankMonitor.cancel(CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION);
+                }
+
+                @Override
+                public void onTransitionEnd(Transition transition) {
+                    mInteractionJankMonitor.end(CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION);
+                }
+            };
+
     @Inject
     public NotificationPanelViewController(NotificationPanelView view,
             @Main Handler handler,
@@ -691,12 +709,10 @@
             QuickSettingsController quickSettingsController,
             FragmentService fragmentService,
             ContentResolver contentResolver,
-            RecordingController recordingController,
             ShadeHeaderController shadeHeaderController,
             ScreenOffAnimationController screenOffAnimationController,
             LockscreenGestureLogger lockscreenGestureLogger,
             ShadeExpansionStateManager shadeExpansionStateManager,
-            NotificationRemoteInputManager remoteInputManager,
             Optional<SysUIUnfoldComponent> unfoldComponent,
             SysUiState sysUiState,
             Provider<KeyguardBottomAreaViewController> keyguardBottomAreaViewControllerProvider,
@@ -706,6 +722,7 @@
             NotificationStackSizeCalculator notificationStackSizeCalculator,
             UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
             ShadeTransitionController shadeTransitionController,
+            InteractionJankMonitor interactionJankMonitor,
             SystemClock systemClock,
             KeyguardBottomAreaViewModel keyguardBottomAreaViewModel,
             KeyguardBottomAreaInteractor keyguardBottomAreaInteractor,
@@ -720,6 +737,7 @@
             DumpManager dumpManager,
             KeyguardLongPressViewModel keyguardLongPressViewModel,
             KeyguardInteractor keyguardInteractor) {
+        mInteractionJankMonitor = interactionJankMonitor;
         keyguardStateController.addCallback(new KeyguardStateController.Callback() {
             @Override
             public void onKeyguardFadingAwayChanged() {
@@ -752,7 +770,7 @@
         });
 
         mView.addOnLayoutChangeListener(new ShadeLayoutChangeListener());
-        mView.setOnTouchListener(createTouchHandler());
+        mView.setOnTouchListener(getTouchHandler());
         mView.setOnConfigurationChangedListener(config -> loadDimens());
 
         mResources = mView.getResources();
@@ -943,6 +961,7 @@
                 onTrackingStopped(false);
                 instantCollapse();
             } else {
+                mView.animate().cancel();
                 mView.animate()
                         .alpha(0f)
                         .setStartDelay(0)
@@ -1184,6 +1203,12 @@
 
     private void onSplitShadeEnabledChanged() {
         mShadeLog.logSplitShadeChanged(mSplitShadeEnabled);
+        // Reset any left over overscroll state. It is a rare corner case but can happen.
+        mQsController.setOverScrollAmount(0);
+        mScrimController.setNotificationsOverScrollAmount(0);
+        mNotificationStackScrollLayoutController.setOverExpansion(0);
+        mNotificationStackScrollLayoutController.setOverScrollAmount(0);
+
         // when we switch between split shade and regular shade we want to enforce setting qs to
         // the default state: expanded for split shade and collapsed otherwise
         if (!isOnKeyguard() && mPanelExpanded) {
@@ -1540,6 +1565,7 @@
             int statusConstraint = shouldBeCentered ? PARENT_ID : R.id.qs_edge_guideline;
             constraintSet.connect(R.id.keyguard_status_view, END, statusConstraint, END);
             if (animate) {
+                mInteractionJankMonitor.begin(mView, CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION);
                 ChangeBounds transition = new ChangeBounds();
                 if (mSplitShadeEnabled) {
                     // Excluding media from the transition on split-shade, as it doesn't transition
@@ -1550,10 +1576,9 @@
                 transition.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
                 transition.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
 
-                boolean customClockAnimation =
-                            mKeyguardStatusViewController.getClockAnimations() != null
-                            && mKeyguardStatusViewController.getClockAnimations()
-                                    .getHasCustomPositionUpdatedAnimation();
+                ClockAnimations clockAnims = mKeyguardStatusViewController.getClockAnimations();
+                boolean customClockAnimation = clockAnims != null
+                        && clockAnims.getHasCustomPositionUpdatedAnimation();
 
                 if (mFeatureFlags.isEnabled(Flags.STEP_CLOCK_ANIMATION) && customClockAnimation) {
                     // Find the clock, so we can exclude it from this transition.
@@ -1563,6 +1588,7 @@
                     // The clock container can sometimes be null. If it is, just fall back to the
                     // old animation rather than setting up the custom animations.
                     if (clockContainerView == null || clockContainerView.getChildCount() == 0) {
+                        transition.addListener(mKeyguardStatusAlignmentTransitionListener);
                         TransitionManager.beginDelayedTransition(
                                 mNotificationContainerParent, transition);
                     } else {
@@ -1581,10 +1607,11 @@
                         adapter.setDuration(KEYGUARD_STATUS_VIEW_CUSTOM_CLOCK_MOVE_DURATION);
                         adapter.addTarget(clockView);
                         set.addTransition(adapter);
-
+                        set.addListener(mKeyguardStatusAlignmentTransitionListener);
                         TransitionManager.beginDelayedTransition(mNotificationContainerParent, set);
                     }
                 } else {
+                    transition.addListener(mKeyguardStatusAlignmentTransitionListener);
                     TransitionManager.beginDelayedTransition(
                             mNotificationContainerParent, transition);
                 }
@@ -1621,10 +1648,6 @@
         return mDozing && mDozeParameters.getAlwaysOn();
     }
 
-    boolean isDozing() {
-        return mDozing;
-    }
-
     private boolean hasVisibleNotifications() {
         return mNotificationStackScrollLayoutController
                 .getVisibleNotificationCount() != 0
@@ -2861,7 +2884,10 @@
         mHeadsUpStartHeight = startHeight;
         float scrimMinFraction;
         if (mSplitShadeEnabled) {
-            boolean highHun = mHeadsUpStartHeight * 2.5 > mSplitShadeScrimTransitionDistance;
+            boolean highHun = mHeadsUpStartHeight * 2.5
+                    >
+                    (mFeatureFlags.isEnabled(Flags.LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION)
+                    ? mSplitShadeFullTransitionDistance : mSplitShadeScrimTransitionDistance);
             // if HUN height is higher than 40% of predefined transition distance, it means HUN
             // is too high for regular transition. In that case we need to calculate transition
             // distance - here we take scrim transition distance as equal to shade transition
@@ -3061,7 +3087,9 @@
      */
     public void startFoldToAodAnimation(Runnable startAction, Runnable endAction,
             Runnable cancelAction) {
-        mView.animate()
+        final ViewPropertyAnimator viewAnimator = mView.animate();
+        viewAnimator.cancel();
+        viewAnimator
                 .translationX(0)
                 .alpha(1f)
                 .setDuration(ANIMATION_DURATION_FOLD_TO_AOD)
@@ -3080,9 +3108,14 @@
                     @Override
                     public void onAnimationEnd(Animator animation) {
                         endAction.run();
+
+                        viewAnimator.setListener(null);
+                        viewAnimator.setUpdateListener(null);
                     }
-                }).setUpdateListener(anim -> mKeyguardStatusViewController.animateFoldToAod(
-                        anim.getAnimatedFraction())).start();
+                })
+                .setUpdateListener(anim ->
+                        mKeyguardStatusViewController.animateFoldToAod(anim.getAnimatedFraction()))
+                .start();
     }
 
     /** Cancels fold to AOD transition and resets view state. */
@@ -3281,6 +3314,7 @@
     }
 
     public ViewPropertyAnimator fadeOut(long startDelayMs, long durationMs, Runnable endAction) {
+        mView.animate().cancel();
         return mView.animate().alpha(0).setStartDelay(startDelayMs).setDuration(
                 durationMs).setInterpolator(Interpolators.ALPHA_OUT).withLayer().withEndAction(
                 endAction);
@@ -3311,8 +3345,8 @@
     }
 
     @VisibleForTesting
-    TouchHandler createTouchHandler() {
-        return new TouchHandler();
+    TouchHandler getTouchHandler() {
+        return mTouchHandler;
     }
 
     public NotificationStackScrollLayoutController getNotificationStackScrollLayoutController() {
@@ -3530,7 +3564,13 @@
                             : (mKeyguardStateController.canDismissLockScreen()
                                     ? UNLOCK : BOUNCER_UNLOCK);
 
-            fling(vel, expand, isFalseTouch(x, y, interactionType));
+            // don't fling while in keyguard to avoid jump in shade expand animation;
+            // touch has been intercepted already so flinging here is redundant
+            if (mBarState == KEYGUARD && mExpandedFraction >= 1.0) {
+                mShadeLog.d("NPVC endMotionEvent - skipping fling on keyguard");
+            } else {
+                fling(vel, expand, isFalseTouch(x, y, interactionType));
+            }
             onTrackingStopped(expand);
             mUpdateFlingOnLayout = expand && mPanelClosedOnDown && !mHasLayoutedSinceDown;
             if (mUpdateFlingOnLayout) {
@@ -3681,10 +3721,10 @@
                     mHeightAnimator.end();
                 }
             }
-            mQsController.setShadeExpandedHeight(mExpandedHeight);
-            mExpansionDragDownAmountPx = h;
             mExpandedFraction = Math.min(1f,
                     maxPanelHeight == 0 ? 0 : mExpandedHeight / maxPanelHeight);
+            mQsController.setShadeExpansion(mExpandedHeight, mExpandedFraction);
+            mExpansionDragDownAmountPx = h;
             mAmbientState.setExpansionFraction(mExpandedFraction);
             onHeightUpdated(mExpandedHeight);
             updatePanelExpansionAndVisibility();
@@ -3960,14 +4000,14 @@
         return mView.post(action);
     }
 
-    /** */
-    public boolean sendInterceptTouchEventToView(MotionEvent event) {
-        return mView.onInterceptTouchEvent(event);
+    /** Sends an external (e.g. Status Bar) intercept touch event to the Shade touch handler. */
+    public boolean handleExternalInterceptTouch(MotionEvent event) {
+        return mTouchHandler.onInterceptTouchEvent(event);
     }
 
-    /** */
-    public boolean sendTouchEventToView(MotionEvent event) {
-        return mView.dispatchTouchEvent(event);
+    /** Sends an external (e.g. Status Bar) touch event to the Shade touch handler. */
+    public boolean handleExternalTouch(MotionEvent event) {
+        return mTouchHandler.onTouchEvent(event);
     }
 
     /** */
@@ -3985,14 +4025,6 @@
         return mView.isEnabled();
     }
 
-    int getDisplayRightInset() {
-        return mDisplayRightInset;
-    }
-
-    int getDisplayLeftInset() {
-        return mDisplayLeftInset;
-    }
-
     float getOverStretchAmount() {
         return mOverStretchAmount;
     }
@@ -4001,10 +4033,6 @@
         return mMinFraction;
     }
 
-    boolean getCollapsedOnDown() {
-        return mCollapsedOnDown;
-    }
-
     int getNavigationBarBottomHeight() {
         return mNavigationBarBottomHeight;
     }
@@ -4568,7 +4596,7 @@
     }
 
     /** Handles MotionEvents for the Shade. */
-    public final class TouchHandler implements View.OnTouchListener {
+    public final class TouchHandler implements View.OnTouchListener, Gefingerpoken {
         private long mLastTouchDownTime = -1L;
 
         /** @see ViewGroup#onInterceptTouchEvent(MotionEvent) */
@@ -4714,6 +4742,11 @@
 
         @Override
         public boolean onTouch(View v, MotionEvent event) {
+            return onTouchEvent(event);
+        }
+
+        @Override
+        public boolean onTouchEvent(MotionEvent event) {
             if (event.getAction() == MotionEvent.ACTION_DOWN) {
                 if (event.getDownTime() == mLastTouchDownTime) {
                     // An issue can occur when swiping down after unlock, where multiple down
@@ -4992,17 +5025,26 @@
             captureValues(transitionValues);
         }
 
+        @Nullable
         @Override
-        public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
-                TransitionValues endValues) {
+        public Animator createAnimator(ViewGroup sceneRoot, @Nullable TransitionValues startValues,
+                @Nullable TransitionValues endValues) {
+            if (startValues == null || endValues == null) {
+                return null;
+            }
             ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
 
             Rect from = (Rect) startValues.values.get(PROP_BOUNDS);
             Rect to = (Rect) endValues.values.get(PROP_BOUNDS);
 
-            anim.addUpdateListener(
-                    animation -> mController.getClockAnimations().onPositionUpdated(
-                            from, to, animation.getAnimatedFraction()));
+            anim.addUpdateListener(animation -> {
+                ClockAnimations clockAnims = mController.getClockAnimations();
+                if (clockAnims == null) {
+                    return;
+                }
+
+                clockAnims.onPositionUpdated(from, to, animation.getAnimatedFraction());
+            });
 
             return anim;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index c130b39..13f7be6 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -240,7 +240,9 @@
 
                 mFalsingCollector.onTouchEvent(ev);
                 mPulsingWakeupGestureHandler.onTouchEvent(ev);
-                mStatusBarKeyguardViewManager.onTouch(ev);
+                if (mStatusBarKeyguardViewManager.onTouch(ev)) {
+                    return true;
+                }
                 if (mBrightnessMirror != null
                         && mBrightnessMirror.getVisibility() == View.VISIBLE) {
                     // Disallow new pointers while the brightness mirror is visible. This is so that
@@ -342,7 +344,7 @@
                 MotionEvent cancellation = MotionEvent.obtain(ev);
                 cancellation.setAction(MotionEvent.ACTION_CANCEL);
                 mStackScrollLayout.onInterceptTouchEvent(cancellation);
-                mNotificationPanelViewController.sendInterceptTouchEventToView(cancellation);
+                mNotificationPanelViewController.handleExternalInterceptTouch(cancellation);
                 cancellation.recycle();
             }
 
diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
index 099ad94..6e185fe 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
@@ -339,7 +339,6 @@
         mFeatureFlags = featureFlags;
         mInteractionJankMonitor = interactionJankMonitor;
 
-        mShadeExpansionStateManager.addExpansionListener(this::onPanelExpansionChanged);
         mLockscreenShadeTransitionController.addCallback(new LockscreenShadeTransitionCallback());
     }
 
@@ -845,8 +844,9 @@
         mCollapsedOnDown = collapsedOnDown;
     }
 
-    void setShadeExpandedHeight(float shadeExpandedHeight) {
-        mShadeExpandedHeight = shadeExpandedHeight;
+    void setShadeExpansion(float expandedHeight, float expandedFraction) {
+        mShadeExpandedHeight = expandedHeight;
+        mShadeExpandedFraction = expandedFraction;
     }
 
     @VisibleForTesting
@@ -1035,7 +1035,11 @@
     private void setClippingBounds() {
         float qsExpansionFraction = computeExpansionFraction();
         final int qsPanelBottomY = calculateBottomPosition(qsExpansionFraction);
-        final boolean qsVisible = (qsExpansionFraction > 0 || qsPanelBottomY > 0);
+        // Split shade has no QQS
+        final boolean qqsVisible =
+                !mSplitShadeEnabled && qsExpansionFraction == 0 && qsPanelBottomY > 0;
+        final boolean qsVisible = qsExpansionFraction > 0;
+        final boolean qsOrQqsVisible = qqsVisible || qsVisible;
         checkCorrectScrimVisibility(qsExpansionFraction);
 
         int top = calculateTopClippingBound(qsPanelBottomY);
@@ -1044,7 +1048,7 @@
         int right = calculateRightClippingBound();
         // top should never be lower than bottom, otherwise it will be invisible.
         top = Math.min(top, bottom);
-        applyClippingBounds(left, top, right, bottom, qsVisible);
+        applyClippingBounds(left, top, right, bottom, qsOrQqsVisible);
     }
 
     /**
@@ -1694,11 +1698,6 @@
         return false;
     }
 
-    @VisibleForTesting
-    void onPanelExpansionChanged(ShadeExpansionChangeEvent event) {
-        mShadeExpandedFraction = event.getFraction();
-    }
-
     /**
      * Animate QS closing by flinging it.
      * If QS is expanded, it will collapse into QQS and stop.
diff --git a/packages/SystemUI/src/com/android/systemui/shade/transition/LargeScreenPortraitShadeInterpolator.kt b/packages/SystemUI/src/com/android/systemui/shade/transition/LargeScreenPortraitShadeInterpolator.kt
new file mode 100644
index 0000000..0519131
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shade/transition/LargeScreenPortraitShadeInterpolator.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shade.transition
+
+import android.util.MathUtils
+import com.android.systemui.animation.ShadeInterpolation
+import javax.inject.Inject
+
+/** Interpolator responsible for the shade when in portrait on a large screen. */
+internal class LargeScreenPortraitShadeInterpolator @Inject internal constructor() :
+    LargeScreenShadeInterpolator {
+
+    override fun getBehindScrimAlpha(fraction: Float): Float {
+        return MathUtils.constrainedMap(0f, 1f, 0f, 0.3f, fraction)
+    }
+
+    override fun getNotificationScrimAlpha(fraction: Float): Float {
+        return MathUtils.constrainedMap(0f, 1f, 0.3f, 0.75f, fraction)
+    }
+
+    override fun getNotificationContentAlpha(fraction: Float): Float {
+        return ShadeInterpolation.getContentAlpha(fraction)
+    }
+
+    override fun getNotificationFooterAlpha(fraction: Float): Float {
+        return ShadeInterpolation.getContentAlpha(fraction)
+    }
+
+    override fun getQsAlpha(fraction: Float): Float {
+        return ShadeInterpolation.getContentAlpha(fraction)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/transition/LargeScreenShadeInterpolator.kt b/packages/SystemUI/src/com/android/systemui/shade/transition/LargeScreenShadeInterpolator.kt
new file mode 100644
index 0000000..671dfc9c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shade/transition/LargeScreenShadeInterpolator.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shade.transition
+
+/** An interpolator interface for the shade expansion. */
+interface LargeScreenShadeInterpolator {
+
+    /** Returns the alpha for the behind/back scrim. */
+    fun getBehindScrimAlpha(fraction: Float): Float
+
+    /** Returns the alpha for the notification scrim. */
+    fun getNotificationScrimAlpha(fraction: Float): Float
+
+    /** Returns the alpha for the notifications. */
+    fun getNotificationContentAlpha(fraction: Float): Float
+
+    /** Returns the alpha for the notifications footer (Manager, Clear All). */
+    fun getNotificationFooterAlpha(fraction: Float): Float
+
+    /** Returns the alpha for the QS panel. */
+    fun getQsAlpha(fraction: Float): Float
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/transition/LargeScreenShadeInterpolatorImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/transition/LargeScreenShadeInterpolatorImpl.kt
new file mode 100644
index 0000000..fd57f21
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shade/transition/LargeScreenShadeInterpolatorImpl.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shade.transition
+
+import android.content.Context
+import android.content.res.Configuration
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.util.LargeScreenUtils
+import javax.inject.Inject
+
+/** Interpolator responsible for the shade when on large screens. */
+@SysUISingleton
+internal class LargeScreenShadeInterpolatorImpl
+@Inject
+internal constructor(
+    configurationController: ConfigurationController,
+    private val context: Context,
+    private val splitShadeInterpolator: SplitShadeInterpolator,
+    private val portraitShadeInterpolator: LargeScreenPortraitShadeInterpolator,
+) : LargeScreenShadeInterpolator {
+
+    private var inSplitShade = false
+
+    init {
+        configurationController.addCallback(
+            object : ConfigurationController.ConfigurationListener {
+                override fun onConfigChanged(newConfig: Configuration?) {
+                    updateResources()
+                }
+            }
+        )
+        updateResources()
+    }
+
+    private fun updateResources() {
+        inSplitShade = LargeScreenUtils.shouldUseSplitNotificationShade(context.resources)
+    }
+
+    private val impl: LargeScreenShadeInterpolator
+        get() =
+            if (inSplitShade) {
+                splitShadeInterpolator
+            } else {
+                portraitShadeInterpolator
+            }
+
+    override fun getBehindScrimAlpha(fraction: Float) = impl.getBehindScrimAlpha(fraction)
+
+    override fun getNotificationScrimAlpha(fraction: Float) =
+        impl.getNotificationScrimAlpha(fraction)
+
+    override fun getNotificationContentAlpha(fraction: Float) =
+        impl.getNotificationContentAlpha(fraction)
+
+    override fun getNotificationFooterAlpha(fraction: Float) =
+        impl.getNotificationFooterAlpha(fraction)
+
+    override fun getQsAlpha(fraction: Float) = impl.getQsAlpha(fraction)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt
index 218e897..4e1c272 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt
@@ -23,6 +23,8 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.dump.DumpManager
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
 import com.android.systemui.shade.PanelState
 import com.android.systemui.shade.STATE_OPENING
 import com.android.systemui.shade.ShadeExpansionChangeEvent
@@ -45,7 +47,8 @@
     private val scrimController: ScrimController,
     @Main private val resources: Resources,
     private val statusBarStateController: SysuiStatusBarStateController,
-    private val headsUpManager: HeadsUpManager
+    private val headsUpManager: HeadsUpManager,
+    private val featureFlags: FeatureFlags,
 ) {
 
     private var inSplitShade = false
@@ -106,7 +109,8 @@
                 // in case of HUN we can't always use predefined distances to manage scrim
                 // transition because dragDownPxAmount can start from value bigger than
                 // splitShadeScrimTransitionDistance
-                !headsUpManager.isTrackingHeadsUp
+                !headsUpManager.isTrackingHeadsUp &&
+                !featureFlags.isEnabled(Flags.LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION)
 
     private fun isScreenUnlocked() =
         statusBarStateController.currentOrUpcomingState == StatusBarState.SHADE
diff --git a/packages/SystemUI/src/com/android/systemui/shade/transition/SplitShadeInterpolator.kt b/packages/SystemUI/src/com/android/systemui/shade/transition/SplitShadeInterpolator.kt
new file mode 100644
index 0000000..423ba8d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shade/transition/SplitShadeInterpolator.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shade.transition
+
+import android.util.MathUtils
+import javax.inject.Inject
+
+/** Interpolator responsible for the split shade. */
+internal class SplitShadeInterpolator @Inject internal constructor() :
+    LargeScreenShadeInterpolator {
+
+    override fun getBehindScrimAlpha(fraction: Float): Float {
+        // Start delay: 0%
+        // Duration: 40%
+        // End: 40%
+        return mapFraction(start = 0f, end = 0.4f, fraction)
+    }
+
+    override fun getNotificationScrimAlpha(fraction: Float): Float {
+        // Start delay: 39%
+        // Duration: 27%
+        // End: 66%
+        return mapFraction(start = 0.39f, end = 0.66f, fraction)
+    }
+
+    override fun getNotificationContentAlpha(fraction: Float): Float {
+        return getNotificationScrimAlpha(fraction)
+    }
+
+    override fun getNotificationFooterAlpha(fraction: Float): Float {
+        // Start delay: 57.6%
+        // Duration: 32.1%
+        // End: 89.7%
+        return mapFraction(start = 0.576f, end = 0.897f, fraction)
+    }
+
+    override fun getQsAlpha(fraction: Float): Float {
+        return getNotificationScrimAlpha(fraction)
+    }
+
+    private fun mapFraction(start: Float, end: Float, fraction: Float) =
+        MathUtils.constrainedMap(
+            /* rangeMin= */ 0f,
+            /* rangeMax= */ 1f,
+            /* valueMin= */ start,
+            /* valueMax= */ end,
+            /* value= */ fraction
+        )
+}
diff --git a/packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceViewComponent.kt b/packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceViewComponent.kt
index 5736a5c..26149321 100644
--- a/packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceViewComponent.kt
+++ b/packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceViewComponent.kt
@@ -37,7 +37,8 @@
         fun create(
             @BindsInstance parent: ViewGroup,
             @BindsInstance @Named(PLUGIN) plugin: BcSmartspaceDataPlugin,
-            @BindsInstance onAttachListener: View.OnAttachStateChangeListener
+            @BindsInstance onAttachListener: View.OnAttachStateChangeListener,
+            @BindsInstance viewWithCustomLayout: View? = null
         ): SmartspaceViewComponent
     }
 
@@ -53,10 +54,13 @@
             falsingManager: FalsingManager,
             parent: ViewGroup,
             @Named(PLUGIN) plugin: BcSmartspaceDataPlugin,
+            viewWithCustomLayout: View?,
             onAttachListener: View.OnAttachStateChangeListener
         ):
                 BcSmartspaceDataPlugin.SmartspaceView {
-            val ssView = plugin.getView(parent)
+            val ssView = viewWithCustomLayout
+                    as? BcSmartspaceDataPlugin.SmartspaceView
+                    ?: plugin.getView(parent)
             // Currently, this is only used to provide SmartspaceView on Dream surface.
             ssView.setUiSurface(UI_SURFACE_DREAM)
             ssView.registerDataProvider(plugin)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
index 5adb58b..63179da 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
@@ -77,12 +77,6 @@
      */
     public static void fadeOut(View view, float fadeOutAmount, boolean remap) {
         view.animate().cancel();
-
-        // Don't fade out if already not visible.
-        if (view.getAlpha() == 0.0f) {
-            return;
-        }
-
         if (fadeOutAmount == 1.0f && view.getVisibility() != View.GONE) {
             view.setVisibility(View.INVISIBLE);
         } else if (view.getVisibility() == View.INVISIBLE) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index f4782c2..d5751f4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -177,10 +177,12 @@
     private boolean mVisible;
     private boolean mOrganizationOwnedDevice;
 
+    // these all assume the device is plugged in (wired/wireless/docked) AND chargingOrFull:
     private boolean mPowerPluggedIn;
     private boolean mPowerPluggedInWired;
     private boolean mPowerPluggedInWireless;
     private boolean mPowerPluggedInDock;
+
     private boolean mPowerCharged;
     private boolean mBatteryOverheated;
     private boolean mEnableBatteryDefender;
@@ -499,6 +501,7 @@
                 powerIndication += ",  " + (mChargingWattage / 1000) + " mW";
             }
 
+            mKeyguardLogger.logUpdateBatteryIndication(powerIndication, mPowerPluggedIn);
             mRotateTextViewController.updateIndication(
                     INDICATION_TYPE_BATTERY,
                     new KeyguardIndication.Builder()
@@ -507,6 +510,7 @@
                             .build(),
                     animate);
         } else {
+            mKeyguardLogger.log(TAG, LogLevel.DEBUG, "hide battery indication");
             // don't show the charging information if device isn't plugged in
             mRotateTextViewController.hideIndication(INDICATION_TYPE_BATTERY);
         }
@@ -885,6 +889,9 @@
         updateLockScreenIndications(animate, getCurrentUser());
     }
 
+    /**
+     * Assumption: device is charging
+     */
     protected String computePowerIndication() {
         int chargingId;
         if (mBatteryOverheated) {
@@ -1035,6 +1042,12 @@
             }
         }
 
+        /**
+         * KeyguardUpdateMonitor only sends "interesting" battery updates
+         * {@link KeyguardUpdateMonitor#isBatteryUpdateInteresting}.
+         * Therefore, make sure to always check plugged in state along with any charging status
+         * change, or else we could end up with stale state.
+         */
         @Override
         public void onRefreshBatteryInfo(BatteryStatus status) {
             boolean isChargingOrFull = status.status == BatteryManager.BATTERY_STATUS_CHARGING
@@ -1050,7 +1063,9 @@
             mBatteryLevel = status.level;
             mBatteryPresent = status.present;
             mBatteryOverheated = status.isOverheated();
+            // when the battery is overheated, device doesn't charge so only guard on pluggedIn:
             mEnableBatteryDefender = mBatteryOverheated && status.isPluggedIn();
+
             try {
                 mChargingTimeRemaining = mPowerPluggedIn
                         ? mBatteryInfo.computeChargeTimeRemaining() : -1;
@@ -1058,14 +1073,10 @@
                 mKeyguardLogger.log(TAG, ERROR, "Error calling IBatteryStats", e);
                 mChargingTimeRemaining = -1;
             }
+
+            mKeyguardLogger.logRefreshBatteryInfo(isChargingOrFull, mPowerPluggedIn, mBatteryLevel,
+                    mBatteryOverheated);
             updateDeviceEntryIndication(!wasPluggedIn && mPowerPluggedInWired);
-            if (mDozing) {
-                if (!wasPluggedIn && mPowerPluggedIn) {
-                    showTransientIndication(computePowerIndication());
-                } else if (wasPluggedIn && !mPowerPluggedIn) {
-                    hideTransientIndication();
-                }
-            }
         }
 
         @Override
@@ -1317,6 +1328,10 @@
         }
     }
 
+    protected boolean isPluggedInAndCharging() {
+        return mPowerPluggedIn;
+    }
+
     private boolean isCurrentUser(int userId) {
         return getCurrentUser() == userId;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 51c5183..cac4251 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -16,7 +16,6 @@
 package com.android.systemui.statusbar;
 
 import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED;
-
 import static com.android.systemui.DejankUtils.whitelistIpcs;
 
 import android.app.KeyguardManager;
@@ -145,7 +144,10 @@
                     break;
                 case Intent.ACTION_USER_UNLOCKED:
                     // Start the overview connection to the launcher service
-                    mOverviewProxyServiceLazy.get().startConnectionToCurrentUser();
+                    // Connect if user hasn't connected yet
+                    if (mOverviewProxyServiceLazy.get().getProxy() == null) {
+                        mOverviewProxyServiceLazy.get().startConnectionToCurrentUser();
+                    }
                     break;
                 case NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION:
                     final IntentSender intentSender = intent.getParcelableExtra(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 8f1e0a1..3709a13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -39,7 +39,10 @@
 import com.android.systemui.R;
 import com.android.systemui.animation.Interpolators;
 import com.android.systemui.animation.ShadeInterpolation;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
+import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
 import com.android.systemui.statusbar.notification.LegacySourceType;
 import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.statusbar.notification.SourceType;
@@ -216,7 +219,15 @@
                 if (ambientState.isBouncerInTransit()) {
                     viewState.setAlpha(aboutToShowBouncerProgress(expansion));
                 } else {
-                    viewState.setAlpha(ShadeInterpolation.getContentAlpha(expansion));
+                    FeatureFlags flags = ambientState.getFeatureFlags();
+                    if (ambientState.isSmallScreen() || !flags.isEnabled(
+                            Flags.LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION)) {
+                        viewState.setAlpha(ShadeInterpolation.getContentAlpha(expansion));
+                    } else {
+                        LargeScreenShadeInterpolator interpolator =
+                                ambientState.getLargeScreenShadeInterpolator();
+                        viewState.setAlpha(interpolator.getNotificationContentAlpha(expansion));
+                    }
                 }
             } else {
                 viewState.setAlpha(1f - ambientState.getHideAmount());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index c35c5c5..7755003 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -93,6 +93,16 @@
     @IntDef({STATE_ICON, STATE_DOT, STATE_HIDDEN})
     public @interface VisibleState { }
 
+    /** Returns a human-readable string of {@link VisibleState}. */
+    public static String getVisibleStateString(@VisibleState int state) {
+        switch(state) {
+            case STATE_ICON: return "ICON";
+            case STATE_DOT: return "DOT";
+            case STATE_HIDDEN: return "HIDDEN";
+            default: return "UNKNOWN";
+        }
+    }
+
     private static final String TAG = "StatusBarIconView";
     private static final Property<StatusBarIconView, Float> ICON_APPEAR_AMOUNT
             = new FloatProperty<StatusBarIconView>("iconAppearAmount") {
@@ -561,7 +571,8 @@
     @Override
     public String toString() {
         return "StatusBarIconView("
-                + "slot='" + mSlot + " alpha=" + getAlpha() + " icon=" + mIcon
+                + "slot='" + mSlot + "' alpha=" + getAlpha() + " icon=" + mIcon
+                + " visibleState=" + getVisibleStateString(getVisibleState())
                 + " iconColor=#" + Integer.toHexString(mIconColor)
                 + " notification=" + mNotification + ')';
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index 784e2d1..4070edf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -57,6 +57,7 @@
 import com.android.systemui.shade.ShadeExpansionStateManager;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
 import com.android.systemui.statusbar.policy.CallbackController;
+import com.android.systemui.util.Compile;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -300,7 +301,7 @@
 
     @Override
     public boolean setIsDreaming(boolean isDreaming) {
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
+        if (Log.isLoggable(TAG, Log.DEBUG) || Compile.IS_DEBUG) {
             Log.d(TAG, "setIsDreaming:" + isDreaming);
         }
         if (mIsDreaming == isDreaming) {
@@ -322,6 +323,11 @@
     }
 
     @Override
+    public boolean isDreaming() {
+        return mIsDreaming;
+    }
+
+    @Override
     public void setAndInstrumentDozeAmount(View view, float dozeAmount, boolean animated) {
         if (mDarkAnimator != null && mDarkAnimator.isRunning()) {
             if (animated && mDozeAmountTarget == dozeAmount) {
@@ -581,6 +587,7 @@
         pw.println(" mLeaveOpenOnKeyguardHide=" + mLeaveOpenOnKeyguardHide);
         pw.println(" mKeyguardRequested=" + mKeyguardRequested);
         pw.println(" mIsDozing=" + mIsDozing);
+        pw.println(" mIsDreaming=" + mIsDreaming);
         pw.println(" mListeners{" + mListeners.size() + "}=");
         for (RankedListener rl : mListeners) {
             pw.println("    " + rl.mListener);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
index b0ad6a1..37538a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
@@ -500,8 +500,10 @@
 
     private fun updateTextColorFromRegionSampler() {
         smartspaceViews.forEach {
-            val textColor = regionSamplers.getValue(it).currentForegroundColor()
-            it.setPrimaryTextColor(textColor)
+            val textColor = regionSamplers.get(it)?.currentForegroundColor()
+            if (textColor != null) {
+                it.setPrimaryTextColor(textColor)
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
index afeb72f..c40939f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
@@ -28,11 +28,8 @@
 import android.hardware.display.AmbientDisplayConfiguration;
 import android.os.Handler;
 import android.os.PowerManager;
-import android.os.RemoteException;
 import android.provider.Settings;
-import android.service.dreams.IDreamManager;
 import android.service.notification.StatusBarNotification;
-import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.UiEvent;
@@ -67,7 +64,6 @@
     private final KeyguardStateController mKeyguardStateController;
     private final ContentResolver mContentResolver;
     private final PowerManager mPowerManager;
-    private final IDreamManager mDreamManager;
     private final AmbientDisplayConfiguration mAmbientDisplayConfiguration;
     private final BatteryController mBatteryController;
     private final HeadsUpManager mHeadsUpManager;
@@ -109,7 +105,6 @@
     public NotificationInterruptStateProviderImpl(
             ContentResolver contentResolver,
             PowerManager powerManager,
-            IDreamManager dreamManager,
             AmbientDisplayConfiguration ambientDisplayConfiguration,
             BatteryController batteryController,
             StatusBarStateController statusBarStateController,
@@ -123,7 +118,6 @@
             UserTracker userTracker) {
         mContentResolver = contentResolver;
         mPowerManager = powerManager;
-        mDreamManager = dreamManager;
         mBatteryController = batteryController;
         mAmbientDisplayConfiguration = ambientDisplayConfiguration;
         mStatusBarStateController = statusBarStateController;
@@ -283,7 +277,9 @@
         }
 
         // If the device is currently dreaming, then launch the FullScreenIntent
-        if (isDreaming()) {
+        // We avoid using IDreamManager#isDreaming here as that method will return false during
+        // the dream's wake-up phase.
+        if (mStatusBarStateController.isDreaming()) {
             return getDecisionGivenSuppression(FullScreenIntentDecision.FSI_DEVICE_IS_DREAMING,
                     suppressedByDND);
         }
@@ -383,16 +379,6 @@
                 mLogger.logFullscreen(entry, "Expected not to HUN");
         }
     }
-
-    private boolean isDreaming() {
-        try {
-            return mDreamManager.isDreaming();
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to query dream manager.", e);
-            return false;
-        }
-    }
-
     private boolean shouldHeadsUpWhenAwake(NotificationEntry entry, boolean log) {
         StatusBarNotification sbn = entry.getSbn();
 
@@ -442,7 +428,7 @@
             return false;
         }
 
-        boolean inUse = mPowerManager.isScreenOn() && !isDreaming();
+        boolean inUse = mPowerManager.isScreenOn() && !mStatusBarStateController.isDreaming();
 
         if (!inUse) {
             if (log) mLogger.logNoHeadsUpNotInUse(entry);
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 64c1a59..11598e0 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
@@ -73,6 +73,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.util.ContrastColorUtil;
 import com.android.internal.widget.CachingIconView;
 import com.android.internal.widget.CallLayout;
@@ -153,7 +154,6 @@
     // We don't correctly track dark mode until the content views are inflated, so always update
     // the background on first content update just in case it happens to be during a theme change.
     private boolean mUpdateSelfBackgroundOnUpdate = true;
-    private boolean mNotificationTranslationFinished = false;
     private boolean mIsSnoozed;
     private boolean mIsFaded;
     private boolean mAnimatePinnedRoundness = false;
@@ -191,9 +191,7 @@
     private int mMaxSmallHeightBeforeS;
     private int mMaxSmallHeight;
     private int mMaxSmallHeightLarge;
-    private int mMaxSmallHeightMedia;
     private int mMaxExpandedHeight;
-    private int mIncreasedPaddingBetweenElements;
     private int mNotificationLaunchHeight;
     private boolean mMustStayOnScreen;
 
@@ -210,11 +208,6 @@
      */
     private boolean mUserExpanded;
     /**
-     * Whether the blocking helper is showing on this notification (even if dismissed)
-     */
-    private boolean mIsBlockingHelperShowing;
-
-    /**
      * Has this notification been expanded while it was pinned
      */
     private boolean mExpandedWhenPinned;
@@ -1566,18 +1559,6 @@
         }
     }
 
-    public void setBlockingHelperShowing(boolean isBlockingHelperShowing) {
-        mIsBlockingHelperShowing = isBlockingHelperShowing;
-    }
-
-    public boolean isBlockingHelperShowing() {
-        return mIsBlockingHelperShowing;
-    }
-
-    public boolean isBlockingHelperShowingAndTranslationFinished() {
-        return mIsBlockingHelperShowing && mNotificationTranslationFinished;
-    }
-
     @Override
     public View getShelfTransformationTarget() {
         if (mIsSummaryWithChildren && !shouldShowPublic()) {
@@ -1722,7 +1703,8 @@
             MetricsLogger metricsLogger,
             SmartReplyConstants smartReplyConstants,
             SmartReplyController smartReplyController,
-            FeatureFlags featureFlags) {
+            FeatureFlags featureFlags,
+            IStatusBarService statusBarService) {
         mEntry = entry;
         mAppName = appName;
         if (mMenuRow == null) {
@@ -1751,7 +1733,8 @@
                     mPeopleNotificationIdentifier,
                     rivSubcomponentFactory,
                     smartReplyConstants,
-                    smartReplyController);
+                    smartReplyController,
+                    statusBarService);
         }
         mOnUserInteractionCallback = onUserInteractionCallback;
         mBubblesManagerOptional = bubblesManagerOptional;
@@ -1771,8 +1754,6 @@
                 R.dimen.notification_min_height);
         mMaxSmallHeightLarge = NotificationUtils.getFontScaledHeight(mContext,
                 R.dimen.notification_min_height_increased);
-        mMaxSmallHeightMedia = NotificationUtils.getFontScaledHeight(mContext,
-                R.dimen.notification_min_height_media);
         mMaxExpandedHeight = NotificationUtils.getFontScaledHeight(mContext,
                 R.dimen.notification_max_height);
         mMaxHeadsUpHeightBeforeN = NotificationUtils.getFontScaledHeight(mContext,
@@ -2158,10 +2139,7 @@
     @Override
     public void setTranslation(float translationX) {
         invalidate();
-        if (isBlockingHelperShowingAndTranslationFinished()) {
-            mGuts.setTranslationX(translationX);
-            return;
-        } else if (mDismissUsingRowTranslationX) {
+        if (mDismissUsingRowTranslationX) {
             setTranslationX(translationX);
         } else if (mTranslateableViews != null) {
             // Translate the group of views
@@ -2189,10 +2167,6 @@
             return getTranslationX();
         }
 
-        if (isBlockingHelperShowingAndCanTranslate()) {
-            return mGuts.getTranslationX();
-        }
-
         if (mTranslateableViews != null && mTranslateableViews.size() > 0) {
             // All of the views in the list should have same translation, just use first one.
             return mTranslateableViews.get(0).getTranslationX();
@@ -2201,10 +2175,6 @@
         return 0;
     }
 
-    private boolean isBlockingHelperShowingAndCanTranslate() {
-        return areGutsExposed() && mIsBlockingHelperShowing && mNotificationTranslationFinished;
-    }
-
     public Animator getTranslateViewAnimator(final float leftTarget,
                                              AnimatorUpdateListener listener) {
         if (mTranslateAnim != null) {
@@ -2226,9 +2196,6 @@
 
             @Override
             public void onAnimationEnd(Animator anim) {
-                if (mIsBlockingHelperShowing) {
-                    mNotificationTranslationFinished = true;
-                }
                 if (!cancelled && leftTarget == 0) {
                     if (mMenuRow != null) {
                         mMenuRow.resetMenu();
@@ -2808,9 +2775,10 @@
         int intrinsicBefore = getIntrinsicHeight();
         mSensitive = sensitive;
         mSensitiveHiddenInGeneral = hideSensitive;
-        if (intrinsicBefore != getIntrinsicHeight()) {
-            // The animation has a few flaws and is highly visible, so jump cut instead.
-            notifyHeightChanged(false /* needsAnimation */);
+        int intrinsicAfter = getIntrinsicHeight();
+        if (intrinsicBefore != intrinsicAfter) {
+            boolean needsAnimation = mFeatureFlags.isEnabled(Flags.SENSITIVE_REVEAL_ANIM);
+            notifyHeightChanged(needsAnimation);
         }
     }
 
@@ -2867,13 +2835,19 @@
         View[] publicViews = new View[]{mPublicLayout};
         View[] hiddenChildren = showingPublic ? privateViews : publicViews;
         View[] shownChildren = showingPublic ? publicViews : privateViews;
+        // disappear/appear overlap: 10 percent of duration
+        long overlap = duration / 10;
+        // disappear duration: 1/3 of duration + half of overlap
+        long disappearDuration = duration / 3 + overlap / 2;
+        // appear duration: 2/3 of duration + half of overlap
+        long appearDuration = (duration - disappearDuration) + overlap / 2;
         for (final View hiddenView : hiddenChildren) {
             hiddenView.setVisibility(View.VISIBLE);
             hiddenView.animate().cancel();
             hiddenView.animate()
                     .alpha(0f)
                     .setStartDelay(delay)
-                    .setDuration(duration)
+                    .setDuration(disappearDuration)
                     .withEndAction(() -> {
                         hiddenView.setVisibility(View.INVISIBLE);
                         resetAllContentAlphas();
@@ -2885,8 +2859,8 @@
             showView.animate().cancel();
             showView.animate()
                     .alpha(1f)
-                    .setStartDelay(delay)
-                    .setDuration(duration);
+                    .setStartDelay(delay + duration - appearDuration)
+                    .setDuration(appearDuration);
         }
     }
 
@@ -3137,14 +3111,6 @@
         return showingLayout != null && showingLayout.requireRowToHaveOverlappingRendering();
     }
 
-    @Override
-    public int getExtraBottomPadding() {
-        if (mIsSummaryWithChildren && isGroupExpanded()) {
-            return mIncreasedPaddingBetweenElements;
-        }
-        return 0;
-    }
-
     public void setInlineReplyAnimationFlagEnabled(boolean isEnabled) {
         mIsInlineReplyAnimationFlagEnabled = isEnabled;
     }
@@ -3727,7 +3693,9 @@
             }
             pw.println("Roundness: " + getRoundableState().debugString());
 
-            if (mIsSummaryWithChildren) {
+            int transientViewCount = mChildrenContainer == null
+                    ? 0 : mChildrenContainer.getTransientViewCount();
+            if (mIsSummaryWithChildren || transientViewCount > 0) {
                 pw.println();
                 pw.print("ChildrenContainer");
                 pw.print(" visibility: " + mChildrenContainer.getVisibility());
@@ -3735,8 +3703,7 @@
                 pw.print(", translationY: " + mChildrenContainer.getTranslationY());
                 pw.println();
                 List<ExpandableNotificationRow> notificationChildren = getAttachedChildren();
-                pw.println("Children: " + notificationChildren.size());
-                pw.print("{");
+                pw.print("Children: " + notificationChildren.size() + " {");
                 pw.increaseIndent();
                 for (ExpandableNotificationRow child : notificationChildren) {
                     pw.println();
@@ -3744,6 +3711,15 @@
                 }
                 pw.decreaseIndent();
                 pw.println("}");
+                pw.print("Transient Views: " + transientViewCount + " {");
+                pw.increaseIndent();
+                for (int i = 0; i < transientViewCount; i++) {
+                    pw.println();
+                    ExpandableView child = (ExpandableView) mChildrenContainer.getTransientView(i);
+                    child.dump(pw, args);
+                }
+                pw.decreaseIndent();
+                pw.println("}");
             } else if (mPrivateLayout != null) {
                 mPrivateLayout.dumpSmartReplies(pw);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index bb92dfc..b6f0a05 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -29,6 +29,7 @@
 import androidx.annotation.Nullable;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.statusbar.IStatusBarService;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
@@ -100,6 +101,7 @@
     private final SmartReplyConstants mSmartReplyConstants;
     private final SmartReplyController mSmartReplyController;
     private final ExpandableNotificationRowDragController mDragController;
+    private final IStatusBarService mStatusBarService;
     private final ExpandableNotificationRow.ExpandableNotificationRowLogger mLoggerCallback =
             new ExpandableNotificationRow.ExpandableNotificationRowLogger() {
                 @Override
@@ -157,7 +159,8 @@
             FeatureFlags featureFlags,
             PeopleNotificationIdentifier peopleNotificationIdentifier,
             Optional<BubblesManager> bubblesManagerOptional,
-            ExpandableNotificationRowDragController dragController) {
+            ExpandableNotificationRowDragController dragController,
+            IStatusBarService statusBarService) {
         mView = view;
         mListContainer = listContainer;
         mRemoteInputViewSubcomponentFactory = rivSubcomponentFactory;
@@ -189,6 +192,7 @@
         mLogBufferLogger = logBufferLogger;
         mSmartReplyConstants = smartReplyConstants;
         mSmartReplyController = smartReplyController;
+        mStatusBarService = statusBarService;
     }
 
     /**
@@ -220,7 +224,8 @@
                 mMetricsLogger,
                 mSmartReplyConstants,
                 mSmartReplyController,
-                mFeatureFlags
+                mFeatureFlags,
+                mStatusBarService
         );
         mView.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
         if (mAllowLongPress) {
@@ -312,7 +317,7 @@
         }
         mView.removeChildNotification(childView);
         if (!isTransfer) {
-            mListContainer.notifyGroupChildRemoved(childView, mView);
+            mListContainer.notifyGroupChildRemoved(childView, mView.getChildrenContainer());
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index 25c7264..9df6ba9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -451,7 +451,7 @@
     protected void updateClipping() {
         if (mClipToActualHeight && shouldClipToActualHeight()) {
             int top = getClipTopAmount();
-            int bottom = Math.max(Math.max(getActualHeight() + getExtraBottomPadding()
+            int bottom = Math.max(Math.max(getActualHeight()
                     - mClipBottomAmount, top), mMinimumHeightForClipping);
             mClipRect.set(Integer.MIN_VALUE, top, Integer.MAX_VALUE, bottom);
             setClipBounds(mClipRect);
@@ -592,13 +592,6 @@
     }
 
     /**
-     * @return padding used to alter how much of the view is clipped.
-     */
-    public int getExtraBottomPadding() {
-        return 0;
-    }
-
-    /**
      * @return true if the group's expansion state is changing, false otherwise.
      */
     public boolean isGroupExpansionChanging() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index 39e4000..4522e41 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -443,6 +443,7 @@
         CancellationSignal cancellationSignal = new CancellationSignal();
         cancellationSignal.setOnCancelListener(
                 () -> runningInflations.values().forEach(CancellationSignal::cancel));
+
         return cancellationSignal;
     }
 
@@ -783,6 +784,7 @@
     public static class AsyncInflationTask extends AsyncTask<Void, Void, InflationProgress>
             implements InflationCallback, InflationTask {
 
+        private static final long IMG_PRELOAD_TIMEOUT_MS = 1000L;
         private final NotificationEntry mEntry;
         private final Context mContext;
         private final boolean mInflateSynchronously;
@@ -876,7 +878,7 @@
                         recoveredBuilder, mIsLowPriority, mUsesIncreasedHeight,
                         mUsesIncreasedHeadsUpHeight, packageContext);
                 InflatedSmartReplyState previousSmartReplyState = mRow.getExistingSmartReplyState();
-                return inflateSmartReplyViews(
+                InflationProgress result = inflateSmartReplyViews(
                         inflationProgress,
                         mReInflateFlags,
                         mEntry,
@@ -884,6 +886,11 @@
                         packageContext,
                         previousSmartReplyState,
                         mSmartRepliesInflater);
+
+                // wait for image resolver to finish preloading
+                mRow.getImageResolver().waitForPreloadedImages(IMG_PRELOAD_TIMEOUT_MS);
+
+                return result;
             } catch (Exception e) {
                 mError = e;
                 return null;
@@ -918,6 +925,9 @@
                 mCallback.handleInflationException(mRow.getEntry(),
                         new InflationException("Couldn't inflate contentViews" + e));
             }
+
+            // Cancel any image loading tasks, not useful any more
+            mRow.getImageResolver().cancelRunningTasks();
         }
 
         @Override
@@ -944,6 +954,9 @@
             // Notify the resolver that the inflation task has finished,
             // try to purge unnecessary cached entries.
             mRow.getImageResolver().purgeCache();
+
+            // Cancel any image loading tasks that have not completed at this point
+            mRow.getImageResolver().cancelRunningTasks();
         }
 
         private static class RtlEnabledContext extends ContextWrapper {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 4a023c4..ef32a08 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -21,10 +21,13 @@
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.content.Context;
+import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
+import android.os.RemoteException;
 import android.provider.Settings;
+import android.service.notification.StatusBarNotification;
 import android.util.ArrayMap;
 import android.util.AttributeSet;
 import android.util.IndentingPrintWriter;
@@ -39,6 +42,7 @@
 import android.widget.LinearLayout;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.statusbar.IStatusBarService;
 import com.android.systemui.R;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.statusbar.RemoteInputController;
@@ -129,6 +133,7 @@
     private Runnable mExpandedVisibleListener;
     private PeopleNotificationIdentifier mPeopleIdentifier;
     private RemoteInputViewSubcomponent.Factory mRemoteInputSubcomponentFactory;
+    private IStatusBarService mStatusBarService;
 
     /**
      * List of listeners for when content views become inactive (i.e. not the showing view).
@@ -196,11 +201,13 @@
             PeopleNotificationIdentifier peopleNotificationIdentifier,
             RemoteInputViewSubcomponent.Factory rivSubcomponentFactory,
             SmartReplyConstants smartReplyConstants,
-            SmartReplyController smartReplyController) {
+            SmartReplyController smartReplyController,
+            IStatusBarService statusBarService) {
         mPeopleIdentifier = peopleNotificationIdentifier;
         mRemoteInputSubcomponentFactory = rivSubcomponentFactory;
         mSmartReplyConstants = smartReplyConstants;
         mSmartReplyController = smartReplyController;
+        mStatusBarService = statusBarService;
     }
 
     public void reinflate() {
@@ -2176,4 +2183,36 @@
     protected void setHeadsUpWrapper(NotificationViewWrapper headsUpWrapper) {
         mHeadsUpWrapper = headsUpWrapper;
     }
+
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        try {
+            super.dispatchDraw(canvas);
+        } catch (Exception e) {
+            // Catch draw exceptions that may be caused by RemoteViews
+            Log.e(TAG, "Drawing view failed: " + e);
+            cancelNotification(e);
+        }
+    }
+
+    private void cancelNotification(Exception exception) {
+        try {
+            setVisibility(GONE);
+            final StatusBarNotification sbn = mNotificationEntry.getSbn();
+            if (mStatusBarService != null) {
+                // report notification inflation errors back up
+                // to notification delegates
+                mStatusBarService.onNotificationError(
+                        sbn.getPackageName(),
+                        sbn.getTag(),
+                        sbn.getId(),
+                        sbn.getUid(),
+                        sbn.getInitialPid(),
+                        exception.getMessage(),
+                        sbn.getUser().getIdentifier());
+            }
+        } catch (RemoteException ex) {
+            Log.e(TAG, "cancelNotification failed: " + ex);
+        }
+    }
 }
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 93f0812..596bdc0 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
@@ -238,12 +238,11 @@
     }
 
     public void openControls(
-            boolean shouldDoCircularReveal,
             int x,
             int y,
             boolean needsFalsingProtection,
             @Nullable Runnable onAnimationEnd) {
-        animateOpen(shouldDoCircularReveal, x, y, onAnimationEnd);
+        animateOpen(x, y, onAnimationEnd);
         setExposed(true /* exposed */, needsFalsingProtection);
     }
 
@@ -300,7 +299,7 @@
         if (mGutsContent == null
                 || !mGutsContent.handleCloseControls(save, force)) {
             // We only want to do a circular reveal if we're not showing the blocking helper.
-            animateClose(x, y, true /* shouldDoCircularReveal */);
+            animateClose(x, y);
 
             setExposed(false, mNeedsFalsingProtection);
             if (mClosedListener != null) {
@@ -309,66 +308,45 @@
         }
     }
 
-    /** Animates in the guts view via either a fade or a circular reveal. */
-    private void animateOpen(
-            boolean shouldDoCircularReveal, int x, int y, @Nullable Runnable onAnimationEnd) {
+    /** Animates in the guts view with a circular reveal. */
+    private void animateOpen(int x, int y, @Nullable Runnable onAnimationEnd) {
         if (isAttachedToWindow()) {
-            if (shouldDoCircularReveal) {
-                double horz = Math.max(getWidth() - x, x);
-                double vert = Math.max(getHeight() - y, y);
-                float r = (float) Math.hypot(horz, vert);
-                // Make sure we'll be visible after the circular reveal
-                setAlpha(1f);
-                // Circular reveal originating at (x, y)
-                Animator a = ViewAnimationUtils.createCircularReveal(this, x, y, 0, r);
-                a.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
-                a.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
-                a.addListener(new AnimateOpenListener(onAnimationEnd));
-                a.start();
-            } else {
-                // Fade in content
-                this.setAlpha(0f);
-                this.animate()
-                        .alpha(1f)
-                        .setDuration(StackStateAnimator.ANIMATION_DURATION_BLOCKING_HELPER_FADE)
-                        .setInterpolator(Interpolators.ALPHA_IN)
-                        .setListener(new AnimateOpenListener(onAnimationEnd))
-                        .start();
-            }
+            double horz = Math.max(getWidth() - x, x);
+            double vert = Math.max(getHeight() - y, y);
+            float r = (float) Math.hypot(horz, vert);
+            // Make sure we'll be visible after the circular reveal
+            setAlpha(1f);
+            // Circular reveal originating at (x, y)
+            Animator a = ViewAnimationUtils.createCircularReveal(this, x, y, 0, r);
+            a.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+            a.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
+            a.addListener(new AnimateOpenListener(onAnimationEnd));
+            a.start();
+
         } else {
             Log.w(TAG, "Failed to animate guts open");
         }
     }
 
 
-    /** Animates out the guts view via either a fade or a circular reveal. */
+    /** Animates out the guts view with a circular reveal. */
     @VisibleForTesting
-    void animateClose(int x, int y, boolean shouldDoCircularReveal) {
+    void animateClose(int x, int y) {
         if (isAttachedToWindow()) {
-            if (shouldDoCircularReveal) {
-                // Circular reveal originating at (x, y)
-                if (x == -1 || y == -1) {
-                    x = (getLeft() + getRight()) / 2;
-                    y = (getTop() + getHeight() / 2);
-                }
-                double horz = Math.max(getWidth() - x, x);
-                double vert = Math.max(getHeight() - y, y);
-                float r = (float) Math.hypot(horz, vert);
-                Animator a = ViewAnimationUtils.createCircularReveal(this,
-                        x, y, r, 0);
-                a.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
-                a.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
-                a.addListener(new AnimateCloseListener(this /* view */, mGutsContent));
-                a.start();
-            } else {
-                // Fade in the blocking helper.
-                this.animate()
-                        .alpha(0f)
-                        .setDuration(StackStateAnimator.ANIMATION_DURATION_BLOCKING_HELPER_FADE)
-                        .setInterpolator(Interpolators.ALPHA_OUT)
-                        .setListener(new AnimateCloseListener(this, /* view */mGutsContent))
-                        .start();
+            // Circular reveal originating at (x, y)
+            if (x == -1 || y == -1) {
+                x = (getLeft() + getRight()) / 2;
+                y = (getTop() + getHeight() / 2);
             }
+            double horz = Math.max(getWidth() - x, x);
+            double vert = Math.max(getHeight() - y, y);
+            float r = (float) Math.hypot(horz, vert);
+            Animator a = ViewAnimationUtils.createCircularReveal(this,
+                    x, y, r, 0);
+            a.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+            a.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
+            a.addListener(new AnimateCloseListener(this /* view */, mGutsContent));
+            a.start();
         } else {
             Log.w(TAG, "Failed to animate guts close");
             mGutsContent.onFinishedClosing();
@@ -449,7 +427,7 @@
         return mGutsContent != null && mGutsContent.isLeavebehind();
     }
 
-    /** Listener for animations executed in {@link #animateOpen(boolean, int, int, Runnable)}. */
+    /** Listener for animations executed in {@link #animateOpen(int, int, Runnable)}. */
     private static class AnimateOpenListener extends AnimatorListenerAdapter {
         final Runnable mOnAnimationEnd;
 
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 06d4080..46f1bb5 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
@@ -629,7 +629,6 @@
                                 !mAccessibilityManager.isTouchExplorationEnabled());
 
                 guts.openControls(
-                        !row.isBlockingHelperShowing(),
                         x,
                         y,
                         needsFalsingProtection,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java
index 41eeada0..fe0b312 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java
@@ -22,8 +22,11 @@
 import android.util.Log;
 
 import java.util.Set;
+import java.util.concurrent.CancellationException;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 /**
  * A cache for inline images of image messages.
@@ -56,12 +59,13 @@
     }
 
     @Override
-    public Drawable get(Uri uri) {
+    public Drawable get(Uri uri, long timeoutMs) {
         Drawable result = null;
         try {
-            result = mCache.get(uri).get();
-        } catch (InterruptedException | ExecutionException ex) {
-            Log.d(TAG, "get: Failed get image from " + uri);
+            result = mCache.get(uri).get(timeoutMs, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException | ExecutionException
+                | TimeoutException | CancellationException ex) {
+            Log.d(TAG, "get: Failed get image from " + uri + " " + ex);
         }
         return result;
     }
@@ -72,6 +76,15 @@
         mCache.entrySet().removeIf(entry -> !wantedSet.contains(entry.getKey()));
     }
 
+    @Override
+    public void cancelRunningTasks() {
+        mCache.forEach((key, value) -> {
+            if (value.getStatus() != AsyncTask.Status.FINISHED) {
+                value.cancel(true);
+            }
+        });
+    }
+
     private static class PreloadImageTask extends AsyncTask<Uri, Void, Drawable> {
         private final NotificationInlineImageResolver mResolver;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
index b05e64ab..c620f44 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
@@ -23,6 +23,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Parcelable;
+import android.os.SystemClock;
 import android.util.Log;
 
 import com.android.internal.R;
@@ -45,6 +46,9 @@
 public class NotificationInlineImageResolver implements ImageResolver {
     private static final String TAG = NotificationInlineImageResolver.class.getSimpleName();
 
+    // Timeout for loading images from ImageCache when calling from UI thread
+    private static final long MAX_UI_THREAD_TIMEOUT_MS = 100L;
+
     private final Context mContext;
     private final ImageCache mImageCache;
     private Set<Uri> mWantedUriSet;
@@ -123,17 +127,25 @@
         return null;
     }
 
+    /**
+     * Loads an image from the Uri.
+     * This method is synchronous and is usually called from the Main thread.
+     * It will time-out after MAX_UI_THREAD_TIMEOUT_MS.
+     *
+     * @param uri Uri of the target image.
+     * @return drawable of the image, null if loading failed/timeout
+     */
     @Override
     public Drawable loadImage(Uri uri) {
-        return hasCache() ? loadImageFromCache(uri) : resolveImage(uri);
+        return hasCache() ? loadImageFromCache(uri, MAX_UI_THREAD_TIMEOUT_MS) : resolveImage(uri);
     }
 
-    private Drawable loadImageFromCache(Uri uri) {
+    private Drawable loadImageFromCache(Uri uri, long timeoutMs) {
         // if the uri isn't currently cached, try caching it first
         if (!mImageCache.hasEntry(uri)) {
             mImageCache.preload((uri));
         }
-        return mImageCache.get(uri);
+        return mImageCache.get(uri, timeoutMs);
     }
 
     /**
@@ -208,6 +220,30 @@
     }
 
     /**
+     * Wait for a maximum timeout for images to finish preloading
+     * @param timeoutMs total timeout time
+     */
+    void waitForPreloadedImages(long timeoutMs) {
+        if (!hasCache()) {
+            return;
+        }
+        Set<Uri> preloadedUris = getWantedUriSet();
+        if (preloadedUris != null) {
+            // Decrement remaining timeout after each image check
+            long endTimeMs = SystemClock.elapsedRealtime() + timeoutMs;
+            preloadedUris.forEach(
+                    uri -> loadImageFromCache(uri, endTimeMs - SystemClock.elapsedRealtime()));
+        }
+    }
+
+    void cancelRunningTasks() {
+        if (!hasCache()) {
+            return;
+        }
+        mImageCache.cancelRunningTasks();
+    }
+
+    /**
      * A interface for internal cache implementation of this resolver.
      */
     interface ImageCache {
@@ -216,7 +252,7 @@
          * @param uri The uri of the image.
          * @return Drawable of the image.
          */
-        Drawable get(Uri uri);
+        Drawable get(Uri uri, long timeoutMs);
 
         /**
          * Set the image resolver that actually resolves image from specified uri.
@@ -241,6 +277,11 @@
          * Purge unnecessary entries in the cache.
          */
         void purge();
+
+        /**
+         * Cancel all unfinished image loading tasks
+         */
+        void cancelRunningTasks();
     }
 
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index 6f4d6d9..77ede04 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -29,6 +29,8 @@
 import com.android.systemui.R;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -55,6 +57,8 @@
 
     private final SectionProvider mSectionProvider;
     private final BypassController mBypassController;
+    private final LargeScreenShadeInterpolator mLargeScreenShadeInterpolator;
+    private final FeatureFlags mFeatureFlags;
     /**
      *  Used to read bouncer states.
      */
@@ -84,7 +88,7 @@
     private float mExpandingVelocity;
     private boolean mPanelTracking;
     private boolean mExpansionChanging;
-    private boolean mPanelFullWidth;
+    private boolean mIsSmallScreen;
     private boolean mPulsing;
     private boolean mUnlockHintRunning;
     private float mHideAmount;
@@ -252,10 +256,14 @@
             @NonNull DumpManager dumpManager,
             @NonNull SectionProvider sectionProvider,
             @NonNull BypassController bypassController,
-            @Nullable StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
+            @Nullable StatusBarKeyguardViewManager statusBarKeyguardViewManager,
+            @NonNull LargeScreenShadeInterpolator largeScreenShadeInterpolator,
+            @NonNull FeatureFlags featureFlags) {
         mSectionProvider = sectionProvider;
         mBypassController = bypassController;
         mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
+        mLargeScreenShadeInterpolator = largeScreenShadeInterpolator;
+        mFeatureFlags = featureFlags;
         reload(context);
         dumpManager.registerDumpable(this);
     }
@@ -574,12 +582,12 @@
         return mPanelTracking;
     }
 
-    public boolean isPanelFullWidth() {
-        return mPanelFullWidth;
+    public boolean isSmallScreen() {
+        return mIsSmallScreen;
     }
 
-    public void setPanelFullWidth(boolean panelFullWidth) {
-        mPanelFullWidth = panelFullWidth;
+    public void setSmallScreen(boolean smallScreen) {
+        mIsSmallScreen = smallScreen;
     }
 
     public void setUnlockHintRunning(boolean unlockHintRunning) {
@@ -736,6 +744,14 @@
         return mIsClosing;
     }
 
+    public LargeScreenShadeInterpolator getLargeScreenShadeInterpolator() {
+        return mLargeScreenShadeInterpolator;
+    }
+
+    public FeatureFlags getFeatureFlags() {
+        return mFeatureFlags;
+    }
+
     @Override
     public void dump(PrintWriter pw, String[] args) {
         pw.println("mTopPadding=" + mTopPadding);
@@ -751,7 +767,7 @@
         pw.println("mDimmed=" + mDimmed);
         pw.println("mStatusBarState=" + mStatusBarState);
         pw.println("mExpansionChanging=" + mExpansionChanging);
-        pw.println("mPanelFullWidth=" + mPanelFullWidth);
+        pw.println("mPanelFullWidth=" + mIsSmallScreen);
         pw.println("mPulsing=" + mPulsing);
         pw.println("mPulseHeight=" + mPulseHeight);
         pw.println("mTrackedHeadsUpRow.key=" + logKey(mTrackedHeadsUpRow));
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 d2087ba6..2c088fa 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
@@ -67,6 +67,7 @@
 import android.view.ViewOutlineProvider;
 import android.view.ViewTreeObserver;
 import android.view.WindowInsets;
+import android.view.WindowInsetsAnimation;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.animation.AnimationUtils;
@@ -199,6 +200,7 @@
     private final boolean mDebugRemoveAnimation;
     private final boolean mSimplifiedAppearFraction;
     private final boolean mUseRoundnessSourceTypes;
+    private boolean mAnimatedInsets;
 
     private int mContentHeight;
     private float mIntrinsicContentHeight;
@@ -207,7 +209,8 @@
     private int mTopPadding;
     private boolean mAnimateNextTopPaddingChange;
     private int mBottomPadding;
-    private int mBottomInset = 0;
+    @VisibleForTesting
+    int mBottomInset = 0;
     private float mQsExpansionFraction;
     private final int mSplitShadeMinContentHeight;
 
@@ -388,9 +391,33 @@
             }
         }
     };
+
     private boolean mPulsing;
     private boolean mScrollable;
     private View mForcedScroll;
+    private boolean mIsInsetAnimationRunning;
+
+    private final WindowInsetsAnimation.Callback mInsetsCallback =
+            new WindowInsetsAnimation.Callback(
+                    WindowInsetsAnimation.Callback.DISPATCH_MODE_CONTINUE_ON_SUBTREE) {
+
+                @Override
+                public void onPrepare(WindowInsetsAnimation animation) {
+                    mIsInsetAnimationRunning = true;
+                }
+
+                @Override
+                public WindowInsets onProgress(WindowInsets windowInsets,
+                        List<WindowInsetsAnimation> list) {
+                    updateBottomInset(windowInsets);
+                    return windowInsets;
+                }
+
+                @Override
+                public void onEnd(WindowInsetsAnimation animation) {
+                    mIsInsetAnimationRunning = false;
+                }
+            };
 
     /**
      * @see #setHideAmount(float, float)
@@ -584,6 +611,7 @@
         mDebugRemoveAnimation = featureFlags.isEnabled(Flags.NSSL_DEBUG_REMOVE_ANIMATION);
         mSimplifiedAppearFraction = featureFlags.isEnabled(Flags.SIMPLIFIED_APPEAR_FRACTION);
         mUseRoundnessSourceTypes = featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES);
+        setAnimatedInsetsEnabled(featureFlags.isEnabled(Flags.ANIMATED_NOTIFICATION_SHADE_INSETS));
         mSectionsManager = Dependency.get(NotificationSectionsManager.class);
         mScreenOffAnimationController =
                 Dependency.get(ScreenOffAnimationController.class);
@@ -622,6 +650,9 @@
         mGroupMembershipManager = Dependency.get(GroupMembershipManager.class);
         mGroupExpansionManager = Dependency.get(GroupExpansionManager.class);
         setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+        if (mAnimatedInsets) {
+            setWindowInsetsAnimationCallback(mInsetsCallback);
+        }
     }
 
     /**
@@ -690,6 +721,11 @@
     }
 
     @VisibleForTesting
+    void setAnimatedInsetsEnabled(boolean enabled) {
+        mAnimatedInsets = enabled;
+    }
+
+    @VisibleForTesting
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     public void updateFooter() {
         if (mFooterView == null) {
@@ -1781,7 +1817,11 @@
             return;
         }
         mForcedScroll = v;
-        scrollTo(v);
+        if (mAnimatedInsets) {
+            updateForcedScroll();
+        } else {
+            scrollTo(v);
+        }
     }
 
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
@@ -1813,26 +1853,46 @@
                 + ((!isExpanded() && isPinnedHeadsUp(v)) ? mHeadsUpInset : getTopPadding());
     }
 
+    private void updateBottomInset(WindowInsets windowInsets) {
+        mBottomInset = windowInsets.getInsets(WindowInsets.Type.ime()).bottom;
+
+        if (mForcedScroll != null) {
+            updateForcedScroll();
+        }
+
+        int range = getScrollRange();
+        if (mOwnScrollY > range) {
+            setOwnScrollY(range);
+        }
+    }
+
     @Override
     @ShadeViewRefactor(RefactorComponent.COORDINATOR)
     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
-        mBottomInset = insets.getInsets(WindowInsets.Type.ime()).bottom;
+        if (!mAnimatedInsets) {
+            mBottomInset = insets.getInsets(WindowInsets.Type.ime()).bottom;
+        }
         mWaterfallTopInset = 0;
         final DisplayCutout cutout = insets.getDisplayCutout();
         if (cutout != null) {
             mWaterfallTopInset = cutout.getWaterfallInsets().top;
         }
-
-        int range = getScrollRange();
-        if (mOwnScrollY > range) {
-            // HACK: We're repeatedly getting staggered insets here while the IME is
-            // animating away. To work around that we'll wait until things have settled.
-            removeCallbacks(mReclamp);
-            postDelayed(mReclamp, 50);
-        } else if (mForcedScroll != null) {
-            // The scroll was requested before we got the actual inset - in case we need
-            // to scroll up some more do so now.
-            scrollTo(mForcedScroll);
+        if (mAnimatedInsets && !mIsInsetAnimationRunning) {
+            // update bottom inset e.g. after rotation
+            updateBottomInset(insets);
+        }
+        if (!mAnimatedInsets) {
+            int range = getScrollRange();
+            if (mOwnScrollY > range) {
+                // HACK: We're repeatedly getting staggered insets here while the IME is
+                // animating away. To work around that we'll wait until things have settled.
+                removeCallbacks(mReclamp);
+                postDelayed(mReclamp, 50);
+            } else if (mForcedScroll != null) {
+                // The scroll was requested before we got the actual inset - in case we need
+                // to scroll up some more do so now.
+                scrollTo(mForcedScroll);
+            }
         }
         return insets;
     }
@@ -2792,7 +2852,7 @@
         }
         child.setOnHeightChangedListener(null);
         updateScrollStateForRemovedChild(child);
-        boolean animationGenerated = generateRemoveAnimation(child);
+        boolean animationGenerated = container != null && generateRemoveAnimation(child);
         if (animationGenerated) {
             if (!mSwipedOutViews.contains(child) || !isFullySwipedOut(child)) {
                 container.addTransientView(child, 0);
@@ -4439,7 +4499,7 @@
                 expandableView.setFakeShadowIntensity(0.0f, 0.0f, 0, 0);
             } else {
                 float yLocation = previous.getTranslationY() + previous.getActualHeight() -
-                        expandableView.getTranslationY() - previous.getExtraBottomPadding();
+                        expandableView.getTranslationY();
                 expandableView.setFakeShadowIntensity(
                         diff / FakeShadowView.SHADOW_SIBLING_TRESHOLD,
                         previous.getOutlineAlpha(), (int) yLocation,
@@ -5163,7 +5223,7 @@
 
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     public void setIsFullWidth(boolean isFullWidth) {
-        mAmbientState.setPanelFullWidth(isFullWidth);
+        mAmbientState.setSmallScreen(isFullWidth);
     }
 
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
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 14b0763..906b959 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
@@ -70,7 +70,6 @@
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.shade.ShadeController;
-import com.android.systemui.shade.transition.ShadeTransitionController;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
@@ -171,7 +170,6 @@
     private final CentralSurfaces mCentralSurfaces;
     private final SectionHeaderController mSilentHeaderController;
     private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
-    private final ShadeTransitionController mShadeTransitionController;
     private final InteractionJankMonitor mJankMonitor;
     private final NotificationStackSizeCalculator mNotificationStackSizeCalculator;
     private final StackStateLogger mStackStateLogger;
@@ -662,7 +660,6 @@
             NotifPipelineFlags notifPipelineFlags,
             NotifCollection notifCollection,
             LockscreenShadeTransitionController lockscreenShadeTransitionController,
-            ShadeTransitionController shadeTransitionController,
             UiEventLogger uiEventLogger,
             NotificationRemoteInputManager remoteInputManager,
             VisibilityLocationProviderDelegator visibilityLocationProviderDelegator,
@@ -694,7 +691,6 @@
         mMetricsLogger = metricsLogger;
         mDumpManager = dumpManager;
         mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
-        mShadeTransitionController = shadeTransitionController;
         mFalsingCollector = falsingCollector;
         mFalsingManager = falsingManager;
         mResources = resources;
@@ -777,7 +773,6 @@
         mScrimController.setScrimBehindChangeRunnable(mView::updateBackgroundDimming);
 
         mLockscreenShadeTransitionController.setStackScroller(this);
-        mShadeTransitionController.setNotificationStackScrollLayoutController(this);
 
         mLockscreenUserManager.addUserChangedListener(mLockscreenUserChangeListener);
 
@@ -832,18 +827,16 @@
 
     private boolean isInVisibleLocation(NotificationEntry entry) {
         ExpandableNotificationRow row = entry.getRow();
-        ExpandableViewState childViewState = row.getViewState();
-
-        if (childViewState == null) {
+        if (row == null) {
             return false;
         }
+
+        ExpandableViewState childViewState = row.getViewState();
         if ((childViewState.location & ExpandableViewState.VISIBLE_LOCATIONS) == 0) {
             return false;
         }
-        if (row.getVisibility() != View.VISIBLE) {
-            return false;
-        }
-        return true;
+
+        return row.getVisibility() == View.VISIBLE;
     }
 
     public boolean isViewAffectedBySwipe(ExpandableView expandableView) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index a425792..5516ede 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -29,6 +29,9 @@
 import com.android.keyguard.BouncerPanelExpansionCalculator;
 import com.android.systemui.R;
 import com.android.systemui.animation.ShadeInterpolation;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
+import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
 import com.android.systemui.statusbar.EmptyShadeView;
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.notification.LegacySourceType;
@@ -135,7 +138,6 @@
                                   AmbientState ambientState) {
         for (ExpandableView view : algorithmState.visibleChildren) {
             final ViewState viewState = view.getViewState();
-
             final boolean isHunGoingToShade = ambientState.isShadeExpanded()
                     && view == ambientState.getTrackedHeadsUpRow();
 
@@ -148,9 +150,14 @@
             } else if (ambientState.isExpansionChanging()) {
                 // Adjust alpha for shade open & close.
                 float expansion = ambientState.getExpansionFraction();
-                viewState.setAlpha(ambientState.isBouncerInTransit()
-                        ? BouncerPanelExpansionCalculator.aboutToShowBouncerProgress(expansion)
-                        : ShadeInterpolation.getContentAlpha(expansion));
+                if (ambientState.isBouncerInTransit()) {
+                    viewState.setAlpha(
+                            BouncerPanelExpansionCalculator.aboutToShowBouncerProgress(expansion));
+                } else if (view instanceof FooterView) {
+                    viewState.setAlpha(interpolateFooterAlpha(ambientState));
+                } else {
+                    viewState.setAlpha(interpolateNotificationContentAlpha(ambientState));
+                }
             }
 
             // For EmptyShadeView if on keyguard, we need to control the alpha to create
@@ -182,6 +189,28 @@
         }
     }
 
+    private float interpolateFooterAlpha(AmbientState ambientState) {
+        float expansion = ambientState.getExpansionFraction();
+        FeatureFlags flags = ambientState.getFeatureFlags();
+        if (ambientState.isSmallScreen()
+                || !flags.isEnabled(Flags.LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION)) {
+            return ShadeInterpolation.getContentAlpha(expansion);
+        }
+        LargeScreenShadeInterpolator interpolator = ambientState.getLargeScreenShadeInterpolator();
+        return interpolator.getNotificationFooterAlpha(expansion);
+    }
+
+    private float interpolateNotificationContentAlpha(AmbientState ambientState) {
+        float expansion = ambientState.getExpansionFraction();
+        FeatureFlags flags = ambientState.getFeatureFlags();
+        if (ambientState.isSmallScreen()
+                || !flags.isEnabled(Flags.LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION)) {
+            return ShadeInterpolation.getContentAlpha(expansion);
+        }
+        LargeScreenShadeInterpolator interpolator = ambientState.getLargeScreenShadeInterpolator();
+        return interpolator.getNotificationContentAlpha(expansion);
+    }
+
     /**
      * How expanded or collapsed notifications are when pulling down the shade.
      *
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 993c4e2..573347c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -398,6 +398,9 @@
             boolean isStrongBiometric) {
         Trace.beginSection("BiometricUnlockController#onBiometricAuthenticated");
         if (mUpdateMonitor.isGoingToSleep()) {
+            mLogger.deferringAuthenticationDueToSleep(userId,
+                    biometricSourceType,
+                    mPendingAuthenticated != null);
             mPendingAuthenticated = new PendingAuthenticated(userId, biometricSourceType,
                     isStrongBiometric);
             Trace.endSection();
@@ -813,6 +816,7 @@
                 public void onFinishedGoingToSleep() {
                     Trace.beginSection("BiometricUnlockController#onFinishedGoingToSleep");
                     if (mPendingAuthenticated != null) {
+                        mLogger.finishedGoingToSleepWithPendingAuth();
                         PendingAuthenticated pendingAuthenticated = mPendingAuthenticated;
                         // Post this to make sure it's executed after the device is fully locked.
                         mHandler.post(() -> onBiometricAuthenticated(pendingAuthenticated.userId,
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 b5d51ce..5131772 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -605,7 +605,6 @@
 
     private Runnable mLaunchTransitionEndRunnable;
     private Runnable mLaunchTransitionCancelRunnable;
-    private boolean mLaunchingAffordance;
     private boolean mLaunchCameraWhenFinishedWaking;
     private boolean mLaunchCameraOnFinishedGoingToSleep;
     private boolean mLaunchEmergencyActionWhenFinishedWaking;
@@ -3571,7 +3570,8 @@
         boolean goingToSleepWithoutAnimation = isGoingToSleep()
                 && !mDozeParameters.shouldControlScreenOff();
         boolean disabled = (!mDeviceInteractive && !mDozeServiceHost.isPulsing())
-                || goingToSleepWithoutAnimation;
+                || goingToSleepWithoutAnimation
+                || mDeviceProvisionedController.isFrpActive();
         mNotificationPanelViewController.setTouchAndAnimationDisabled(disabled);
         mNotificationIconAreaController.setAnimationsEnabled(!disabled);
     }
@@ -3743,12 +3743,10 @@
 
         mScrimController.setExpansionAffectsAlpha(!unlocking);
 
-        boolean launchingAffordanceWithPreview = mLaunchingAffordance;
-        mScrimController.setLaunchingAffordanceWithPreview(launchingAffordanceWithPreview);
-
         if (mAlternateBouncerInteractor.isVisibleState()) {
-            if (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED
-                    || mTransitionToFullShadeProgress > 0f) {
+            if ((!isOccluded() || isPanelExpanded())
+                    && (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED
+                    || mTransitionToFullShadeProgress > 0f)) {
                 mScrimController.transitionTo(ScrimState.AUTH_SCRIMMED_SHADE);
             } else {
                 mScrimController.transitionTo(ScrimState.AUTH_SCRIMMED);
@@ -3763,9 +3761,6 @@
             ScrimState state = mStatusBarKeyguardViewManager.primaryBouncerNeedsScrimming()
                     ? ScrimState.BOUNCER_SCRIMMED : ScrimState.BOUNCER;
             mScrimController.transitionTo(state);
-        } else if (launchingAffordanceWithPreview) {
-            // We want to avoid animating when launching with a preview.
-            mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
         } else if (mBrightnessMirrorVisible) {
             mScrimController.transitionTo(ScrimState.BRIGHTNESS_MIRROR);
         } else if (mState == StatusBarState.SHADE_LOCKED) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
index c72eb05..39b5b5a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
@@ -40,6 +40,7 @@
 import com.android.systemui.statusbar.connectivity.ui.MobileContextProvider;
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger;
 import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernStatusBarMobileView;
 import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel;
 import com.android.systemui.statusbar.pipeline.wifi.ui.view.ModernStatusBarWifiView;
@@ -288,10 +289,14 @@
      * @param mobileContext possibly mcc/mnc overridden mobile context
      * @param subId the subscriptionId for this mobile view
      */
-    public void addModernMobileView(Context mobileContext, int subId) {
+    public void addModernMobileView(
+            Context mobileContext,
+            MobileViewLogger mobileViewLogger,
+            int subId) {
         Log.d(TAG, "addModernMobileView (subId=" + subId + ")");
         ModernStatusBarMobileView view = ModernStatusBarMobileView.constructAndBind(
                 mobileContext,
+                mobileViewLogger,
                 "mobile",
                 mMobileIconsViewModel.viewModelForSub(subId, mLocation)
         );
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index b88531e..ae715b3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -429,7 +429,6 @@
         }
 
         dispatchAlwaysOnEvent();
-        mScreenOffAnimationController.onAlwaysOnChanged(getAlwaysOn());
     }
 
     @Override
@@ -469,6 +468,7 @@
         for (Callback callback : mCallbacks) {
             callback.onAlwaysOnChange();
         }
+        mScreenOffAnimationController.onAlwaysOnChanged(getAlwaysOn());
     }
 
     private boolean getPostureSpecificBool(
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 b1553b0..9d30cb4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
@@ -76,6 +76,7 @@
         if (mLastAnimator != null) {
             mLastAnimator.cancel();
         }
+        mMessage = "";
         setText("");
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index 753032c..3268032 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -59,7 +59,7 @@
 import com.android.systemui.statusbar.notification.stack.AnimationProperties;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
 import com.android.systemui.statusbar.phone.fragment.StatusBarIconBlocklistKt;
-import com.android.systemui.statusbar.phone.fragment.StatusBarSystemEventAnimator;
+import com.android.systemui.statusbar.phone.fragment.StatusBarSystemEventDefaultAnimator;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -75,6 +75,8 @@
 
 import javax.inject.Inject;
 
+import kotlin.Unit;
+
 /** View Controller for {@link com.android.systemui.statusbar.phone.KeyguardStatusBarView}. */
 public class KeyguardStatusBarViewController extends ViewController<KeyguardStatusBarView> {
     private static final String TAG = "KeyguardStatusBarViewController";
@@ -123,7 +125,8 @@
                 public void onDensityOrFontScaleChanged() {
                     mView.loadDimens();
                     // The animator is dependent on resources for offsets
-                    mSystemEventAnimator = new StatusBarSystemEventAnimator(mView, getResources());
+                    mSystemEventAnimator =
+                            getSystemEventAnimator(mSystemEventAnimator.isAnimationRunning());
                 }
 
                 @Override
@@ -248,7 +251,8 @@
     private int mStatusBarState;
     private boolean mDozing;
     private boolean mShowingKeyguardHeadsUp;
-    private StatusBarSystemEventAnimator mSystemEventAnimator;
+    private StatusBarSystemEventDefaultAnimator mSystemEventAnimator;
+    private float mSystemEventAnimatorAlpha = 1;
 
     /**
      * The alpha value to be set on the View. If -1, this value is to be ignored.
@@ -324,7 +328,7 @@
 
         mView.setKeyguardUserAvatarEnabled(
                 !mStatusBarUserChipViewModel.getChipEnabled());
-        mSystemEventAnimator = new StatusBarSystemEventAnimator(mView, r);
+        mSystemEventAnimator = getSystemEventAnimator(/* isAnimationRunning */ false);
 
         mDisableStateTracker = new DisableStateTracker(
                 /* mask1= */ DISABLE_SYSTEM_INFO,
@@ -480,6 +484,10 @@
                     * (1.0f - mKeyguardHeadsUpShowingAmount);
         }
 
+        if (mSystemEventAnimator.isAnimationRunning()) {
+            newAlpha = Math.min(newAlpha, mSystemEventAnimatorAlpha);
+        }
+
         boolean hideForBypass =
                 mFirstBypassAttempt && mKeyguardUpdateMonitor.shouldListenForFace()
                         || mDelayShowingKeyguardStatusBar;
@@ -488,7 +496,7 @@
                         && !mDozing
                         && !hideForBypass
                         && !mDisableStateTracker.isDisabled()
-                ? View.VISIBLE : View.INVISIBLE;
+                        ? View.VISIBLE : View.INVISIBLE;
 
         updateViewState(newAlpha, newVisibility);
     }
@@ -614,4 +622,15 @@
             updateBlockedIcons();
         }
     };
+
+    private StatusBarSystemEventDefaultAnimator getSystemEventAnimator(boolean isAnimationRunning) {
+        return new StatusBarSystemEventDefaultAnimator(getResources(), (alpha) -> {
+            mSystemEventAnimatorAlpha = alpha;
+            updateViewState();
+            return Unit.INSTANCE;
+        }, (translationX) -> {
+            mView.setTranslationX(translationX);
+            return Unit.INSTANCE;
+        }, isAnimationRunning);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 28bc64d..d546a84 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -35,6 +35,7 @@
 
 import com.android.internal.policy.SystemBarUtils;
 import com.android.systemui.Dependency;
+import com.android.systemui.Gefingerpoken;
 import com.android.systemui.R;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
@@ -60,7 +61,7 @@
     private Rect mDisplaySize;
     private int mStatusBarHeight;
     @Nullable
-    private TouchEventHandler mTouchEventHandler;
+    private Gefingerpoken mTouchEventHandler;
 
     /**
      * Draw this many pixels into the left/right side of the cutout to optimally use the space
@@ -72,7 +73,7 @@
         mContentInsetsProvider = Dependency.get(StatusBarContentInsetsProvider.class);
     }
 
-    void setTouchEventHandler(TouchEventHandler handler) {
+    void setTouchEventHandler(Gefingerpoken handler) {
         mTouchEventHandler = handler;
     }
 
@@ -185,7 +186,7 @@
             );
             return true;
         }
-        return mTouchEventHandler.handleTouchEvent(event);
+        return mTouchEventHandler.onTouchEvent(event);
     }
 
     @Override
@@ -267,28 +268,4 @@
                 insets.second,
                 getPaddingBottom());
     }
-
-    /**
-     * A handler responsible for all touch event handling on the status bar.
-     *
-     * Touches that occur on the status bar view may have ramifications for the notification
-     * panel (e.g. a touch that pulls down the shade could start on the status bar), so this
-     * interface provides a way to notify the panel controller when these touches occur.
-     *
-     * The handler will be notified each time {@link PhoneStatusBarView#onTouchEvent} and
-     * {@link PhoneStatusBarView#onInterceptTouchEvent} are called.
-     **/
-    public interface TouchEventHandler {
-        /** Called each time {@link PhoneStatusBarView#onInterceptTouchEvent} is called. */
-        void onInterceptTouchEvent(MotionEvent event);
-
-        /**
-         * Called each time {@link PhoneStatusBarView#onTouchEvent} is called.
-         *
-         * Should return true if the touch was handled by this handler and false otherwise. The
-         * return value from the handler will be returned from
-         * {@link PhoneStatusBarView#onTouchEvent}.
-         */
-        boolean handleTouchEvent(MotionEvent event);
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
index 11bc490..62d302f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
@@ -24,11 +24,13 @@
 import android.view.View
 import android.view.ViewGroup
 import android.view.ViewTreeObserver
+import com.android.systemui.Gefingerpoken
 import com.android.systemui.R
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
 import com.android.systemui.shade.ShadeController
 import com.android.systemui.shade.ShadeLogger
 import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator
-import com.android.systemui.statusbar.phone.PhoneStatusBarView.TouchEventHandler
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.unfold.SysUIUnfoldComponent
 import com.android.systemui.unfold.UNFOLD_STATUS_BAR
@@ -131,7 +133,7 @@
     }
 
     /** Called when a touch event occurred on {@link PhoneStatusBarView}. */
-    fun onTouchEvent(event: MotionEvent) {
+    fun onTouch(event: MotionEvent) {
         if (centralSurfaces.statusBarWindowState == WINDOW_STATE_SHOWING) {
             val upOrCancel =
                     event.action == MotionEvent.ACTION_UP ||
@@ -141,13 +143,14 @@
         }
     }
 
-    inner class PhoneStatusBarViewTouchHandler : TouchEventHandler {
-        override fun onInterceptTouchEvent(event: MotionEvent) {
-            onTouchEvent(event)
+    inner class PhoneStatusBarViewTouchHandler : Gefingerpoken {
+        override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
+            onTouch(event)
+            return false
         }
 
-        override fun handleTouchEvent(event: MotionEvent): Boolean {
-            onTouchEvent(event)
+        override fun onTouchEvent(event: MotionEvent): Boolean {
+            onTouch(event)
 
             // If panels aren't enabled, ignore the gesture and don't pass it down to the
             // panel view.
@@ -174,7 +177,7 @@
                     return true
                 }
             }
-            return centralSurfaces.notificationPanelViewController.sendTouchEventToView(event)
+            return centralSurfaces.notificationPanelViewController.handleExternalTouch(event)
         }
     }
 
@@ -214,6 +217,7 @@
         private val unfoldComponent: Optional<SysUIUnfoldComponent>,
         @Named(UNFOLD_STATUS_BAR)
         private val progressProvider: Optional<ScopedUnfoldTransitionProgressProvider>,
+        private val featureFlags: FeatureFlags,
         private val userChipViewModel: StatusBarUserChipViewModel,
         private val centralSurfaces: CentralSurfaces,
         private val shadeController: ShadeController,
@@ -223,17 +227,25 @@
     ) {
         fun create(
             view: PhoneStatusBarView
-        ) =
-            PhoneStatusBarViewController(
-                view,
-                progressProvider.getOrNull(),
-                centralSurfaces,
-                shadeController,
-                shadeLogger,
-                unfoldComponent.getOrNull()?.getStatusBarMoveFromCenterAnimationController(),
-                userChipViewModel,
-                viewUtil,
-                configurationController
+        ): PhoneStatusBarViewController {
+            val statusBarMoveFromCenterAnimationController =
+                    if (featureFlags.isEnabled(Flags.ENABLE_UNFOLD_STATUS_BAR_ANIMATIONS)) {
+                        unfoldComponent.getOrNull()?.getStatusBarMoveFromCenterAnimationController()
+                    } else {
+                        null
+                    }
+
+            return PhoneStatusBarViewController(
+                    view,
+                    progressProvider.getOrNull(),
+                    centralSurfaces,
+                    shadeController,
+                    shadeLogger,
+                    statusBarMoveFromCenterAnimationController,
+                    userChipViewModel,
+                    viewUtil,
+                    configurationController
             )
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index c01137a..00f26be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -54,14 +54,18 @@
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dock.DockManager;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
 import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants;
+import com.android.systemui.keyguard.shared.model.ScrimAlpha;
 import com.android.systemui.keyguard.shared.model.TransitionState;
 import com.android.systemui.keyguard.shared.model.TransitionStep;
 import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;
 import com.android.systemui.scrim.ScrimView;
 import com.android.systemui.shade.NotificationPanelViewController;
+import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
 import com.android.systemui.statusbar.notification.stack.ViewState;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -243,6 +247,8 @@
     private boolean mWallpaperVisibilityTimedOut;
     private int mScrimsVisibility;
     private final TriConsumer<ScrimState, Float, GradientColors> mScrimStateListener;
+    private final LargeScreenShadeInterpolator mLargeScreenShadeInterpolator;
+    private final FeatureFlags mFeatureFlags;
     private Consumer<Integer> mScrimVisibleListener;
     private boolean mBlankScreen;
     private boolean mScreenBlankingCallbackCalled;
@@ -261,25 +267,21 @@
 
     private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
     private CoroutineDispatcher mMainDispatcher;
-    private boolean mIsBouncerToGoneTransitionStarted = false;
     private boolean mIsBouncerToGoneTransitionRunning = false;
     private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel;
-    private final Consumer<Float> mScrimAlphaConsumer =
-            (Float alpha) -> {
-                mScrimInFront.setViewAlpha(0f);
-                mNotificationsScrim.setViewAlpha(0f);
-                mScrimBehind.setViewAlpha(alpha);
+    private final Consumer<ScrimAlpha> mScrimAlphaConsumer =
+            (ScrimAlpha alphas) -> {
+                mInFrontAlpha = alphas.getFrontAlpha();
+                mScrimInFront.setViewAlpha(mInFrontAlpha);
+
+                mNotificationsAlpha = alphas.getNotificationsAlpha();
+                mNotificationsScrim.setViewAlpha(mNotificationsAlpha);
+
+                mBehindAlpha = alphas.getBehindAlpha();
+                mScrimBehind.setViewAlpha(mBehindAlpha);
             };
-    final Consumer<TransitionStep> mPrimaryBouncerToGoneTransition =
-            (TransitionStep step) -> {
-                mIsBouncerToGoneTransitionRunning =
-                    step.getTransitionState() == TransitionState.RUNNING;
-                mIsBouncerToGoneTransitionStarted =
-                    step.getTransitionState() == TransitionState.STARTED;
-                if (mIsBouncerToGoneTransitionStarted) {
-                    transitionTo(ScrimState.UNLOCKED);
-                }
-            };
+
+    Consumer<TransitionStep> mPrimaryBouncerToGoneTransition;
 
     @Inject
     public ScrimController(
@@ -298,8 +300,12 @@
             StatusBarKeyguardViewManager statusBarKeyguardViewManager,
             PrimaryBouncerToGoneTransitionViewModel primaryBouncerToGoneTransitionViewModel,
             KeyguardTransitionInteractor keyguardTransitionInteractor,
-            @Main CoroutineDispatcher mainDispatcher) {
+            @Main CoroutineDispatcher mainDispatcher,
+            LargeScreenShadeInterpolator largeScreenShadeInterpolator,
+            FeatureFlags featureFlags) {
         mScrimStateListener = lightBarController::setScrimState;
+        mLargeScreenShadeInterpolator = largeScreenShadeInterpolator;
+        mFeatureFlags = featureFlags;
         mDefaultScrimAlpha = BUSY_SCRIM_ALPHA;
 
         mKeyguardStateController = keyguardStateController;
@@ -380,6 +386,28 @@
             state.prepare(state);
         }
 
+        // Directly control transition to UNLOCKED scrim state from PRIMARY_BOUNCER, and make sure
+        // to report back that keyguard has faded away. This fixes cases where the scrim state was
+        // rapidly switching on unlock, due to shifts in state in CentralSurfacesImpl
+        mPrimaryBouncerToGoneTransition =
+                (TransitionStep step) -> {
+                    TransitionState state = step.getTransitionState();
+
+                    mIsBouncerToGoneTransitionRunning = state == TransitionState.RUNNING;
+
+                    if (state == TransitionState.STARTED) {
+                        setExpansionAffectsAlpha(false);
+                        transitionTo(ScrimState.UNLOCKED);
+                    }
+
+                    if (state == TransitionState.FINISHED || state == TransitionState.CANCELED) {
+                        setExpansionAffectsAlpha(true);
+                        if (mKeyguardStateController.isKeyguardFadingAway()) {
+                            mStatusBarKeyguardViewManager.onKeyguardFadedAway();
+                        }
+                    }
+                };
+
         collectFlow(behindScrim, mKeyguardTransitionInteractor.getPrimaryBouncerToGoneTransition(),
                 mPrimaryBouncerToGoneTransition, mMainDispatcher);
         collectFlow(behindScrim, mPrimaryBouncerToGoneTransitionViewModel.getScrimAlpha(),
@@ -768,6 +796,11 @@
 
     public void setOccludeAnimationPlaying(boolean occludeAnimationPlaying) {
         mOccludeAnimationPlaying = occludeAnimationPlaying;
+
+        for (ScrimState state : ScrimState.values()) {
+            state.setOccludeAnimationPlaying(occludeAnimationPlaying);
+        }
+
         applyAndDispatchState();
     }
 
@@ -812,29 +845,32 @@
         if (mState == ScrimState.UNLOCKED || mState == ScrimState.DREAMING) {
             final boolean occluding =
                     mOccludeAnimationPlaying || mState.mLaunchingAffordanceWithPreview;
-
             // Darken scrim as it's pulled down while unlocked. If we're unlocked but playing the
             // screen off/occlusion animations, ignore expansion changes while those animations
             // play.
             if (!mScreenOffAnimationController.shouldExpandNotifications()
                     && !mAnimatingPanelExpansionOnUnlock
                     && !occluding) {
-                if (mClipsQsScrim) {
+                if (mTransparentScrimBackground) {
+                    mBehindAlpha = 0;
+                    mNotificationsAlpha = 0;
+                } else if (mClipsQsScrim) {
                     float behindFraction = getInterpolatedFraction();
                     behindFraction = (float) Math.pow(behindFraction, 0.8f);
-                    mBehindAlpha = mTransparentScrimBackground ? 0 : 1;
-                    mNotificationsAlpha =
-                            mTransparentScrimBackground ? 0 : behindFraction * mDefaultScrimAlpha;
+                    mBehindAlpha = 1;
+                    mNotificationsAlpha = behindFraction * mDefaultScrimAlpha;
                 } else {
-                    if (mTransparentScrimBackground) {
-                        mBehindAlpha = 0;
-                        mNotificationsAlpha = 0;
+                    if (mFeatureFlags.isEnabled(Flags.LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION)) {
+                        mBehindAlpha = mLargeScreenShadeInterpolator.getBehindScrimAlpha(
+                                mPanelExpansionFraction * mDefaultScrimAlpha);
+                        mNotificationsAlpha =
+                                mLargeScreenShadeInterpolator.getNotificationScrimAlpha(
+                                        mPanelExpansionFraction);
                     } else {
+                        // Behind scrim will finish fading in at 30% expansion.
                         float behindFraction = MathUtils
                                 .constrainedMap(0f, 1f, 0f, 0.3f, mPanelExpansionFraction);
-                        if (!mIsBouncerToGoneTransitionStarted) {
-                            mBehindAlpha = behindFraction * mDefaultScrimAlpha;
-                        }
+                        mBehindAlpha = behindFraction * mDefaultScrimAlpha;
                         // Delay fade-in of notification scrim a bit further, to coincide with the
                         // behind scrim finishing fading in.
                         // Also to coincide with the view starting to fade in, otherwise the empty
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index 0e9d3ce..7b20283 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -243,7 +243,12 @@
                     : CentralSurfaces.FADE_KEYGUARD_DURATION;
 
             boolean fromAod = previousState == AOD || previousState == PULSING;
-            mAnimateChange = !mLaunchingAffordanceWithPreview && !fromAod;
+            // If launch/occlude animations were playing, they already animated the scrim
+            // alpha to 0f as part of the animation. If we animate it now, we'll set it back
+            // to 1f and animate it back to 0f, causing an unwanted scrim flash.
+            mAnimateChange = !mLaunchingAffordanceWithPreview
+                    && !mOccludeAnimationPlaying
+                    && !fromAod;
 
             mFrontTint = Color.TRANSPARENT;
             mBehindTint = Color.BLACK;
@@ -308,6 +313,7 @@
     boolean mWallpaperSupportsAmbientMode;
     boolean mHasBackdrop;
     boolean mLaunchingAffordanceWithPreview;
+    boolean mOccludeAnimationPlaying;
     boolean mWakeLockScreenSensorActive;
     boolean mKeyguardFadingAway;
     long mKeyguardFadingAwayDuration;
@@ -411,6 +417,10 @@
         mLaunchingAffordanceWithPreview = launchingAffordanceWithPreview;
     }
 
+    public void setOccludeAnimationPlaying(boolean occludeAnimationPlaying) {
+        mOccludeAnimationPlaying = occludeAnimationPlaying;
+    }
+
     public boolean isLowPowerState() {
         return false;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 11863627..30d2295 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -81,28 +81,22 @@
     void refreshIconGroup(IconManager iconManager);
 
     /**
-     * Adds or updates an icon for a given slot for a **tile service icon**.
+     * Adds or updates an icon that comes from an active tile service.
      *
-     * TODO(b/265307726): Merge with {@link #setIcon(String, StatusBarIcon)} or make this method
-     *   much more clearly distinct from that method.
+     * If the icon is null, the icon will be removed.
      */
-    void setExternalIcon(String slot);
+    void setIconFromTile(String slot, @Nullable StatusBarIcon icon);
+
+    /** Removes an icon that had come from an active tile service. */
+    void removeIconForTile(String slot);
 
     /**
      * Adds or updates an icon for the given slot for **internal system icons**.
      *
-     * TODO(b/265307726): Rename to `setInternalIcon`, or merge this appropriately with the
-     * {@link #setIcon(String, StatusBarIcon)} method.
+     * TODO(b/265307726): Re-name this to `setInternalIcon`.
      */
     void setIcon(String slot, int resourceId, CharSequence contentDescription);
 
-    /**
-     * Adds or updates an icon for the given slot for an **externally-provided icon**.
-     *
-     * TODO(b/265307726): Rename to `setExternalIcon` or something similar.
-     */
-    void setIcon(String slot, StatusBarIcon icon);
-
     /** */
     void setWifiIcon(String slot, WifiIconState state);
 
@@ -152,15 +146,10 @@
      */
     void removeIcon(String slot, int tag);
 
-    /** */
-    void removeAllIconsForSlot(String slot);
-
     /**
-     * Removes all the icons for the given slot.
-     *
-     * Only use this for icons that have come from **an external process**.
+     * TODO(b/265307726): Re-name this to `removeAllIconsForInternalSlot`.
      */
-    void removeAllIconsForExternalSlot(String slot);
+    void removeAllIconsForSlot(String slot);
 
     // TODO: See if we can rename this tunable name.
     String ICON_HIDE_LIST = "icon_blacklist";
@@ -569,7 +558,10 @@
             mGroup.addView(view, index, onCreateLayoutParams());
 
             if (mIsInDemoMode) {
-                mDemoStatusIcons.addModernMobileView(mContext, subId);
+                mDemoStatusIcons.addModernMobileView(
+                        mContext,
+                        mMobileIconsViewModel.getLogger(),
+                        subId);
             }
 
             return view;
@@ -601,6 +593,7 @@
             return ModernStatusBarMobileView
                     .constructAndBind(
                             mobileContext,
+                            mMobileIconsViewModel.getLogger(),
                             slot,
                             mMobileIconsViewModel.viewModelForSub(subId, mLocation)
                         );
@@ -614,13 +607,6 @@
             mGroup.removeAllViews();
         }
 
-        protected void onIconExternal(int viewIndex, int height) {
-            ImageView imageView = (ImageView) mGroup.getChildAt(viewIndex);
-            imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
-            imageView.setAdjustViewBounds(true);
-            setHeightAndCenter(imageView, height);
-        }
-
         protected void onDensityOrFontScaleChanged() {
             for (int i = 0; i < mGroup.getChildCount(); i++) {
                 View child = mGroup.getChildAt(i);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
index 0727c5a..3a18423 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
@@ -32,7 +32,6 @@
 
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.systemui.Dumpable;
-import com.android.systemui.R;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.demomode.DemoMode;
 import com.android.systemui.demomode.DemoModeController;
@@ -62,7 +61,7 @@
  */
 @SysUISingleton
 public class StatusBarIconControllerImpl implements Tunable,
-        ConfigurationListener, Dumpable, CommandQueue.Callbacks, StatusBarIconController, DemoMode {
+        ConfigurationListener, Dumpable, StatusBarIconController, DemoMode {
 
     private static final String TAG = "StatusBarIconController";
     // Use this suffix to prevent external icon slot names from unintentionally overriding our
@@ -93,7 +92,7 @@
         mStatusBarPipelineFlags = statusBarPipelineFlags;
 
         configurationController.addCallback(this);
-        commandQueue.addCallback(this);
+        commandQueue.addCallback(mCommandQueueCallbacks);
         tunerService.addTunable(this, ICON_HIDE_LIST);
         demoModeController.addCallback(this);
         dumpManager.registerDumpable(getClass().getSimpleName(), this);
@@ -350,26 +349,35 @@
         }
     }
 
-    @Override
-    public void setExternalIcon(String slot) {
-        String slotName = createExternalSlotName(slot);
-        int viewIndex = mStatusBarIconList.getViewIndex(slotName, 0);
-        int height = mContext.getResources().getDimensionPixelSize(
-                R.dimen.status_bar_icon_drawing_size);
-        mIconGroups.forEach(l -> l.onIconExternal(viewIndex, height));
-    }
-
-    // Override for *both* CommandQueue.Callbacks AND StatusBarIconController.
-    // TODO(b/265307726): Pull out the CommandQueue callbacks into a member variable to
-    //  differentiate between those callback methods and StatusBarIconController methods.
-    @Override
-    public void setIcon(String slot, StatusBarIcon icon) {
-        String slotName = createExternalSlotName(slot);
-        if (icon == null) {
-            removeAllIconsForSlot(slotName);
-            return;
+    private final CommandQueue.Callbacks mCommandQueueCallbacks = new CommandQueue.Callbacks() {
+        @Override
+        public void setIcon(String slot, StatusBarIcon icon) {
+            // Icons that come from CommandQueue are from external services.
+            setExternalIcon(slot, icon);
         }
 
+        @Override
+        public void removeIcon(String slot) {
+            removeAllIconsForExternalSlot(slot);
+        }
+    };
+
+    @Override
+    public void setIconFromTile(String slot, StatusBarIcon icon) {
+        setExternalIcon(slot, icon);
+    }
+
+    @Override
+    public void removeIconForTile(String slot) {
+        removeAllIconsForExternalSlot(slot);
+    }
+
+    private void setExternalIcon(String slot, StatusBarIcon icon) {
+        if (icon == null) {
+            removeAllIconsForExternalSlot(slot);
+            return;
+        }
+        String slotName = createExternalSlotName(slot);
         StatusBarIconHolder holder = StatusBarIconHolder.fromIcon(icon);
         setIcon(slotName, holder);
     }
@@ -417,14 +425,6 @@
         }
     }
 
-    // CommandQueue.Callbacks override
-    // TODO(b/265307726): Pull out the CommandQueue callbacks into a member variable to
-    //  differentiate between those callback methods and StatusBarIconController methods.
-    @Override
-    public void removeIcon(String slot) {
-        removeAllIconsForExternalSlot(slot);
-    }
-
     /** */
     @Override
     public void removeIcon(String slot, int tag) {
@@ -444,8 +444,7 @@
         mIconGroups.forEach(l -> l.onRemoveIcon(viewIndex));
     }
 
-    @Override
-    public void removeAllIconsForExternalSlot(String slotName) {
+    private void removeAllIconsForExternalSlot(String slotName) {
         removeAllIconsForSlot(createExternalSlotName(slotName));
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java
index f6c0da8..833cb93 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java
@@ -79,6 +79,18 @@
     private @IconType int mType = TYPE_ICON;
     private int mTag = 0;
 
+    /** Returns a human-readable string representing the given type. */
+    public static String getTypeString(@IconType int type) {
+        switch(type) {
+            case TYPE_ICON: return "ICON";
+            case TYPE_WIFI: return "WIFI_OLD";
+            case TYPE_MOBILE: return "MOBILE_OLD";
+            case TYPE_MOBILE_NEW: return "MOBILE_NEW";
+            case TYPE_WIFI_NEW: return "WIFI_NEW";
+            default: return "UNKNOWN";
+        }
+    }
+
     private StatusBarIconHolder() {
     }
 
@@ -230,4 +242,11 @@
     public int getTag() {
         return mTag;
     }
+
+    @Override
+    public String toString() {
+        return "StatusBarIconHolder(type=" + getTypeString(mType)
+                + " tag=" + getTag()
+                + " visible=" + isVisible() + ")";
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java
index 8800b05..565481a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java
@@ -27,6 +27,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.stream.Collectors;
 
 /** A class holding the list of all the system icons that could be shown in the status bar. */
 public class StatusBarIconList {
@@ -302,7 +303,7 @@
 
         @Override
         public String toString() {
-            return String.format("(%s) %s", mName, subSlotsString());
+            return String.format("(%s) holder=%s %s", mName, mHolder, subSlotsString());
         }
 
         private String subSlotsString() {
@@ -310,7 +311,10 @@
                 return "";
             }
 
-            return "" + mSubSlots.size() + " subSlots";
+            return "| " + mSubSlots.size() + " subSlots: "
+                    + mSubSlots.stream()
+                    .map(StatusBarIconHolder::toString)
+                    .collect(Collectors.joining("|"));
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 3c32131..71e2e40 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -279,6 +279,7 @@
     private int mLastBiometricMode;
     private boolean mLastScreenOffAnimationPlaying;
     private float mQsExpansion;
+    private boolean mAlternateBouncerReceivedDownTouch = false;
     final Set<KeyguardViewManagerCallback> mCallbacks = new HashSet<>();
     private boolean mIsModernAlternateBouncerEnabled;
     private boolean mIsBackAnimationEnabled;
@@ -405,14 +406,14 @@
     }
 
     /**
-     * Sets a new legacy alternate bouncer. Only used if mdoern alternate bouncer is NOT enable.
+     * Sets a new legacy alternate bouncer. Only used if modern alternate bouncer is NOT enabled.
      */
     public void setLegacyAlternateBouncer(@NonNull LegacyAlternateBouncer alternateBouncerLegacy) {
         if (!mIsModernAlternateBouncerEnabled) {
             if (!Objects.equals(mAlternateBouncerInteractor.getLegacyAlternateBouncer(),
                     alternateBouncerLegacy)) {
                 mAlternateBouncerInteractor.setLegacyAlternateBouncer(alternateBouncerLegacy);
-                hideAlternateBouncer(false);
+                hideAlternateBouncer(true);
             }
         }
 
@@ -640,8 +641,7 @@
      */
     public void showPrimaryBouncer(boolean scrimmed) {
         hideAlternateBouncer(false);
-
-        if (mKeyguardStateController.isShowing()  && !isBouncerShowing()) {
+        if (mKeyguardStateController.isShowing() && !isBouncerShowing()) {
             mPrimaryBouncerInteractor.show(scrimmed);
         }
         updateStates();
@@ -733,15 +733,17 @@
             } else {
                 showBouncerOrKeyguard(hideBouncerWhenShowing);
             }
-            hideAlternateBouncer(false);
+            if (hideBouncerWhenShowing) {
+                hideAlternateBouncer(true);
+            }
             mKeyguardUpdateManager.sendKeyguardReset();
             updateStates();
         }
     }
 
     @Override
-    public void hideAlternateBouncer(boolean forceUpdateScrim) {
-        updateAlternateBouncerShowing(mAlternateBouncerInteractor.hide() || forceUpdateScrim);
+    public void hideAlternateBouncer(boolean updateScrim) {
+        updateAlternateBouncerShowing(mAlternateBouncerInteractor.hide() && updateScrim);
     }
 
     private void updateAlternateBouncerShowing(boolean updateScrim) {
@@ -1388,6 +1390,7 @@
         pw.println("  mPendingWakeupAction: " + mPendingWakeupAction);
         pw.println("  isBouncerShowing(): " + isBouncerShowing());
         pw.println("  bouncerIsOrWillBeShowing(): " + primaryBouncerIsOrWillBeShowing());
+        pw.println("  mAlternateBouncerReceivedDownTouch: " + mAlternateBouncerReceivedDownTouch);
         pw.println("  Registered KeyguardViewManagerCallbacks:");
         for (KeyguardViewManagerCallback callback : mCallbacks) {
             pw.println("      " + callback);
@@ -1446,16 +1449,29 @@
      * For any touches on the NPVC, show the primary bouncer if the alternate bouncer is currently
      * showing.
      */
-    public void onTouch(MotionEvent event) {
-        if (mAlternateBouncerInteractor.isVisibleState()
-                && mAlternateBouncerInteractor.hasAlternateBouncerShownWithMinTime()) {
-            showPrimaryBouncer(true);
+    public boolean onTouch(MotionEvent event) {
+        boolean handledTouch = false;
+        if (mAlternateBouncerInteractor.isVisibleState()) {
+            final boolean downThenUp = event.getActionMasked() == MotionEvent.ACTION_UP
+                    && mAlternateBouncerReceivedDownTouch;
+            final boolean outsideTouch = event.getActionMasked() == MotionEvent.ACTION_OUTSIDE;
+            if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+                mAlternateBouncerReceivedDownTouch = true;
+            } else if ((downThenUp || outsideTouch)
+                    && mAlternateBouncerInteractor.hasAlternateBouncerShownWithMinTime()) {
+                showPrimaryBouncer(true);
+            }
+            handledTouch = true;
+        } else {
+            mAlternateBouncerReceivedDownTouch = false;
         }
 
         // Forward NPVC touches to callbacks in case they want to respond to touches
         for (KeyguardViewManagerCallback callback: mCallbacks) {
             callback.onTouch(event);
         }
+
+        return handledTouch;
     }
 
     /** Update keyguard position based on a tapped X coordinate. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationController.kt
index 79c0984..d30d0e25 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationController.kt
@@ -22,6 +22,7 @@
 import com.android.systemui.statusbar.phone.PhoneStatusBarViewController.StatusBarViewsCenterProvider
 import com.android.systemui.unfold.SysUIUnfoldScope
 import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
+import com.android.systemui.unfold.util.CurrentActivityTypeProvider
 import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider
 import javax.inject.Inject
 import kotlin.math.max
@@ -29,9 +30,13 @@
 @SysUIUnfoldScope
 class StatusBarMoveFromCenterAnimationController @Inject constructor(
     private val progressProvider: ScopedUnfoldTransitionProgressProvider,
+    private val currentActivityTypeProvider: CurrentActivityTypeProvider,
     windowManager: WindowManager
 ) {
 
+    // Whether we're on home activity. Updated only when the animation starts.
+    private var isOnHomeActivity: Boolean? = null
+
     private val transitionListener = TransitionListener()
     private val moveFromCenterAnimator = UnfoldMoveFromCenterAnimator(
         windowManager,
@@ -60,6 +65,10 @@
     }
 
     private inner class TransitionListener : TransitionProgressListener {
+        override fun onTransitionStarted() {
+            isOnHomeActivity = currentActivityTypeProvider.isHomeActivity
+        }
+
         override fun onTransitionProgress(progress: Float) {
             moveFromCenterAnimator.onTransitionProgress(progress)
         }
@@ -68,11 +77,23 @@
             // Reset translations when transition is stopped/cancelled
             // (e.g. the transition could be cancelled mid-way when rotating the screen)
             moveFromCenterAnimator.onTransitionProgress(1f)
+            isOnHomeActivity = null
         }
     }
 
-    private class StatusBarIconsAlphaProvider : AlphaProvider {
+
+    /**
+     * In certain cases, an alpha is applied based on the progress.
+     *
+     * This mainly happens to hide the statusbar during the unfold animation while on apps, as the
+     * bounds of the app "collapse" to the center, but the statusbar doesn't.
+     * While on launcher, this alpha is not applied.
+     */
+    private inner class StatusBarIconsAlphaProvider : AlphaProvider {
         override fun getAlpha(progress: Float): Float {
+            if (isOnHomeActivity == true) {
+                return 1.0f
+            }
             return max(
                 0f,
                 (progress - ICONS_START_APPEARING_PROGRESS) / (1 - ICONS_START_APPEARING_PROGRESS)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 078a00d..189f2e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -27,6 +27,7 @@
 import android.app.TaskStackBuilder;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ResolveInfo;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Handler;
@@ -45,6 +46,7 @@
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.statusbar.NotificationVisibility;
+import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.systemui.ActivityIntentHelper;
 import com.android.systemui.EventLogTags;
@@ -74,6 +76,7 @@
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.wmshell.BubblesManager;
 
+import java.util.List;
 import java.util.Optional;
 import java.util.concurrent.Executor;
 
@@ -81,6 +84,7 @@
 
 import dagger.Lazy;
 
+
 /**
  * Status bar implementation of {@link NotificationActivityStarter}.
  */
@@ -572,16 +576,29 @@
         });
 
         // not immersive & a fullscreen alert should be shown
-        final PendingIntent fullscreenIntent =
+        final PendingIntent fullScreenIntent =
                 entry.getSbn().getNotification().fullScreenIntent;
-        mLogger.logSendingFullScreenIntent(entry, fullscreenIntent);
+        mLogger.logSendingFullScreenIntent(entry, fullScreenIntent);
         try {
             EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION,
                     entry.getKey());
             mCentralSurfaces.wakeUpForFullScreenIntent();
-            fullscreenIntent.send();
+            fullScreenIntent.send();
             entry.notifyFullScreenIntentLaunched();
             mMetricsLogger.count("note_fullscreen", 1);
+
+            String activityName;
+            List<ResolveInfo> resolveInfos = fullScreenIntent.queryIntentComponents(0);
+            if (resolveInfos.size() > 0 && resolveInfos.get(0) != null
+                    && resolveInfos.get(0).activityInfo != null
+                    && resolveInfos.get(0).activityInfo.name != null) {
+                activityName = resolveInfos.get(0).activityInfo.name;
+            } else {
+                activityName = "";
+            }
+            FrameworkStatsLog.write(FrameworkStatsLog.FULL_SCREEN_INTENT_LAUNCHED,
+                    fullScreenIntent.getCreatorUid(),
+                    activityName);
         } catch (PendingIntent.CanceledException e) {
             // ignore
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index 2fe7145..4a15000 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -453,9 +453,6 @@
     protected int adjustDisableFlags(int state) {
         boolean headsUpVisible =
                 mStatusBarFragmentComponent.getHeadsUpAppearanceController().shouldBeVisible();
-        if (headsUpVisible) {
-            state |= DISABLE_CLOCK;
-        }
 
         if (!mKeyguardStateController.isLaunchTransitionFadingAway()
                 && !mKeyguardStateController.isKeyguardFadingAway()
@@ -473,6 +470,13 @@
             state |= DISABLE_ONGOING_CALL_CHIP;
         }
 
+        if (headsUpVisible) {
+            // Disable everything on the left side of the status bar, since the app name for the
+            // heads up notification appears there instead.
+            state |= DISABLE_CLOCK;
+            state |= DISABLE_ONGOING_CALL_CHIP;
+        }
+
         return state;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt
index c04ea36..5903fa3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt
@@ -26,19 +26,39 @@
 import com.android.systemui.statusbar.events.STATUS_BAR_X_MOVE_OUT
 import com.android.systemui.statusbar.events.SystemStatusAnimationCallback
 import com.android.systemui.util.animation.AnimationUtil.Companion.frames
+import com.android.systemui.util.doOnCancel
+import com.android.systemui.util.doOnEnd
+
+/**
+ * An implementation of [StatusBarSystemEventDefaultAnimator], applying the onAlphaChanged and
+ * onTranslationXChanged callbacks directly to the provided animatedView.
+ */
+class StatusBarSystemEventAnimator @JvmOverloads constructor(
+        val animatedView: View,
+        resources: Resources,
+        isAnimationRunning: Boolean = false
+) : StatusBarSystemEventDefaultAnimator(
+        resources = resources,
+        onAlphaChanged = animatedView::setAlpha,
+        onTranslationXChanged = animatedView::setTranslationX,
+        isAnimationRunning = isAnimationRunning
+)
 
 /**
  * Tied directly to [SystemStatusAnimationScheduler]. Any StatusBar-like thing (keyguard, collapsed
- * status bar fragment), can just feed this an animatable view to get the default system status
- * animation.
+ * status bar fragment), can use this Animator to get the default system status animation. It simply
+ * needs to implement the onAlphaChanged and onTranslationXChanged callbacks.
  *
  * This animator relies on resources, and should be recreated whenever resources are updated. While
  * this class could be used directly as the animation callback, it's probably best to forward calls
  * to it so that it can be recreated at any moment without needing to remove/add callback.
  */
-class StatusBarSystemEventAnimator(
-    val animatedView: View,
-    resources: Resources
+
+open class StatusBarSystemEventDefaultAnimator @JvmOverloads constructor(
+        resources: Resources,
+        private val onAlphaChanged: (Float) -> Unit,
+        private val onTranslationXChanged: (Float) -> Unit,
+        var isAnimationRunning: Boolean = false
 ) : SystemStatusAnimationCallback {
     private val translationXIn: Int = resources.getDimensionPixelSize(
             R.dimen.ongoing_appops_chip_animation_in_status_bar_translation_x)
@@ -46,18 +66,19 @@
             R.dimen.ongoing_appops_chip_animation_out_status_bar_translation_x)
 
     override fun onSystemEventAnimationBegin(): Animator {
+        isAnimationRunning = true
         val moveOut = ValueAnimator.ofFloat(0f, 1f).apply {
             duration = 23.frames
             interpolator = STATUS_BAR_X_MOVE_OUT
             addUpdateListener {
-                animatedView.translationX = -(translationXIn * animatedValue as Float)
+                onTranslationXChanged(-(translationXIn * animatedValue as Float))
             }
         }
         val alphaOut = ValueAnimator.ofFloat(1f, 0f).apply {
             duration = 8.frames
             interpolator = null
             addUpdateListener {
-                animatedView.alpha = animatedValue as Float
+                onAlphaChanged(animatedValue as Float)
             }
         }
 
@@ -67,13 +88,13 @@
     }
 
     override fun onSystemEventAnimationFinish(hasPersistentDot: Boolean): Animator {
-        animatedView.translationX = translationXOut.toFloat()
+        onTranslationXChanged(translationXOut.toFloat())
         val moveIn = ValueAnimator.ofFloat(1f, 0f).apply {
             duration = 23.frames
             startDelay = 7.frames
             interpolator = STATUS_BAR_X_MOVE_IN
             addUpdateListener {
-                animatedView.translationX = translationXOut * animatedValue as Float
+                onTranslationXChanged(translationXOut * animatedValue as Float)
             }
         }
         val alphaIn = ValueAnimator.ofFloat(0f, 1f).apply {
@@ -81,13 +102,14 @@
             startDelay = 11.frames
             interpolator = null
             addUpdateListener {
-                animatedView.alpha = animatedValue as Float
+                onAlphaChanged(animatedValue as Float)
             }
         }
 
         val animatorSet = AnimatorSet()
         animatorSet.playTogether(moveIn, alphaIn)
-
+        animatorSet.doOnEnd { isAnimationRunning = false }
+        animatorSet.doOnCancel { isAnimationRunning = false }
         return animatorSet
     }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/data/model/BacklightModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/MobileViewLog.kt
similarity index 68%
copy from packages/SystemUI/src/com/android/systemui/keyboard/data/model/BacklightModel.kt
copy to packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/MobileViewLog.kt
index ea15a9f..e594a8a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/data/model/BacklightModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/MobileViewLog.kt
@@ -12,13 +12,14 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
- *
  */
 
-package com.android.systemui.keyboard.data.model
+package com.android.systemui.statusbar.pipeline.dagger
 
-/**
- * Model for current state of keyboard backlight brightness. [level] indicates current level of
- * backlight brightness and [maxLevel] its max possible value.
- */
-data class BacklightModel(val level: Int, val maxLevel: Int)
+import javax.inject.Qualifier
+
+/** Logs for changes with the new mobile views. */
+@Qualifier
+@MustBeDocumented
+@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
+annotation class MobileViewLog
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
index 4464751..adfea80 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
@@ -148,5 +148,19 @@
         fun provideMobileInputLogBuffer(factory: LogBufferFactory): LogBuffer {
             return factory.create("MobileInputLog", 100)
         }
+
+        @Provides
+        @SysUISingleton
+        @MobileViewLog
+        fun provideMobileViewLogBuffer(factory: LogBufferFactory): LogBuffer {
+            return factory.create("MobileViewLog", 100)
+        }
+
+        @Provides
+        @SysUISingleton
+        @VerboseMobileViewLog
+        fun provideVerboseMobileViewLogBuffer(factory: LogBufferFactory): LogBuffer {
+            return factory.create("VerboseMobileViewLog", 100)
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/data/model/BacklightModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/VerboseMobileViewLog.kt
similarity index 68%
copy from packages/SystemUI/src/com/android/systemui/keyboard/data/model/BacklightModel.kt
copy to packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/VerboseMobileViewLog.kt
index ea15a9f..b987898 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/data/model/BacklightModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/VerboseMobileViewLog.kt
@@ -12,13 +12,14 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
- *
  */
 
-package com.android.systemui.keyboard.data.model
+package com.android.systemui.statusbar.pipeline.dagger
 
-/**
- * Model for current state of keyboard backlight brightness. [level] indicates current level of
- * backlight brightness and [maxLevel] its max possible value.
- */
-data class BacklightModel(val level: Int, val maxLevel: Int)
+import javax.inject.Qualifier
+
+/** Logs for **verbose** changes with the new mobile views. */
+@Qualifier
+@MustBeDocumented
+@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
+annotation class VerboseMobileViewLog
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/shared/MobileInputLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLogger.kt
similarity index 88%
rename from packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/shared/MobileInputLogger.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLogger.kt
index 3cbd2b7..73bf188 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/shared/MobileInputLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLogger.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.pipeline.mobile.shared
+package com.android.systemui.statusbar.pipeline.mobile.data
 
 import android.net.Network
 import android.net.NetworkCapabilities
@@ -51,8 +51,8 @@
         )
     }
 
-    fun logOnLost(network: Network) {
-        LoggerHelper.logOnLost(buffer, TAG, network)
+    fun logOnLost(network: Network, isDefaultNetworkCallback: Boolean) {
+        LoggerHelper.logOnLost(buffer, TAG, network, isDefaultNetworkCallback)
     }
 
     fun logOnServiceStateChanged(serviceState: ServiceState, subId: Int) {
@@ -133,24 +133,6 @@
         )
     }
 
-    fun logUiAdapterSubIdsUpdated(subs: List<Int>) {
-        buffer.log(
-            TAG,
-            LogLevel.INFO,
-            { str1 = subs.toString() },
-            { "Sub IDs in MobileUiAdapter updated internally: $str1" },
-        )
-    }
-
-    fun logUiAdapterSubIdsSentToIconController(subs: List<Int>) {
-        buffer.log(
-            TAG,
-            LogLevel.INFO,
-            { str1 = subs.toString() },
-            { "Sub IDs in MobileUiAdapter being sent to icon controller: $str1" },
-        )
-    }
-
     fun logCarrierConfigChanged(subId: Int) {
         buffer.log(
             TAG,
@@ -197,6 +179,10 @@
     fun logDefaultMobileIconGroup(group: SignalIcon.MobileIconGroup) {
         buffer.log(TAG, LogLevel.INFO, { str1 = group.name }, { "defaultMobileIconGroup: $str1" })
     }
+
+    fun logOnSubscriptionsChanged() {
+        buffer.log(TAG, LogLevel.INFO, {}, { "onSubscriptionsChanged" })
+    }
 }
 
 private const val TAG = "MobileInputLog"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/DataConnectionState.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/DataConnectionState.kt
index 85729c1..19f0242 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/DataConnectionState.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/DataConnectionState.kt
@@ -24,9 +24,11 @@
 import android.telephony.TelephonyManager.DATA_SUSPENDED
 import android.telephony.TelephonyManager.DATA_UNKNOWN
 import android.telephony.TelephonyManager.DataState
+import com.android.systemui.log.table.Diffable
+import com.android.systemui.log.table.TableRowLogger
 
 /** Internal enum representation of the telephony data connection states */
-enum class DataConnectionState {
+enum class DataConnectionState : Diffable<DataConnectionState> {
     Connected,
     Connecting,
     Disconnected,
@@ -34,7 +36,17 @@
     Suspended,
     HandoverInProgress,
     Unknown,
-    Invalid,
+    Invalid;
+
+    override fun logDiffs(prevVal: DataConnectionState, row: TableRowLogger) {
+        if (prevVal != this) {
+            row.logChange(COL_CONNECTION_STATE, name)
+        }
+    }
+
+    companion object {
+        private const val COL_CONNECTION_STATE = "connectionState"
+    }
 }
 
 fun @receiver:DataState Int.toDataConnectionType(): DataConnectionState =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileConnectionModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileConnectionModel.kt
deleted file mode 100644
index ed7f60b..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileConnectionModel.kt
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.pipeline.mobile.data.model
-
-import android.annotation.IntRange
-import android.telephony.CellSignalStrength
-import android.telephony.TelephonyCallback.CarrierNetworkListener
-import android.telephony.TelephonyCallback.DataActivityListener
-import android.telephony.TelephonyCallback.DataConnectionStateListener
-import android.telephony.TelephonyCallback.DisplayInfoListener
-import android.telephony.TelephonyCallback.ServiceStateListener
-import android.telephony.TelephonyCallback.SignalStrengthsListener
-import android.telephony.TelephonyDisplayInfo
-import android.telephony.TelephonyManager
-import androidx.annotation.VisibleForTesting
-import com.android.systemui.log.table.Diffable
-import com.android.systemui.log.table.TableRowLogger
-import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState.Disconnected
-import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
-
-/**
- * Data class containing all of the relevant information for a particular line of service, known as
- * a Subscription in the telephony world. These models are the result of a single telephony listener
- * which has many callbacks which each modify some particular field on this object.
- *
- * The design goal here is to de-normalize fields from the system into our model fields below. So
- * any new field that needs to be tracked should be copied into this data class rather than
- * threading complex system objects through the pipeline.
- */
-data class MobileConnectionModel(
-    /** Fields below are from [ServiceStateListener.onServiceStateChanged] */
-    val isEmergencyOnly: Boolean = false,
-    val isRoaming: Boolean = false,
-    /**
-     * See [android.telephony.ServiceState.getOperatorAlphaShort], this value is defined as the
-     * current registered operator name in short alphanumeric format. In some cases this name might
-     * be preferred over other methods of calculating the network name
-     */
-    val operatorAlphaShort: String? = null,
-
-    /**
-     * TODO (b/263167683): Clarify this field
-     *
-     * This check comes from [com.android.settingslib.Utils.isInService]. It is intended to be a
-     * mapping from a ServiceState to a notion of connectivity. Notably, it will consider a
-     * connection to be in-service if either the voice registration state is IN_SERVICE or the data
-     * registration state is IN_SERVICE and NOT IWLAN.
-     */
-    val isInService: Boolean = false,
-
-    /** Fields below from [SignalStrengthsListener.onSignalStrengthsChanged] */
-    val isGsm: Boolean = false,
-    @IntRange(from = 0, to = 4)
-    val cdmaLevel: Int = CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN,
-    @IntRange(from = 0, to = 4)
-    val primaryLevel: Int = CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN,
-
-    /** Fields below from [DataConnectionStateListener.onDataConnectionStateChanged] */
-    val dataConnectionState: DataConnectionState = Disconnected,
-
-    /**
-     * Fields below from [DataActivityListener.onDataActivity]. See [TelephonyManager] for the
-     * values
-     */
-    val dataActivityDirection: DataActivityModel =
-        DataActivityModel(
-            hasActivityIn = false,
-            hasActivityOut = false,
-        ),
-
-    /** Fields below from [CarrierNetworkListener.onCarrierNetworkChange] */
-    val carrierNetworkChangeActive: Boolean = false,
-
-    /** Fields below from [DisplayInfoListener.onDisplayInfoChanged]. */
-
-    /**
-     * [resolvedNetworkType] is the [TelephonyDisplayInfo.getOverrideNetworkType] if it exists or
-     * [TelephonyDisplayInfo.getNetworkType]. This is used to look up the proper network type icon
-     */
-    val resolvedNetworkType: ResolvedNetworkType = ResolvedNetworkType.UnknownNetworkType,
-) : Diffable<MobileConnectionModel> {
-    override fun logDiffs(prevVal: MobileConnectionModel, row: TableRowLogger) {
-        if (prevVal.dataConnectionState != dataConnectionState) {
-            row.logChange(COL_CONNECTION_STATE, dataConnectionState.name)
-        }
-
-        if (prevVal.isEmergencyOnly != isEmergencyOnly) {
-            row.logChange(COL_EMERGENCY, isEmergencyOnly)
-        }
-
-        if (prevVal.isRoaming != isRoaming) {
-            row.logChange(COL_ROAMING, isRoaming)
-        }
-
-        if (prevVal.operatorAlphaShort != operatorAlphaShort) {
-            row.logChange(COL_OPERATOR, operatorAlphaShort)
-        }
-
-        if (prevVal.isInService != isInService) {
-            row.logChange(COL_IS_IN_SERVICE, isInService)
-        }
-
-        if (prevVal.isGsm != isGsm) {
-            row.logChange(COL_IS_GSM, isGsm)
-        }
-
-        if (prevVal.cdmaLevel != cdmaLevel) {
-            row.logChange(COL_CDMA_LEVEL, cdmaLevel)
-        }
-
-        if (prevVal.primaryLevel != primaryLevel) {
-            row.logChange(COL_PRIMARY_LEVEL, primaryLevel)
-        }
-
-        if (prevVal.dataActivityDirection.hasActivityIn != dataActivityDirection.hasActivityIn) {
-            row.logChange(COL_ACTIVITY_DIRECTION_IN, dataActivityDirection.hasActivityIn)
-        }
-
-        if (prevVal.dataActivityDirection.hasActivityOut != dataActivityDirection.hasActivityOut) {
-            row.logChange(COL_ACTIVITY_DIRECTION_OUT, dataActivityDirection.hasActivityOut)
-        }
-
-        if (prevVal.carrierNetworkChangeActive != carrierNetworkChangeActive) {
-            row.logChange(COL_CARRIER_NETWORK_CHANGE, carrierNetworkChangeActive)
-        }
-
-        if (prevVal.resolvedNetworkType != resolvedNetworkType) {
-            row.logChange(COL_RESOLVED_NETWORK_TYPE, resolvedNetworkType.toString())
-        }
-    }
-
-    override fun logFull(row: TableRowLogger) {
-        row.logChange(COL_CONNECTION_STATE, dataConnectionState.name)
-        row.logChange(COL_EMERGENCY, isEmergencyOnly)
-        row.logChange(COL_ROAMING, isRoaming)
-        row.logChange(COL_OPERATOR, operatorAlphaShort)
-        row.logChange(COL_IS_IN_SERVICE, isInService)
-        row.logChange(COL_IS_GSM, isGsm)
-        row.logChange(COL_CDMA_LEVEL, cdmaLevel)
-        row.logChange(COL_PRIMARY_LEVEL, primaryLevel)
-        row.logChange(COL_ACTIVITY_DIRECTION_IN, dataActivityDirection.hasActivityIn)
-        row.logChange(COL_ACTIVITY_DIRECTION_OUT, dataActivityDirection.hasActivityOut)
-        row.logChange(COL_CARRIER_NETWORK_CHANGE, carrierNetworkChangeActive)
-        row.logChange(COL_RESOLVED_NETWORK_TYPE, resolvedNetworkType.toString())
-    }
-
-    @VisibleForTesting
-    companion object {
-        const val COL_EMERGENCY = "EmergencyOnly"
-        const val COL_ROAMING = "Roaming"
-        const val COL_OPERATOR = "OperatorName"
-        const val COL_IS_IN_SERVICE = "IsInService"
-        const val COL_IS_GSM = "IsGsm"
-        const val COL_CDMA_LEVEL = "CdmaLevel"
-        const val COL_PRIMARY_LEVEL = "PrimaryLevel"
-        const val COL_CONNECTION_STATE = "ConnectionState"
-        const val COL_ACTIVITY_DIRECTION_IN = "DataActivity.In"
-        const val COL_ACTIVITY_DIRECTION_OUT = "DataActivity.Out"
-        const val COL_CARRIER_NETWORK_CHANGE = "CarrierNetworkChangeActive"
-        const val COL_RESOLVED_NETWORK_TYPE = "NetworkType"
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/ResolvedNetworkType.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/ResolvedNetworkType.kt
index 5562e73..cf7a313 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/ResolvedNetworkType.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/ResolvedNetworkType.kt
@@ -17,8 +17,12 @@
 package com.android.systemui.statusbar.pipeline.mobile.data.model
 
 import android.telephony.Annotation.NetworkType
+import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
 import com.android.settingslib.SignalIcon
+import com.android.settingslib.mobile.MobileMappings
 import com.android.settingslib.mobile.TelephonyIcons
+import com.android.systemui.log.table.Diffable
+import com.android.systemui.log.table.TableRowLogger
 import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
 
 /**
@@ -26,11 +30,19 @@
  * on whether or not the display info contains an override type, we may have to call different
  * methods on [MobileMappingsProxy] to generate an icon lookup key.
  */
-sealed interface ResolvedNetworkType {
+sealed interface ResolvedNetworkType : Diffable<ResolvedNetworkType> {
     val lookupKey: String
 
+    override fun logDiffs(prevVal: ResolvedNetworkType, row: TableRowLogger) {
+        if (prevVal != this) {
+            row.logChange(COL_NETWORK_TYPE, this.toString())
+        }
+    }
+
     object UnknownNetworkType : ResolvedNetworkType {
-        override val lookupKey: String = "unknown"
+        override val lookupKey: String = MobileMappings.toIconKey(NETWORK_TYPE_UNKNOWN)
+
+        override fun toString(): String = "Unknown"
     }
 
     data class DefaultNetworkType(
@@ -47,5 +59,11 @@
         override val lookupKey: String = "cwf"
 
         val iconGroupOverride: SignalIcon.MobileIconGroup = TelephonyIcons.CARRIER_MERGED_WIFI
+
+        override fun toString(): String = "CarrierMerged"
+    }
+
+    companion object {
+        private const val COL_NETWORK_TYPE = "networkType"
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepository.kt
index bb3b9b2..efdce06 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepository.kt
@@ -30,8 +30,8 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
-import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger
 import java.io.PrintWriter
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt
index 6187f64..90c32dc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt
@@ -17,11 +17,12 @@
 package com.android.systemui.statusbar.pipeline.mobile.data.repository
 
 import android.telephony.SubscriptionInfo
-import android.telephony.TelephonyCallback
 import android.telephony.TelephonyManager
 import com.android.systemui.log.table.TableLogBuffer
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
 import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
+import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
 import kotlinx.coroutines.flow.StateFlow
 
 /**
@@ -45,11 +46,57 @@
      */
     val tableLogBuffer: TableLogBuffer
 
+    /** True if the [android.telephony.ServiceState] says this connection is emergency calls only */
+    val isEmergencyOnly: StateFlow<Boolean>
+
+    /** True if [android.telephony.ServiceState] says we are roaming */
+    val isRoaming: StateFlow<Boolean>
+
     /**
-     * A flow that aggregates all necessary callbacks from [TelephonyCallback] into a single
-     * listener + model.
+     * See [android.telephony.ServiceState.getOperatorAlphaShort], this value is defined as the
+     * current registered operator name in short alphanumeric format. In some cases this name might
+     * be preferred over other methods of calculating the network name
      */
-    val connectionInfo: StateFlow<MobileConnectionModel>
+    val operatorAlphaShort: StateFlow<String?>
+
+    /**
+     * TODO (b/263167683): Clarify this field
+     *
+     * This check comes from [com.android.settingslib.Utils.isInService]. It is intended to be a
+     * mapping from a ServiceState to a notion of connectivity. Notably, it will consider a
+     * connection to be in-service if either the voice registration state is IN_SERVICE or the data
+     * registration state is IN_SERVICE and NOT IWLAN.
+     */
+    val isInService: StateFlow<Boolean>
+
+    /** True if [android.telephony.SignalStrength] told us that this connection is using GSM */
+    val isGsm: StateFlow<Boolean>
+
+    /**
+     * There is still specific logic in the pipeline that calls out CDMA level explicitly. This
+     * field is not completely orthogonal to [primaryLevel], because CDMA could be primary.
+     */
+    // @IntRange(from = 0, to = 4)
+    val cdmaLevel: StateFlow<Int>
+
+    /** [android.telephony.SignalStrength]'s concept of the overall signal level */
+    // @IntRange(from = 0, to = 4)
+    val primaryLevel: StateFlow<Int>
+
+    /** The current data connection state. See [DataConnectionState] */
+    val dataConnectionState: StateFlow<DataConnectionState>
+
+    /** The current data activity direction. See [DataActivityModel] */
+    val dataActivityDirection: StateFlow<DataActivityModel>
+
+    /** True if there is currently a carrier network change in process */
+    val carrierNetworkChangeActive: StateFlow<Boolean>
+
+    /**
+     * [resolvedNetworkType] is the [TelephonyDisplayInfo.getOverrideNetworkType] if it exists or
+     * [TelephonyDisplayInfo.getNetworkType]. This is used to look up the proper network type icon
+     */
+    val resolvedNetworkType: StateFlow<ResolvedNetworkType>
 
     /** The total number of levels. Used with [SignalDrawable]. */
     val numberOfLevels: StateFlow<Int>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt
new file mode 100644
index 0000000..809772e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.data.repository.demo
+
+import android.telephony.CellSignalStrength
+import android.telephony.TelephonyManager
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.logDiffsForTable
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_CARRIER_NETWORK_CHANGE
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_CDMA_LEVEL
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_EMERGENCY
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_IS_GSM
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_IS_IN_SERVICE
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_OPERATOR
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_PRIMARY_LEVEL
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_ROAMING
+import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
+import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model.FakeWifiEventModel
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.stateIn
+
+/**
+ * Demo version of [MobileConnectionRepository]. Note that this class shares all of its flows using
+ * [SharingStarted.WhileSubscribed()] to give the same semantics as using a regular
+ * [MutableStateFlow] while still logging all of the inputs in the same manor as the production
+ * repos.
+ */
+class DemoMobileConnectionRepository(
+    override val subId: Int,
+    override val tableLogBuffer: TableLogBuffer,
+    val scope: CoroutineScope,
+) : MobileConnectionRepository {
+    private val _isEmergencyOnly = MutableStateFlow(false)
+    override val isEmergencyOnly =
+        _isEmergencyOnly
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnPrefix = "",
+                columnName = COL_EMERGENCY,
+                _isEmergencyOnly.value
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), _isEmergencyOnly.value)
+
+    private val _isRoaming = MutableStateFlow(false)
+    override val isRoaming =
+        _isRoaming
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnPrefix = "",
+                columnName = COL_ROAMING,
+                _isRoaming.value
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), _isRoaming.value)
+
+    private val _operatorAlphaShort: MutableStateFlow<String?> = MutableStateFlow(null)
+    override val operatorAlphaShort =
+        _operatorAlphaShort
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnPrefix = "",
+                columnName = COL_OPERATOR,
+                _operatorAlphaShort.value
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), _operatorAlphaShort.value)
+
+    private val _isInService = MutableStateFlow(false)
+    override val isInService =
+        _isInService
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnPrefix = "",
+                columnName = COL_IS_IN_SERVICE,
+                _isInService.value
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), _isInService.value)
+
+    private val _isGsm = MutableStateFlow(false)
+    override val isGsm =
+        _isGsm
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnPrefix = "",
+                columnName = COL_IS_GSM,
+                _isGsm.value
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), _isGsm.value)
+
+    private val _cdmaLevel = MutableStateFlow(CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
+    override val cdmaLevel =
+        _cdmaLevel
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnPrefix = "",
+                columnName = COL_CDMA_LEVEL,
+                _cdmaLevel.value
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), _cdmaLevel.value)
+
+    private val _primaryLevel = MutableStateFlow(CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
+    override val primaryLevel =
+        _primaryLevel
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnPrefix = "",
+                columnName = COL_PRIMARY_LEVEL,
+                _primaryLevel.value
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), _primaryLevel.value)
+
+    private val _dataConnectionState = MutableStateFlow(DataConnectionState.Disconnected)
+    override val dataConnectionState =
+        _dataConnectionState
+            .logDiffsForTable(tableLogBuffer, columnPrefix = "", _dataConnectionState.value)
+            .stateIn(scope, SharingStarted.WhileSubscribed(), _dataConnectionState.value)
+
+    private val _dataActivityDirection =
+        MutableStateFlow(
+            DataActivityModel(
+                hasActivityIn = false,
+                hasActivityOut = false,
+            )
+        )
+    override val dataActivityDirection =
+        _dataActivityDirection
+            .logDiffsForTable(tableLogBuffer, columnPrefix = "", _dataActivityDirection.value)
+            .stateIn(scope, SharingStarted.WhileSubscribed(), _dataActivityDirection.value)
+
+    private val _carrierNetworkChangeActive = MutableStateFlow(false)
+    override val carrierNetworkChangeActive =
+        _carrierNetworkChangeActive
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnPrefix = "",
+                columnName = COL_CARRIER_NETWORK_CHANGE,
+                _carrierNetworkChangeActive.value
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), _carrierNetworkChangeActive.value)
+
+    private val _resolvedNetworkType: MutableStateFlow<ResolvedNetworkType> =
+        MutableStateFlow(ResolvedNetworkType.UnknownNetworkType)
+    override val resolvedNetworkType =
+        _resolvedNetworkType
+            .logDiffsForTable(tableLogBuffer, columnPrefix = "", _resolvedNetworkType.value)
+            .stateIn(scope, SharingStarted.WhileSubscribed(), _resolvedNetworkType.value)
+
+    override val numberOfLevels = MutableStateFlow(MobileConnectionRepository.DEFAULT_NUM_LEVELS)
+
+    override val dataEnabled = MutableStateFlow(true)
+
+    override val cdmaRoaming = MutableStateFlow(false)
+
+    override val networkName = MutableStateFlow(NetworkNameModel.IntentDerived("demo network"))
+
+    /**
+     * Process a new demo mobile event. Note that [resolvedNetworkType] must be passed in separately
+     * from the event, due to the requirement to reverse the mobile mappings lookup in the top-level
+     * repository.
+     */
+    fun processDemoMobileEvent(
+        event: FakeNetworkEventModel.Mobile,
+        resolvedNetworkType: ResolvedNetworkType,
+    ) {
+        // This is always true here, because we split out disabled states at the data-source level
+        dataEnabled.value = true
+        networkName.value = NetworkNameModel.IntentDerived(event.name)
+
+        cdmaRoaming.value = event.roaming
+        _isRoaming.value = event.roaming
+        // TODO(b/261029387): not yet supported
+        _isEmergencyOnly.value = false
+        _operatorAlphaShort.value = event.name
+        _isInService.value = (event.level ?: 0) > 0
+        // TODO(b/261029387): not yet supported
+        _isGsm.value = false
+        _cdmaLevel.value = event.level ?: 0
+        _primaryLevel.value = event.level ?: 0
+        // TODO(b/261029387): not yet supported
+        _dataConnectionState.value = DataConnectionState.Connected
+        _dataActivityDirection.value =
+            (event.activity ?: TelephonyManager.DATA_ACTIVITY_NONE).toMobileDataActivityModel()
+        _carrierNetworkChangeActive.value = event.carrierNetworkChange
+        _resolvedNetworkType.value = resolvedNetworkType
+    }
+
+    fun processCarrierMergedEvent(event: FakeWifiEventModel.CarrierMerged) {
+        // This is always true here, because we split out disabled states at the data-source level
+        dataEnabled.value = true
+        networkName.value = NetworkNameModel.IntentDerived(CARRIER_MERGED_NAME)
+        numberOfLevels.value = event.numberOfLevels
+        cdmaRoaming.value = false
+        _primaryLevel.value = event.level
+        _cdmaLevel.value = event.level
+        _dataActivityDirection.value = event.activity.toMobileDataActivityModel()
+
+        // These fields are always the same for carrier-merged networks
+        _resolvedNetworkType.value = ResolvedNetworkType.CarrierMergedNetworkType
+        _dataConnectionState.value = DataConnectionState.Connected
+        _isRoaming.value = false
+        _isEmergencyOnly.value = false
+        _operatorAlphaShort.value = null
+        _isInService.value = true
+        _isGsm.value = false
+        _carrierNetworkChangeActive.value = false
+    }
+
+    companion object {
+        private const val CARRIER_MERGED_NAME = "Carrier Merged Network"
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
index e924832..3cafb73 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
@@ -18,30 +18,22 @@
 
 import android.content.Context
 import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
-import android.telephony.TelephonyManager.DATA_ACTIVITY_NONE
 import android.util.Log
 import com.android.settingslib.SignalIcon
 import com.android.settingslib.mobile.MobileMappings
 import com.android.settingslib.mobile.TelephonyIcons
 import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.log.table.TableLogBuffer
 import com.android.systemui.log.table.TableLogBufferFactory
-import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
 import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel
-import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.Mobile
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.MobileDisabled
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.CarrierMergedConnectionRepository.Companion.createCarrierMergedConnectionModel
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Factory.Companion.MOBILE_CONNECTION_BUFFER_SIZE
-import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoModeWifiDataSource
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model.FakeWifiEventModel
 import javax.inject.Inject
@@ -183,7 +175,7 @@
     private fun createDemoMobileConnectionRepo(subId: Int): CacheContainer {
         val tableLogBuffer =
             logFactory.getOrCreate(
-                "DemoMobileConnectionLog [$subId]",
+                "DemoMobileConnectionLog[$subId]",
                 MOBILE_CONNECTION_BUFFER_SIZE,
             )
 
@@ -191,6 +183,7 @@
             DemoMobileConnectionRepository(
                 subId,
                 tableLogBuffer,
+                scope,
             )
         return CacheContainer(repo, lastMobileState = null)
     }
@@ -237,23 +230,18 @@
         }
     }
 
-    private fun processEnabledMobileState(state: Mobile) {
+    private fun processEnabledMobileState(event: Mobile) {
         // get or create the connection repo, and set its values
-        val subId = state.subId ?: DEFAULT_SUB_ID
+        val subId = event.subId ?: DEFAULT_SUB_ID
         maybeCreateSubscription(subId)
 
         val connection = getRepoForSubId(subId)
-        connectionRepoCache[subId]?.lastMobileState = state
+        connectionRepoCache[subId]?.lastMobileState = event
 
         // TODO(b/261029387): until we have a command, use the most recent subId
         defaultDataSubId.value = subId
 
-        // This is always true here, because we split out disabled states at the data-source level
-        connection.dataEnabled.value = true
-        connection.networkName.value = NetworkNameModel.IntentDerived(state.name)
-
-        connection.cdmaRoaming.value = state.roaming
-        connection.connectionInfo.value = state.toMobileConnectionModel()
+        connection.processDemoMobileEvent(event, event.dataType.toResolvedNetworkType())
     }
 
     private fun processCarrierMergedWifiState(event: FakeWifiEventModel.CarrierMerged) {
@@ -272,13 +260,7 @@
         defaultDataSubId.value = subId
 
         val connection = getRepoForSubId(subId)
-        // This is always true here, because we split out disabled states at the data-source level
-        connection.dataEnabled.value = true
-        connection.networkName.value = NetworkNameModel.IntentDerived(CARRIER_MERGED_NAME)
-        connection.numberOfLevels.value = event.numberOfLevels
-        connection.cdmaRoaming.value = false
-        connection.connectionInfo.value = event.toMobileConnectionModel()
-        Log.e("CCS", "output connection info = ${connection.connectionInfo.value}")
+        connection.processCarrierMergedEvent(event)
     }
 
     private fun maybeRemoveSubscription(subId: Int?) {
@@ -332,29 +314,6 @@
     private fun subIdsString(): String =
         _subscriptions.value.joinToString(",") { it.subscriptionId.toString() }
 
-    private fun Mobile.toMobileConnectionModel(): MobileConnectionModel {
-        return MobileConnectionModel(
-            isEmergencyOnly = false, // TODO(b/261029387): not yet supported
-            isRoaming = roaming,
-            isInService = (level ?: 0) > 0,
-            isGsm = false, // TODO(b/261029387): not yet supported
-            cdmaLevel = level ?: 0,
-            primaryLevel = level ?: 0,
-            dataConnectionState =
-                DataConnectionState.Connected, // TODO(b/261029387): not yet supported
-            dataActivityDirection = (activity ?: DATA_ACTIVITY_NONE).toMobileDataActivityModel(),
-            carrierNetworkChangeActive = carrierNetworkChange,
-            resolvedNetworkType = dataType.toResolvedNetworkType()
-        )
-    }
-
-    private fun FakeWifiEventModel.CarrierMerged.toMobileConnectionModel(): MobileConnectionModel {
-        return createCarrierMergedConnectionModel(
-            this.level,
-            activity.toMobileDataActivityModel(),
-        )
-    }
-
     private fun SignalIcon.MobileIconGroup?.toResolvedNetworkType(): ResolvedNetworkType {
         val key = mobileMappingsReverseLookup.value[this] ?: "dis"
         return DefaultNetworkType(key)
@@ -364,8 +323,6 @@
         private const val TAG = "DemoMobileConnectionsRepo"
 
         private const val DEFAULT_SUB_ID = 1
-
-        private const val CARRIER_MERGED_NAME = "Carrier Merged Network"
     }
 }
 
@@ -374,18 +331,3 @@
     /** The last received [Mobile] event. Used when switching from carrier merged back to mobile. */
     var lastMobileState: Mobile?,
 )
-
-class DemoMobileConnectionRepository(
-    override val subId: Int,
-    override val tableLogBuffer: TableLogBuffer,
-) : MobileConnectionRepository {
-    override val connectionInfo = MutableStateFlow(MobileConnectionModel())
-
-    override val numberOfLevels = MutableStateFlow(DEFAULT_NUM_LEVELS)
-
-    override val dataEnabled = MutableStateFlow(true)
-
-    override val cdmaRoaming = MutableStateFlow(false)
-
-    override val networkName = MutableStateFlow(NetworkNameModel.IntentDerived("demo network"))
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt
index 8f6a87b..94d6d0b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt
@@ -16,18 +16,17 @@
 
 package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
 
+import android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN
 import android.telephony.TelephonyManager
 import android.util.Log
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.log.table.TableLogBuffer
 import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
 import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
-import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
 import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
 import javax.inject.Inject
@@ -94,16 +93,6 @@
             }
         }
 
-    override val connectionInfo: StateFlow<MobileConnectionModel> =
-        combine(network, wifiRepository.wifiActivity) { network, activity ->
-                if (network == null) {
-                    MobileConnectionModel()
-                } else {
-                    createCarrierMergedConnectionModel(network.level, activity)
-                }
-            }
-            .stateIn(scope, SharingStarted.WhileSubscribed(), MobileConnectionModel())
-
     override val cdmaRoaming: StateFlow<Boolean> = MutableStateFlow(ROAMING).asStateFlow()
 
     override val networkName: StateFlow<NetworkNameModel> =
@@ -129,34 +118,54 @@
             }
             .stateIn(scope, SharingStarted.WhileSubscribed(), DEFAULT_NUM_LEVELS)
 
+    override val primaryLevel =
+        network
+            .map { it?.level ?: SIGNAL_STRENGTH_NONE_OR_UNKNOWN }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
+
+    override val cdmaLevel =
+        network
+            .map { it?.level ?: SIGNAL_STRENGTH_NONE_OR_UNKNOWN }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
+
+    override val dataActivityDirection = wifiRepository.wifiActivity
+
+    override val resolvedNetworkType =
+        network
+            .map {
+                if (it != null) {
+                    ResolvedNetworkType.CarrierMergedNetworkType
+                } else {
+                    ResolvedNetworkType.UnknownNetworkType
+                }
+            }
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                ResolvedNetworkType.UnknownNetworkType
+            )
+
+    override val dataConnectionState =
+        network
+            .map {
+                if (it != null) {
+                    DataConnectionState.Connected
+                } else {
+                    DataConnectionState.Disconnected
+                }
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), DataConnectionState.Disconnected)
+
+    override val isRoaming = MutableStateFlow(false).asStateFlow()
+    override val isEmergencyOnly = MutableStateFlow(false).asStateFlow()
+    override val operatorAlphaShort = MutableStateFlow(null).asStateFlow()
+    override val isInService = MutableStateFlow(true).asStateFlow()
+    override val isGsm = MutableStateFlow(false).asStateFlow()
+    override val carrierNetworkChangeActive = MutableStateFlow(false).asStateFlow()
+
     override val dataEnabled: StateFlow<Boolean> = wifiRepository.isWifiEnabled
 
     companion object {
-        /**
-         * Creates an instance of [MobileConnectionModel] that represents a carrier merged network
-         * with the given [level] and [activity].
-         */
-        fun createCarrierMergedConnectionModel(
-            level: Int,
-            activity: DataActivityModel,
-        ): MobileConnectionModel {
-            return MobileConnectionModel(
-                primaryLevel = level,
-                cdmaLevel = level,
-                dataActivityDirection = activity,
-                // Here and below: These values are always the same for every carrier-merged
-                // connection.
-                resolvedNetworkType = ResolvedNetworkType.CarrierMergedNetworkType,
-                dataConnectionState = DataConnectionState.Connected,
-                isRoaming = ROAMING,
-                isEmergencyOnly = false,
-                operatorAlphaShort = null,
-                isInService = true,
-                isGsm = false,
-                carrierNetworkChangeActive = false,
-            )
-        }
-
         // Carrier merged is never roaming
         private const val ROAMING = false
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt
index a39ea0a..b3737ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt
@@ -114,15 +114,147 @@
             .flatMapLatest { it.cdmaRoaming }
             .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.cdmaRoaming.value)
 
-    override val connectionInfo =
+    override val isEmergencyOnly =
         activeRepo
-            .flatMapLatest { it.connectionInfo }
+            .flatMapLatest { it.isEmergencyOnly }
             .logDiffsForTable(
                 tableLogBuffer,
                 columnPrefix = "",
-                initialValue = activeRepo.value.connectionInfo.value,
+                columnName = COL_EMERGENCY,
+                activeRepo.value.isEmergencyOnly.value
             )
-            .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.connectionInfo.value)
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                activeRepo.value.isEmergencyOnly.value
+            )
+
+    override val isRoaming =
+        activeRepo
+            .flatMapLatest { it.isRoaming }
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnPrefix = "",
+                columnName = COL_ROAMING,
+                activeRepo.value.isRoaming.value
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.isRoaming.value)
+
+    override val operatorAlphaShort =
+        activeRepo
+            .flatMapLatest { it.operatorAlphaShort }
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnPrefix = "",
+                columnName = COL_OPERATOR,
+                activeRepo.value.operatorAlphaShort.value
+            )
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                activeRepo.value.operatorAlphaShort.value
+            )
+
+    override val isInService =
+        activeRepo
+            .flatMapLatest { it.isInService }
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnPrefix = "",
+                columnName = COL_IS_IN_SERVICE,
+                activeRepo.value.isInService.value
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.isInService.value)
+
+    override val isGsm =
+        activeRepo
+            .flatMapLatest { it.isGsm }
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnPrefix = "",
+                columnName = COL_IS_GSM,
+                activeRepo.value.isGsm.value
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.isGsm.value)
+
+    override val cdmaLevel =
+        activeRepo
+            .flatMapLatest { it.cdmaLevel }
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnPrefix = "",
+                columnName = COL_CDMA_LEVEL,
+                activeRepo.value.cdmaLevel.value
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.cdmaLevel.value)
+
+    override val primaryLevel =
+        activeRepo
+            .flatMapLatest { it.primaryLevel }
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnPrefix = "",
+                columnName = COL_PRIMARY_LEVEL,
+                activeRepo.value.primaryLevel.value
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.primaryLevel.value)
+
+    override val dataConnectionState =
+        activeRepo
+            .flatMapLatest { it.dataConnectionState }
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnPrefix = "",
+                activeRepo.value.dataConnectionState.value
+            )
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                activeRepo.value.dataConnectionState.value
+            )
+
+    override val dataActivityDirection =
+        activeRepo
+            .flatMapLatest { it.dataActivityDirection }
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnPrefix = "",
+                activeRepo.value.dataActivityDirection.value
+            )
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                activeRepo.value.dataActivityDirection.value
+            )
+
+    override val carrierNetworkChangeActive =
+        activeRepo
+            .flatMapLatest { it.carrierNetworkChangeActive }
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnPrefix = "",
+                columnName = COL_CARRIER_NETWORK_CHANGE,
+                activeRepo.value.carrierNetworkChangeActive.value
+            )
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                activeRepo.value.carrierNetworkChangeActive.value
+            )
+
+    override val resolvedNetworkType =
+        activeRepo
+            .flatMapLatest { it.resolvedNetworkType }
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnPrefix = "",
+                activeRepo.value.resolvedNetworkType.value
+            )
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                activeRepo.value.resolvedNetworkType.value
+            )
 
     override val dataEnabled =
         activeRepo
@@ -187,4 +319,15 @@
             fun tableBufferLogName(subId: Int): String = "MobileConnectionLog[$subId]"
         }
     }
+
+    companion object {
+        const val COL_EMERGENCY = "emergencyOnly"
+        const val COL_ROAMING = "roaming"
+        const val COL_OPERATOR = "operatorName"
+        const val COL_IS_IN_SERVICE = "isInService"
+        const val COL_IS_GSM = "isGsm"
+        const val COL_CDMA_LEVEL = "cdmaLevel"
+        const val COL_PRIMARY_LEVEL = "primaryLevel"
+        const val COL_CARRIER_NETWORK_CHANGE = "carrierNetworkChangeActive"
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
index 96b96f1..d0c6215 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
@@ -18,7 +18,7 @@
 
 import android.content.Context
 import android.content.IntentFilter
-import android.telephony.CellSignalStrength
+import android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN
 import android.telephony.CellSignalStrengthCdma
 import android.telephony.ServiceState
 import android.telephony.SignalStrength
@@ -27,16 +27,17 @@
 import android.telephony.TelephonyDisplayInfo
 import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE
 import android.telephony.TelephonyManager
-import android.telephony.TelephonyManager.ERI_OFF
+import android.telephony.TelephonyManager.ERI_FLASH
+import android.telephony.TelephonyManager.ERI_ON
 import android.telephony.TelephonyManager.EXTRA_SUBSCRIPTION_ID
 import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
 import com.android.settingslib.Utils
 import com.android.systemui.broadcast.BroadcastDispatcher
-import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.log.table.TableLogBuffer
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState.Disconnected
 import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.OverrideNetworkType
@@ -47,8 +48,8 @@
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigRepository
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
-import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger
 import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
+import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
 import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
@@ -57,16 +58,14 @@
 import kotlinx.coroutines.asExecutor
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableSharedFlow
-import kotlinx.coroutines.flow.SharedFlow
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.callbackFlow
 import kotlinx.coroutines.flow.filter
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.mapLatest
 import kotlinx.coroutines.flow.mapNotNull
 import kotlinx.coroutines.flow.scan
-import kotlinx.coroutines.flow.shareIn
 import kotlinx.coroutines.flow.stateIn
 
 /**
@@ -98,8 +97,6 @@
         }
     }
 
-    private val telephonyCallbackEvent = MutableSharedFlow<Unit>(extraBufferCapacity = 1)
-
     /**
      * This flow defines the single shared connection to system_server via TelephonyCallback. Any
      * new callback should be added to this listener and funneled through callbackEvents via a data
@@ -107,9 +104,19 @@
      *
      * The reason we need to do this is because TelephonyManager limits the number of registered
      * listeners per-process, so we don't want to create a new listener for every callback.
+     *
+     * A note on the design for back pressure here: We don't control _which_ telephony callback
+     * comes in first, since we register every relevant bit of information as a batch. E.g., if a
+     * downstream starts collecting on a field which is backed by
+     * [TelephonyCallback.ServiceStateListener], it's not possible for us to guarantee that _that_
+     * callback comes in -- the first callback could very well be
+     * [TelephonyCallback.DataActivityListener], which would promptly be dropped if we didn't keep
+     * it tracked. We use the [scan] operator here to track the most recent callback of _each type_
+     * here. See [TelephonyCallbackState] to see how the callbacks are stored.
      */
-    private val callbackEvents: SharedFlow<CallbackEvent> =
-        conflatedCallbackFlow {
+    private val callbackEvents: StateFlow<TelephonyCallbackState> = run {
+        val initial = TelephonyCallbackState()
+        callbackFlow {
                 val callback =
                     object :
                         TelephonyCallback(),
@@ -163,86 +170,103 @@
                 telephonyManager.registerTelephonyCallback(bgDispatcher.asExecutor(), callback)
                 awaitClose { telephonyManager.unregisterTelephonyCallback(callback) }
             }
-            .shareIn(scope, SharingStarted.WhileSubscribed())
-
-    private fun updateConnectionState(
-        prevState: MobileConnectionModel,
-        callbackEvent: CallbackEvent,
-    ): MobileConnectionModel =
-        when (callbackEvent) {
-            is CallbackEvent.OnServiceStateChanged -> {
-                val serviceState = callbackEvent.serviceState
-                prevState.copy(
-                    isEmergencyOnly = serviceState.isEmergencyOnly,
-                    isRoaming = serviceState.roaming,
-                    operatorAlphaShort = serviceState.operatorAlphaShort,
-                    isInService = Utils.isInService(serviceState),
-                )
-            }
-            is CallbackEvent.OnSignalStrengthChanged -> {
-                val signalStrength = callbackEvent.signalStrength
-                val cdmaLevel =
-                    signalStrength.getCellSignalStrengths(CellSignalStrengthCdma::class.java).let {
-                        strengths ->
-                        if (!strengths.isEmpty()) {
-                            strengths[0].level
-                        } else {
-                            CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN
-                        }
-                    }
-
-                val primaryLevel = signalStrength.level
-
-                prevState.copy(
-                    cdmaLevel = cdmaLevel,
-                    primaryLevel = primaryLevel,
-                    isGsm = signalStrength.isGsm,
-                )
-            }
-            is CallbackEvent.OnDataConnectionStateChanged -> {
-                prevState.copy(dataConnectionState = callbackEvent.dataState.toDataConnectionType())
-            }
-            is CallbackEvent.OnDataActivity -> {
-                prevState.copy(
-                    dataActivityDirection = callbackEvent.direction.toMobileDataActivityModel()
-                )
-            }
-            is CallbackEvent.OnCarrierNetworkChange -> {
-                prevState.copy(carrierNetworkChangeActive = callbackEvent.active)
-            }
-            is CallbackEvent.OnDisplayInfoChanged -> {
-                val telephonyDisplayInfo = callbackEvent.telephonyDisplayInfo
-                val networkType =
-                    if (telephonyDisplayInfo.networkType == NETWORK_TYPE_UNKNOWN) {
-                        UnknownNetworkType
-                    } else if (
-                        telephonyDisplayInfo.overrideNetworkType == OVERRIDE_NETWORK_TYPE_NONE
-                    ) {
-                        DefaultNetworkType(
-                            mobileMappingsProxy.toIconKey(telephonyDisplayInfo.networkType)
-                        )
-                    } else {
-                        OverrideNetworkType(
-                            mobileMappingsProxy.toIconKeyOverride(
-                                telephonyDisplayInfo.overrideNetworkType
-                            )
-                        )
-                    }
-                prevState.copy(resolvedNetworkType = networkType)
-            }
-            is CallbackEvent.OnDataEnabledChanged -> {
-                // Not part of this object, handled in a separate flow
-                prevState
-            }
-        }
-
-    override val connectionInfo = run {
-        val initial = MobileConnectionModel()
-        callbackEvents
-            .scan(initial, ::updateConnectionState)
-            .stateIn(scope, SharingStarted.WhileSubscribed(), initial)
+            .scan(initial = initial) { state, event -> state.applyEvent(event) }
+            .stateIn(scope = scope, started = SharingStarted.WhileSubscribed(), initial)
     }
 
+    override val isEmergencyOnly =
+        callbackEvents
+            .mapNotNull { it.onServiceStateChanged }
+            .map { it.serviceState.isEmergencyOnly }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val isRoaming =
+        callbackEvents
+            .mapNotNull { it.onServiceStateChanged }
+            .map { it.serviceState.roaming }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val operatorAlphaShort =
+        callbackEvents
+            .mapNotNull { it.onServiceStateChanged }
+            .map { it.serviceState.operatorAlphaShort }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), null)
+
+    override val isInService =
+        callbackEvents
+            .mapNotNull { it.onServiceStateChanged }
+            .map { Utils.isInService(it.serviceState) }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val isGsm =
+        callbackEvents
+            .mapNotNull { it.onSignalStrengthChanged }
+            .map { it.signalStrength.isGsm }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val cdmaLevel =
+        callbackEvents
+            .mapNotNull { it.onSignalStrengthChanged }
+            .map {
+                it.signalStrength.getCellSignalStrengths(CellSignalStrengthCdma::class.java).let {
+                    strengths ->
+                    if (strengths.isNotEmpty()) {
+                        strengths[0].level
+                    } else {
+                        SIGNAL_STRENGTH_NONE_OR_UNKNOWN
+                    }
+                }
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
+
+    override val primaryLevel =
+        callbackEvents
+            .mapNotNull { it.onSignalStrengthChanged }
+            .map { it.signalStrength.level }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
+
+    override val dataConnectionState =
+        callbackEvents
+            .mapNotNull { it.onDataConnectionStateChanged }
+            .map { it.dataState.toDataConnectionType() }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), Disconnected)
+
+    override val dataActivityDirection =
+        callbackEvents
+            .mapNotNull { it.onDataActivity }
+            .map { it.direction.toMobileDataActivityModel() }
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                DataActivityModel(hasActivityIn = false, hasActivityOut = false)
+            )
+
+    override val carrierNetworkChangeActive =
+        callbackEvents
+            .mapNotNull { it.onCarrierNetworkChange }
+            .map { it.active }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val resolvedNetworkType =
+        callbackEvents
+            .mapNotNull { it.onDisplayInfoChanged }
+            .map {
+                if (it.telephonyDisplayInfo.overrideNetworkType != OVERRIDE_NETWORK_TYPE_NONE) {
+                    OverrideNetworkType(
+                        mobileMappingsProxy.toIconKeyOverride(
+                            it.telephonyDisplayInfo.overrideNetworkType
+                        )
+                    )
+                } else if (it.telephonyDisplayInfo.networkType != NETWORK_TYPE_UNKNOWN) {
+                    DefaultNetworkType(
+                        mobileMappingsProxy.toIconKey(it.telephonyDisplayInfo.networkType)
+                    )
+                } else {
+                    UnknownNetworkType
+                }
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), UnknownNetworkType)
+
     override val numberOfLevels =
         systemUiCarrierConfig.shouldInflateSignalStrength
             .map { shouldInflate ->
@@ -263,7 +287,10 @@
 
     override val cdmaRoaming: StateFlow<Boolean> =
         telephonyPollingEvent
-            .mapLatest { telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber != ERI_OFF }
+            .mapLatest {
+                val cdmaEri = telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber
+                cdmaEri == ERI_ON || cdmaEri == ERI_FLASH
+            }
             .stateIn(scope, SharingStarted.WhileSubscribed(), false)
 
     override val networkName: StateFlow<NetworkNameModel> =
@@ -281,7 +308,8 @@
     override val dataEnabled = run {
         val initial = telephonyManager.isDataConnectionAllowed
         callbackEvents
-            .mapNotNull { (it as? CallbackEvent.OnDataEnabledChanged)?.enabled }
+            .mapNotNull { it.onDataEnabledChanged }
+            .map { it.enabled }
             .stateIn(scope, SharingStarted.WhileSubscribed(), initial)
     }
 
@@ -325,12 +353,41 @@
  * Wrap every [TelephonyCallback] we care about in a data class so we can accept them in a single
  * shared flow and then split them back out into other flows.
  */
-private sealed interface CallbackEvent {
+sealed interface CallbackEvent {
+    data class OnCarrierNetworkChange(val active: Boolean) : CallbackEvent
+    data class OnDataActivity(val direction: Int) : CallbackEvent
+    data class OnDataConnectionStateChanged(val dataState: Int) : CallbackEvent
+    data class OnDataEnabledChanged(val enabled: Boolean) : CallbackEvent
+    data class OnDisplayInfoChanged(val telephonyDisplayInfo: TelephonyDisplayInfo) : CallbackEvent
     data class OnServiceStateChanged(val serviceState: ServiceState) : CallbackEvent
     data class OnSignalStrengthChanged(val signalStrength: SignalStrength) : CallbackEvent
-    data class OnDataConnectionStateChanged(val dataState: Int) : CallbackEvent
-    data class OnDataActivity(val direction: Int) : CallbackEvent
-    data class OnCarrierNetworkChange(val active: Boolean) : CallbackEvent
-    data class OnDisplayInfoChanged(val telephonyDisplayInfo: TelephonyDisplayInfo) : CallbackEvent
-    data class OnDataEnabledChanged(val enabled: Boolean) : CallbackEvent
+}
+
+/**
+ * A simple box type for 1-to-1 mapping of [CallbackEvent] to the batched event. Used in conjunction
+ * with [scan] to make sure we don't drop important callbacks due to late subscribers
+ */
+data class TelephonyCallbackState(
+    val onDataActivity: CallbackEvent.OnDataActivity? = null,
+    val onCarrierNetworkChange: CallbackEvent.OnCarrierNetworkChange? = null,
+    val onDataConnectionStateChanged: CallbackEvent.OnDataConnectionStateChanged? = null,
+    val onDataEnabledChanged: CallbackEvent.OnDataEnabledChanged? = null,
+    val onDisplayInfoChanged: CallbackEvent.OnDisplayInfoChanged? = null,
+    val onServiceStateChanged: CallbackEvent.OnServiceStateChanged? = null,
+    val onSignalStrengthChanged: CallbackEvent.OnSignalStrengthChanged? = null,
+) {
+    fun applyEvent(event: CallbackEvent): TelephonyCallbackState {
+        return when (event) {
+            is CallbackEvent.OnCarrierNetworkChange -> copy(onCarrierNetworkChange = event)
+            is CallbackEvent.OnDataActivity -> copy(onDataActivity = event)
+            is CallbackEvent.OnDataConnectionStateChanged ->
+                copy(onDataConnectionStateChanged = event)
+            is CallbackEvent.OnDataEnabledChanged -> copy(onDataEnabledChanged = event)
+            is CallbackEvent.OnDisplayInfoChanged -> copy(onDisplayInfoChanged = event)
+            is CallbackEvent.OnServiceStateChanged -> {
+                copy(onServiceStateChanged = event)
+            }
+            is CallbackEvent.OnSignalStrengthChanged -> copy(onSignalStrengthChanged = event)
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
index 53a208c..991b786 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
@@ -45,11 +45,11 @@
 import com.android.systemui.log.table.TableLogBuffer
 import com.android.systemui.log.table.logDiffsForTable
 import com.android.systemui.statusbar.pipeline.dagger.MobileSummaryLog
+import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
 import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel
 import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
-import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger
 import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
 import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
@@ -129,6 +129,7 @@
         val callback =
             object : SubscriptionManager.OnSubscriptionsChangedListener() {
                 override fun onSubscriptionsChanged() {
+                    logger.logOnSubscriptionsChanged()
                     trySend(Unit)
                 }
             }
@@ -266,6 +267,7 @@
                 val callback =
                     object : NetworkCallback(FLAG_INCLUDE_LOCATION_INFO) {
                         override fun onLost(network: Network) {
+                            logger.logOnLost(network, isDefaultNetworkCallback = true)
                             // Send a disconnected model when lost. Maybe should create a sealed
                             // type or null here?
                             trySend(MobileConnectivityModel())
@@ -275,6 +277,11 @@
                             network: Network,
                             caps: NetworkCapabilities
                         ) {
+                            logger.logOnCapabilitiesChanged(
+                                network,
+                                caps,
+                                isDefaultNetworkCallback = true,
+                            )
                             trySend(
                                 MobileConnectivityModel(
                                     isConnected = caps.hasTransport(TRANSPORT_CELLULAR),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
index 4caf2b0..7df6764 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
@@ -34,6 +34,7 @@
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.mapLatest
 import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.flow.stateIn
@@ -133,11 +134,9 @@
     override val isForceHidden: Flow<Boolean>,
     connectionRepository: MobileConnectionRepository,
 ) : MobileIconInteractor {
-    private val connectionInfo = connectionRepository.connectionInfo
-
     override val tableLogBuffer: TableLogBuffer = connectionRepository.tableLogBuffer
 
-    override val activity = connectionInfo.mapLatest { it.dataActivityDirection }
+    override val activity = connectionRepository.dataActivityDirection
 
     override val isConnected: Flow<Boolean> = defaultMobileConnectivity.mapLatest { it.isConnected }
 
@@ -155,11 +154,11 @@
     override val isDefaultDataEnabled = defaultSubscriptionHasDataEnabled
 
     override val networkName =
-        combine(connectionInfo, connectionRepository.networkName) { connection, networkName ->
-                if (
-                    networkName is NetworkNameModel.Default && connection.operatorAlphaShort != null
-                ) {
-                    NetworkNameModel.IntentDerived(connection.operatorAlphaShort)
+        combine(connectionRepository.operatorAlphaShort, connectionRepository.networkName) {
+                operatorAlphaShort,
+                networkName ->
+                if (networkName is NetworkNameModel.Default && operatorAlphaShort != null) {
+                    NetworkNameModel.IntentDerived(operatorAlphaShort)
                 } else {
                     networkName
                 }
@@ -173,19 +172,19 @@
     /** Observable for the current RAT indicator icon ([MobileIconGroup]) */
     override val networkTypeIconGroup: StateFlow<MobileIconGroup> =
         combine(
-                connectionInfo,
+                connectionRepository.resolvedNetworkType,
                 defaultMobileIconMapping,
                 defaultMobileIconGroup,
                 isDefault,
-            ) { info, mapping, defaultGroup, isDefault ->
+            ) { resolvedNetworkType, mapping, defaultGroup, isDefault ->
                 if (!isDefault) {
                     return@combine NOT_DEFAULT_DATA
                 }
 
-                when (info.resolvedNetworkType) {
+                when (resolvedNetworkType) {
                     is ResolvedNetworkType.CarrierMergedNetworkType ->
-                        info.resolvedNetworkType.iconGroupOverride
-                    else -> mapping[info.resolvedNetworkType.lookupKey] ?: defaultGroup
+                        resolvedNetworkType.iconGroupOverride
+                    else -> mapping[resolvedNetworkType.lookupKey] ?: defaultGroup
                 }
             }
             .distinctUntilChanged()
@@ -200,17 +199,19 @@
             }
             .stateIn(scope, SharingStarted.WhileSubscribed(), defaultMobileIconGroup.value)
 
-    override val isEmergencyOnly: StateFlow<Boolean> =
-        connectionInfo
-            .mapLatest { it.isEmergencyOnly }
-            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+    override val isEmergencyOnly = connectionRepository.isEmergencyOnly
 
     override val isRoaming: StateFlow<Boolean> =
-        combine(connectionInfo, connectionRepository.cdmaRoaming) { connection, cdmaRoaming ->
-                if (connection.carrierNetworkChangeActive) {
+        combine(
+                connectionRepository.carrierNetworkChangeActive,
+                connectionRepository.isGsm,
+                connectionRepository.isRoaming,
+                connectionRepository.cdmaRoaming,
+            ) { carrierNetworkChangeActive, isGsm, isRoaming, cdmaRoaming ->
+                if (carrierNetworkChangeActive) {
                     false
-                } else if (connection.isGsm) {
-                    connection.isRoaming
+                } else if (isGsm) {
+                    isRoaming
                 } else {
                     cdmaRoaming
                 }
@@ -218,12 +219,17 @@
             .stateIn(scope, SharingStarted.WhileSubscribed(), false)
 
     override val level: StateFlow<Int> =
-        combine(connectionInfo, alwaysUseCdmaLevel) { connection, alwaysUseCdmaLevel ->
+        combine(
+                connectionRepository.isGsm,
+                connectionRepository.primaryLevel,
+                connectionRepository.cdmaLevel,
+                alwaysUseCdmaLevel,
+            ) { isGsm, primaryLevel, cdmaLevel, alwaysUseCdmaLevel ->
                 when {
                     // GSM connections should never use the CDMA level
-                    connection.isGsm -> connection.primaryLevel
-                    alwaysUseCdmaLevel -> connection.cdmaLevel
-                    else -> connection.primaryLevel
+                    isGsm -> primaryLevel
+                    alwaysUseCdmaLevel -> cdmaLevel
+                    else -> primaryLevel
                 }
             }
             .stateIn(scope, SharingStarted.WhileSubscribed(), 0)
@@ -236,12 +242,9 @@
         )
 
     override val isDataConnected: StateFlow<Boolean> =
-        connectionInfo
-            .mapLatest { connection -> connection.dataConnectionState == Connected }
+        connectionRepository.dataConnectionState
+            .map { it == Connected }
             .stateIn(scope, SharingStarted.WhileSubscribed(), false)
 
-    override val isInService =
-        connectionRepository.connectionInfo
-            .mapLatest { it.isInService }
-            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+    override val isInService = connectionRepository.isInService
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt
index da63ab1..075e6ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt
@@ -22,7 +22,6 @@
 import com.android.systemui.statusbar.phone.StatusBarIconController
 import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
-import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger
 import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel
 import java.io.PrintWriter
 import javax.inject.Inject
@@ -55,17 +54,14 @@
     interactor: MobileIconsInteractor,
     private val iconController: StatusBarIconController,
     private val iconsViewModelFactory: MobileIconsViewModel.Factory,
-    private val logger: MobileInputLogger,
+    private val logger: MobileViewLogger,
     @Application private val scope: CoroutineScope,
     private val statusBarPipelineFlags: StatusBarPipelineFlags,
 ) : CoreStartable {
     private val mobileSubIds: Flow<List<Int>> =
-        interactor.filteredSubscriptions
-            .mapLatest { subscriptions ->
-                subscriptions.map { subscriptionModel -> subscriptionModel.subscriptionId }
-            }
-            .distinctUntilChanged()
-            .onEach { logger.logUiAdapterSubIdsUpdated(it) }
+        interactor.filteredSubscriptions.mapLatest { subscriptions ->
+            subscriptions.map { subscriptionModel -> subscriptionModel.subscriptionId }
+        }
 
     /**
      * We expose the list of tracked subscriptions as a flow of a list of ints, where each int is
@@ -75,7 +71,10 @@
      * NOTE: this should go away as the view presenter learns more about this data pipeline
      */
     private val mobileSubIdsState: StateFlow<List<Int>> =
-        mobileSubIds.stateIn(scope, SharingStarted.WhileSubscribed(), listOf())
+        mobileSubIds
+            .distinctUntilChanged()
+            .onEach { logger.logUiAdapterSubIdsUpdated(it) }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), listOf())
 
     /** In order to keep the logs tame, we will reuse the same top-level mobile icons view model */
     val mobileIconsViewModel = iconsViewModelFactory.create(mobileSubIdsState)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt
new file mode 100644
index 0000000..90dff23
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.ui
+
+import android.view.View
+import com.android.systemui.Dumpable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.statusbar.pipeline.dagger.MobileViewLog
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.LocationBasedMobileViewModel
+import java.io.PrintWriter
+import javax.inject.Inject
+
+/** Logs for changes with the new mobile views. */
+@SysUISingleton
+class MobileViewLogger
+@Inject
+constructor(
+    @MobileViewLog private val buffer: LogBuffer,
+    dumpManager: DumpManager,
+) : Dumpable {
+    init {
+        dumpManager.registerNormalDumpable(this)
+    }
+
+    private val collectionStatuses = mutableMapOf<String, Boolean>()
+
+    fun logUiAdapterSubIdsUpdated(subs: List<Int>) {
+        buffer.log(
+            TAG,
+            LogLevel.INFO,
+            { str1 = subs.toString() },
+            { "Sub IDs in MobileUiAdapter updated internally: $str1" },
+        )
+    }
+
+    fun logUiAdapterSubIdsSentToIconController(subs: List<Int>) {
+        buffer.log(
+            TAG,
+            LogLevel.INFO,
+            { str1 = subs.toString() },
+            { "Sub IDs in MobileUiAdapter being sent to icon controller: $str1" },
+        )
+    }
+
+    fun logNewViewBinding(view: View, viewModel: LocationBasedMobileViewModel) {
+        buffer.log(
+            TAG,
+            LogLevel.INFO,
+            {
+                str1 = view.getIdForLogging()
+                str2 = viewModel.getIdForLogging()
+                str3 = viewModel.locationName
+            },
+            { "New view binding. viewId=$str1, viewModelId=$str2, viewModelLocation=$str3" },
+        )
+    }
+
+    fun logCollectionStarted(view: View, viewModel: LocationBasedMobileViewModel) {
+        collectionStatuses[view.getIdForLogging()] = true
+        buffer.log(
+            TAG,
+            LogLevel.INFO,
+            {
+                str1 = view.getIdForLogging()
+                str2 = viewModel.getIdForLogging()
+                str3 = viewModel.locationName
+            },
+            { "Collection started. viewId=$str1, viewModelId=$str2, viewModelLocation=$str3" },
+        )
+    }
+
+    fun logCollectionStopped(view: View, viewModel: LocationBasedMobileViewModel) {
+        collectionStatuses[view.getIdForLogging()] = false
+        buffer.log(
+            TAG,
+            LogLevel.INFO,
+            {
+                str1 = view.getIdForLogging()
+                str2 = viewModel.getIdForLogging()
+                str3 = viewModel.locationName
+            },
+            { "Collection stopped. viewId=$str1, viewModelId=$str2, viewModelLocation=$str3" },
+        )
+    }
+
+    override fun dump(pw: PrintWriter, args: Array<out String>) {
+        pw.println("Collection statuses per view:---")
+        collectionStatuses.forEach { viewId, isCollecting ->
+            pw.println("viewId=$viewId, isCollecting=$isCollecting")
+        }
+    }
+
+    companion object {
+        fun Any.getIdForLogging(): String {
+            // The identityHashCode is guaranteed to be constant for the lifetime of the object.
+            return Integer.toHexString(System.identityHashCode(this))
+        }
+    }
+}
+
+private const val TAG = "MobileViewLogger"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/VerboseMobileViewLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/VerboseMobileViewLogger.kt
new file mode 100644
index 0000000..f67bc8f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/VerboseMobileViewLogger.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.ui
+
+import android.view.View
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.statusbar.pipeline.dagger.VerboseMobileViewLog
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger.Companion.getIdForLogging
+import com.android.systemui.statusbar.pipeline.mobile.ui.model.SignalIconModel
+import javax.inject.Inject
+
+/**
+ * Logs for **verbose** changes with the new mobile views.
+ *
+ * This is a hopefully temporary log until we resolve some open bugs (b/267236367, b/269565345,
+ * b/270300839).
+ */
+@SysUISingleton
+class VerboseMobileViewLogger
+@Inject
+constructor(
+    @VerboseMobileViewLog private val buffer: LogBuffer,
+) {
+    fun logBinderReceivedSignalIcon(parentView: View, subId: Int, icon: SignalIconModel) {
+        buffer.log(
+            TAG,
+            LogLevel.VERBOSE,
+            {
+                str1 = parentView.getIdForLogging()
+                int1 = subId
+                int2 = icon.level
+                bool1 = icon.showExclamationMark
+            },
+            {
+                "Binder[subId=$int1, viewId=$str1] received new signal icon: " +
+                    "level=$int2 showExclamation=$bool1"
+            },
+        )
+    }
+
+    fun logBinderReceivedNetworkTypeIcon(parentView: View, subId: Int, icon: Icon.Resource?) {
+        buffer.log(
+            TAG,
+            LogLevel.VERBOSE,
+            {
+                str1 = parentView.getIdForLogging()
+                int1 = subId
+                bool1 = icon != null
+                int2 = icon?.res ?: -1
+            },
+            {
+                "Binder[subId=$int1, viewId=$str1] received new network type icon: " +
+                    if (bool1) "resId=$int2" else "null"
+            },
+        )
+    }
+}
+
+private const val TAG = "VerboseMobileViewLogger"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt
index db585e6..5b7d45b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt
@@ -36,8 +36,10 @@
 import com.android.systemui.statusbar.StatusBarIconView.STATE_DOT
 import com.android.systemui.statusbar.StatusBarIconView.STATE_HIDDEN
 import com.android.systemui.statusbar.StatusBarIconView.STATE_ICON
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger
 import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.LocationBasedMobileViewModel
 import com.android.systemui.statusbar.pipeline.shared.ui.binder.ModernStatusBarViewBinding
+import kotlinx.coroutines.awaitCancellation
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.launch
@@ -48,6 +50,7 @@
     fun bind(
         view: ViewGroup,
         viewModel: LocationBasedMobileViewModel,
+        logger: MobileViewLogger,
     ): ModernStatusBarViewBinding {
         val mobileGroupView = view.requireViewById<ViewGroup>(R.id.mobile_group)
         val activityContainer = view.requireViewById<View>(R.id.inout_container)
@@ -70,8 +73,13 @@
         val iconTint: MutableStateFlow<Int> = MutableStateFlow(viewModel.defaultColor)
         val decorTint: MutableStateFlow<Int> = MutableStateFlow(viewModel.defaultColor)
 
+        var isCollecting: Boolean = false
+
         view.repeatWhenAttached {
             repeatOnLifecycle(Lifecycle.State.STARTED) {
+                logger.logCollectionStarted(view, viewModel)
+                isCollecting = true
+
                 launch {
                     visibilityState.collect { state ->
                         when (state) {
@@ -96,6 +104,11 @@
                 // Set the icon for the triangle
                 launch {
                     viewModel.icon.distinctUntilChanged().collect { icon ->
+                        viewModel.verboseLogger?.logBinderReceivedSignalIcon(
+                            view,
+                            viewModel.subscriptionId,
+                            icon,
+                        )
                         mobileDrawable.level =
                             SignalDrawable.getState(
                                 icon.level,
@@ -114,6 +127,11 @@
                 // Set the network type icon
                 launch {
                     viewModel.networkTypeIcon.distinctUntilChanged().collect { dataTypeId ->
+                        viewModel.verboseLogger?.logBinderReceivedNetworkTypeIcon(
+                            view,
+                            viewModel.subscriptionId,
+                            dataTypeId,
+                        )
                         dataTypeId?.let { IconViewBinder.bind(dataTypeId, networkTypeView) }
                         networkTypeView.visibility = if (dataTypeId != null) VISIBLE else GONE
                     }
@@ -150,6 +168,13 @@
                 }
 
                 launch { decorTint.collect { tint -> dotView.setDecorColor(tint) } }
+
+                try {
+                    awaitCancellation()
+                } finally {
+                    isCollecting = false
+                    logger.logCollectionStopped(view, viewModel)
+                }
             }
         }
 
@@ -175,6 +200,10 @@
                 }
                 decorTint.value = newTint
             }
+
+            override fun isCollecting(): Boolean {
+                return isCollecting
+            }
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt
index ed9a188..4144293d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt
@@ -20,6 +20,8 @@
 import android.util.AttributeSet
 import android.view.LayoutInflater
 import com.android.systemui.R
+import com.android.systemui.statusbar.StatusBarIconView.getVisibleStateString
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger
 import com.android.systemui.statusbar.pipeline.mobile.ui.binder.MobileIconBinder
 import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.LocationBasedMobileViewModel
 import com.android.systemui.statusbar.pipeline.shared.ui.view.ModernStatusBarView
@@ -31,6 +33,15 @@
 
     var subId: Int = -1
 
+    override fun toString(): String {
+        return "ModernStatusBarMobileView(" +
+            "slot='$slot', " +
+            "subId=$subId, " +
+            "isCollecting=${binding.isCollecting()}, " +
+            "visibleState=${getVisibleStateString(visibleState)}); " +
+            "viewString=${super.toString()}"
+    }
+
     companion object {
 
         /**
@@ -40,6 +51,7 @@
         @JvmStatic
         fun constructAndBind(
             context: Context,
+            logger: MobileViewLogger,
             slot: String,
             viewModel: LocationBasedMobileViewModel,
         ): ModernStatusBarMobileView {
@@ -48,7 +60,8 @@
                     as ModernStatusBarMobileView)
                 .also {
                     it.subId = viewModel.subscriptionId
-                    it.initView(slot) { MobileIconBinder.bind(it, viewModel) }
+                    it.initView(slot) { MobileIconBinder.bind(it, viewModel, logger) }
+                    logger.logNewViewBinding(it, viewModel)
                 }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileViewModel.kt
index 8e103f7..f775940 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileViewModel.kt
@@ -19,6 +19,7 @@
 import android.graphics.Color
 import com.android.systemui.statusbar.phone.StatusBarLocation
 import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
+import com.android.systemui.statusbar.pipeline.mobile.ui.VerboseMobileViewLogger
 
 /**
  * A view model for an individual mobile icon that embeds the notion of a [StatusBarLocation]. This
@@ -26,11 +27,15 @@
  *
  * @param commonImpl for convenience, this class wraps a base interface that can provides all of the
  *   common implementations between locations. See [MobileIconViewModel]
+ * @property locationName the name of the location of this VM, used for logging.
+ * @property verboseLogger an optional logger to log extremely verbose view updates.
  */
 abstract class LocationBasedMobileViewModel(
     val commonImpl: MobileIconViewModelCommon,
     statusBarPipelineFlags: StatusBarPipelineFlags,
     debugTint: Int,
+    val locationName: String,
+    val verboseLogger: VerboseMobileViewLogger?,
 ) : MobileIconViewModelCommon by commonImpl {
     val useDebugColoring: Boolean = statusBarPipelineFlags.useDebugColoring()
 
@@ -45,11 +50,16 @@
         fun viewModelForLocation(
             commonImpl: MobileIconViewModelCommon,
             statusBarPipelineFlags: StatusBarPipelineFlags,
+            verboseMobileViewLogger: VerboseMobileViewLogger,
             loc: StatusBarLocation,
         ): LocationBasedMobileViewModel =
             when (loc) {
                 StatusBarLocation.HOME ->
-                    HomeMobileIconViewModel(commonImpl, statusBarPipelineFlags)
+                    HomeMobileIconViewModel(
+                        commonImpl,
+                        statusBarPipelineFlags,
+                        verboseMobileViewLogger,
+                    )
                 StatusBarLocation.KEYGUARD ->
                     KeyguardMobileIconViewModel(commonImpl, statusBarPipelineFlags)
                 StatusBarLocation.QS -> QsMobileIconViewModel(commonImpl, statusBarPipelineFlags)
@@ -60,20 +70,41 @@
 class HomeMobileIconViewModel(
     commonImpl: MobileIconViewModelCommon,
     statusBarPipelineFlags: StatusBarPipelineFlags,
+    verboseMobileViewLogger: VerboseMobileViewLogger,
 ) :
     MobileIconViewModelCommon,
-    LocationBasedMobileViewModel(commonImpl, statusBarPipelineFlags, debugTint = Color.CYAN)
+    LocationBasedMobileViewModel(
+        commonImpl,
+        statusBarPipelineFlags,
+        debugTint = Color.CYAN,
+        locationName = "Home",
+        verboseMobileViewLogger,
+    )
 
 class QsMobileIconViewModel(
     commonImpl: MobileIconViewModelCommon,
     statusBarPipelineFlags: StatusBarPipelineFlags,
 ) :
     MobileIconViewModelCommon,
-    LocationBasedMobileViewModel(commonImpl, statusBarPipelineFlags, debugTint = Color.GREEN)
+    LocationBasedMobileViewModel(
+        commonImpl,
+        statusBarPipelineFlags,
+        debugTint = Color.GREEN,
+        locationName = "QS",
+        // Only do verbose logging for the Home location.
+        verboseLogger = null,
+    )
 
 class KeyguardMobileIconViewModel(
     commonImpl: MobileIconViewModelCommon,
     statusBarPipelineFlags: StatusBarPipelineFlags,
 ) :
     MobileIconViewModelCommon,
-    LocationBasedMobileViewModel(commonImpl, statusBarPipelineFlags, debugTint = Color.MAGENTA)
+    LocationBasedMobileViewModel(
+        commonImpl,
+        statusBarPipelineFlags,
+        debugTint = Color.MAGENTA,
+        locationName = "Keyguard",
+        // Only do verbose logging for the Home location.
+        verboseLogger = null,
+    )
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
index 0496278..dbb534b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
@@ -49,7 +49,7 @@
     val contentDescription: Flow<ContentDescription>
     val roaming: Flow<Boolean>
     /** The RAT icon (LTE, 3G, 5G, etc) to be displayed. Null if we shouldn't show anything */
-    val networkTypeIcon: Flow<Icon?>
+    val networkTypeIcon: Flow<Icon.Resource?>
     val activityInVisible: Flow<Boolean>
     val activityOutVisible: Flow<Boolean>
     val activityContainerVisible: Flow<Boolean>
@@ -161,7 +161,7 @@
             )
             .stateIn(scope, SharingStarted.WhileSubscribed(), false)
 
-    override val networkTypeIcon: Flow<Icon?> =
+    override val networkTypeIcon: Flow<Icon.Resource?> =
         combine(
                 iconInteractor.networkTypeIconGroup,
                 showNetworkTypeIcon,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
index 8cb52af..2b90065 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
@@ -23,6 +23,8 @@
 import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
 import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger
+import com.android.systemui.statusbar.pipeline.mobile.ui.VerboseMobileViewLogger
 import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernStatusBarMobileView
 import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
 import javax.inject.Inject
@@ -39,6 +41,8 @@
 @Inject
 constructor(
     val subscriptionIdsFlow: StateFlow<List<Int>>,
+    val logger: MobileViewLogger,
+    private val verboseLogger: VerboseMobileViewLogger,
     private val interactor: MobileIconsInteractor,
     private val airplaneModeInteractor: AirplaneModeInteractor,
     private val constants: ConnectivityConstants,
@@ -66,6 +70,7 @@
         return LocationBasedMobileViewModel.viewModelForLocation(
             common,
             statusBarPipelineFlags,
+            verboseLogger,
             location,
         )
     }
@@ -79,6 +84,8 @@
     class Factory
     @Inject
     constructor(
+        private val logger: MobileViewLogger,
+        private val verboseLogger: VerboseMobileViewLogger,
         private val interactor: MobileIconsInteractor,
         private val airplaneModeInteractor: AirplaneModeInteractor,
         private val constants: ConnectivityConstants,
@@ -88,6 +95,8 @@
         fun create(subscriptionIdsFlow: StateFlow<List<Int>>): MobileIconsViewModel {
             return MobileIconsViewModel(
                 subscriptionIdsFlow,
+                logger,
+                verboseLogger,
                 interactor,
                 airplaneModeInteractor,
                 constants,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/LoggerHelper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/LoggerHelper.kt
index 6f29e33..a96e8ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/LoggerHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/LoggerHelper.kt
@@ -38,11 +38,24 @@
                 int1 = network.getNetId()
                 str1 = networkCapabilities.toString()
             },
-            { "onCapabilitiesChanged[default=$bool1]: net=$int1 capabilities=$str1" }
+            { "on${if (bool1) "Default" else ""}CapabilitiesChanged: net=$int1 capabilities=$str1" }
         )
     }
 
-    fun logOnLost(buffer: LogBuffer, tag: String, network: Network) {
-        buffer.log(tag, LogLevel.INFO, { int1 = network.getNetId() }, { "onLost: net=$int1" })
+    fun logOnLost(
+        buffer: LogBuffer,
+        tag: String,
+        network: Network,
+        isDefaultNetworkCallback: Boolean,
+    ) {
+        buffer.log(
+            tag,
+            LogLevel.INFO,
+            {
+                int1 = network.getNetId()
+                bool1 = isDefaultNetworkCallback
+            },
+            { "on${if (bool1) "Default" else ""}Lost: net=$int1" }
+        )
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/ModernStatusBarViewBinding.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/ModernStatusBarViewBinding.kt
index f67876b..81f8683 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/ModernStatusBarViewBinding.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/ModernStatusBarViewBinding.kt
@@ -37,4 +37,7 @@
 
     /** Notifies that the decor tint has been updated (used only for the dot). */
     fun onDecorTintChanged(newTint: Int)
+
+    /** Returns true if the binding between the view and view-model is currently collecting. */
+    fun isCollecting(): Boolean
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarView.kt
index b1e2812..1a13404 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarView.kt
@@ -36,7 +36,7 @@
     BaseStatusBarFrameLayout(context, attrs) {
 
     private lateinit var slot: String
-    private lateinit var binding: ModernStatusBarViewBinding
+    internal lateinit var binding: ModernStatusBarViewBinding
 
     @StatusBarIconView.VisibleState
     private var iconVisibleState: Int = STATE_HIDDEN
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
index ee58160..b5e7b7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
@@ -128,6 +128,7 @@
                         }
 
                         override fun onLost(network: Network) {
+                            logger.logOnLost(network, isDefaultNetworkCallback = true)
                             // The system no longer has a default network, so wifi is definitely not
                             // default.
                             trySend(false)
@@ -179,7 +180,7 @@
                         }
 
                         override fun onLost(network: Network) {
-                            logger.logOnLost(network)
+                            logger.logOnLost(network, isDefaultNetworkCallback = false)
 
                             wifiNetworkChangeEvents.tryEmit(Unit)
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt
index a32e475..bb0b166 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt
@@ -48,8 +48,8 @@
         )
     }
 
-    fun logOnLost(network: Network) {
-        LoggerHelper.logOnLost(buffer, TAG, network)
+    fun logOnLost(network: Network, isDefaultNetworkCallback: Boolean) {
+        LoggerHelper.logOnLost(buffer, TAG, network, isDefaultNetworkCallback)
     }
 
     fun logIntent(intentName: String) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt
index 2aff12c..9e8c814 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt
@@ -34,6 +34,7 @@
 import com.android.systemui.statusbar.pipeline.wifi.ui.model.WifiIcon
 import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.LocationBasedWifiViewModel
 import kotlinx.coroutines.InternalCoroutinesApi
+import kotlinx.coroutines.awaitCancellation
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.flow.distinctUntilChanged
@@ -74,8 +75,12 @@
         val iconTint: MutableStateFlow<Int> = MutableStateFlow(viewModel.defaultColor)
         val decorTint: MutableStateFlow<Int> = MutableStateFlow(viewModel.defaultColor)
 
+        var isCollecting: Boolean = false
+
         view.repeatWhenAttached {
             repeatOnLifecycle(Lifecycle.State.STARTED) {
+                isCollecting = true
+
                 launch {
                     visibilityState.collect { visibilityState ->
                         groupView.isVisible = visibilityState == STATE_ICON
@@ -127,6 +132,12 @@
                         airplaneSpacer.isVisible = visible
                     }
                 }
+
+                try {
+                    awaitCancellation()
+                } finally {
+                    isCollecting = false
+                }
             }
         }
 
@@ -152,6 +163,10 @@
                 }
                 decorTint.value = newTint
             }
+
+            override fun isCollecting(): Boolean {
+                return isCollecting
+            }
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt
index 7a73486..f23e102 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt
@@ -21,6 +21,7 @@
 import android.util.AttributeSet
 import android.view.LayoutInflater
 import com.android.systemui.R
+import com.android.systemui.statusbar.StatusBarIconView
 import com.android.systemui.statusbar.pipeline.shared.ui.view.ModernStatusBarView
 import com.android.systemui.statusbar.pipeline.wifi.ui.binder.WifiViewBinder
 import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.LocationBasedWifiViewModel
@@ -33,6 +34,15 @@
     context: Context,
     attrs: AttributeSet?,
 ) : ModernStatusBarView(context, attrs) {
+
+    override fun toString(): String {
+        return "ModernStatusBarWifiView(" +
+            "slot='$slot', " +
+            "isCollecting=${binding.isCollecting()}, " +
+            "visibleState=${StatusBarIconView.getVisibleStateString(visibleState)}); " +
+            "viewString=${super.toString()}"
+    }
+
     companion object {
         /**
          * Inflates a new instance of [ModernStatusBarWifiView], binds it to a view model, and
@@ -45,12 +55,9 @@
             slot: String,
             wifiViewModel: LocationBasedWifiViewModel,
         ): ModernStatusBarWifiView {
-            return (
-                LayoutInflater.from(context).inflate(R.layout.new_status_bar_wifi_group, null)
-                    as ModernStatusBarWifiView
-                ).also {
-                    it.initView(slot) { WifiViewBinder.bind(it, wifiViewModel) }
-                }
+            return (LayoutInflater.from(context).inflate(R.layout.new_status_bar_wifi_group, null)
+                    as ModernStatusBarWifiView)
+                .also { it.initView(slot) { WifiViewBinder.bind(it, wifiViewModel) } }
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
index 1057231..4b24e7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
@@ -124,7 +124,8 @@
                     isDefault -> icon
                     wifiConstants.alwaysShowIconIfEnabled -> icon
                     !connectivityConstants.hasDataCapabilities -> icon
-                    wifiNetwork is WifiNetworkModel.Active && wifiNetwork.isValidated -> icon
+                    // See b/272509965: Even if we have an active and validated wifi network, we
+                    // don't want to show the icon if wifi isn't the default network.
                     else -> WifiIcon.Hidden
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
index 2ee5232..654ba04 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
@@ -57,6 +57,8 @@
 import java.util.List;
 import java.util.concurrent.atomic.AtomicReference;
 
+import javax.annotation.concurrent.GuardedBy;
+
 /**
  * Default implementation of a {@link BatteryController}. This controller monitors for battery
  * level change events that are broadcasted by the system.
@@ -94,7 +96,10 @@
     private boolean mTestMode = false;
     @VisibleForTesting
     boolean mHasReceivedBattery = false;
+    @GuardedBy("mEstimateLock")
     private Estimate mEstimate;
+    private final Object mEstimateLock = new Object();
+
     private boolean mFetchingEstimate = false;
 
     // Use AtomicReference because we may request it from a different thread
@@ -321,7 +326,7 @@
 
     @Nullable
     private String generateTimeRemainingString() {
-        synchronized (mFetchCallbacks) {
+        synchronized (mEstimateLock) {
             if (mEstimate == null) {
                 return null;
             }
@@ -340,7 +345,7 @@
         mFetchingEstimate = true;
         mBgHandler.post(() -> {
             // Only fetch the estimate if they are enabled
-            synchronized (mFetchCallbacks) {
+            synchronized (mEstimateLock) {
                 mEstimate = null;
                 if (mEstimates.isHybridNotificationEnabled()) {
                     updateEstimate();
@@ -363,6 +368,7 @@
     }
 
     @WorkerThread
+    @GuardedBy("mEstimateLock")
     private void updateEstimate() {
         Assert.isNotMainThread();
         // if the estimate has been cached we can just use that, otherwise get a new one and
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedController.java
index 3944c8c..0d09fc1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedController.java
@@ -21,7 +21,8 @@
 /**
  * Controller to cache in process the state of the device provisioning.
  * <p>
- * This controller keeps track of the values of device provisioning and user setup complete
+ * This controller keeps track of the values of device provisioning, user setup complete, and
+ * whether Factory Reset Protection is active.
  */
 public interface DeviceProvisionedController extends CallbackController<DeviceProvisionedListener> {
 
@@ -49,6 +50,9 @@
      */
     boolean isCurrentUserSetup();
 
+    /** Returns true when Factory Reset Protection is locking the device. */
+    boolean isFrpActive();
+
     /**
      * Interface to provide calls when the values tracked change
      */
@@ -69,5 +73,10 @@
          * Call when some user changes from not provisioned to provisioned
          */
         default void onUserSetupChanged() { }
+
+        /**
+         * Called when the state of FRP changes.
+         */
+        default void onFrpActiveChanged() {}
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.kt
index a6b7d9c5..32c64f4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.kt
@@ -60,9 +60,11 @@
     }
 
     private val deviceProvisionedUri = globalSettings.getUriFor(Settings.Global.DEVICE_PROVISIONED)
+    private val frpActiveUri = secureSettings.getUriFor(Settings.Secure.SECURE_FRP_MODE)
     private val userSetupUri = secureSettings.getUriFor(Settings.Secure.USER_SETUP_COMPLETE)
 
     private val deviceProvisioned = AtomicBoolean(false)
+    private val frpActive = AtomicBoolean(false)
     @GuardedBy("lock")
     private val userSetupComplete = SparseBooleanArray()
     @GuardedBy("lock")
@@ -89,11 +91,15 @@
             userId: Int
         ) {
             val updateDeviceProvisioned = deviceProvisionedUri in uris
+            val updateFrp = frpActiveUri in uris
             val updateUser = if (userSetupUri in uris) userId else NO_USERS
-            updateValues(updateDeviceProvisioned, updateUser)
+            updateValues(updateDeviceProvisioned, updateFrp, updateUser)
             if (updateDeviceProvisioned) {
                 onDeviceProvisionedChanged()
             }
+            if (updateFrp) {
+                onFrpActiveChanged()
+            }
             if (updateUser != NO_USERS) {
                 onUserSetupChanged()
             }
@@ -103,7 +109,7 @@
     private val userChangedCallback = object : UserTracker.Callback {
         @WorkerThread
         override fun onUserChanged(newUser: Int, userContext: Context) {
-            updateValues(updateDeviceProvisioned = false, updateUser = newUser)
+            updateValues(updateDeviceProvisioned = false, updateFrp = false, updateUser = newUser)
             onUserSwitched()
         }
 
@@ -125,19 +131,27 @@
         updateValues()
         userTracker.addCallback(userChangedCallback, backgroundExecutor)
         globalSettings.registerContentObserver(deviceProvisionedUri, observer)
+        globalSettings.registerContentObserver(frpActiveUri, observer)
         secureSettings.registerContentObserverForUser(userSetupUri, observer, UserHandle.USER_ALL)
     }
 
     @WorkerThread
-    private fun updateValues(updateDeviceProvisioned: Boolean = true, updateUser: Int = ALL_USERS) {
+    private fun updateValues(
+        updateDeviceProvisioned: Boolean = true,
+        updateFrp: Boolean = true,
+        updateUser: Int = ALL_USERS
+    ) {
         if (updateDeviceProvisioned) {
             deviceProvisioned
                     .set(globalSettings.getInt(Settings.Global.DEVICE_PROVISIONED, 0) != 0)
         }
+        if (updateFrp) {
+            frpActive.set(globalSettings.getInt(Settings.Secure.SECURE_FRP_MODE, 0) != 0)
+        }
         synchronized(lock) {
             if (updateUser == ALL_USERS) {
-                val N = userSetupComplete.size()
-                for (i in 0 until N) {
+                val n = userSetupComplete.size()
+                for (i in 0 until n) {
                     val user = userSetupComplete.keyAt(i)
                     val value = secureSettings
                             .getIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 0, user) != 0
@@ -172,6 +186,10 @@
         return deviceProvisioned.get()
     }
 
+    override fun isFrpActive(): Boolean {
+        return frpActive.get()
+    }
+
     override fun isUserSetup(user: Int): Boolean {
         val index = synchronized(lock) {
             userSetupComplete.indexOfKey(user)
@@ -196,7 +214,13 @@
 
     override fun onDeviceProvisionedChanged() {
         dispatchChange(
-                DeviceProvisionedController.DeviceProvisionedListener::onDeviceProvisionedChanged
+            DeviceProvisionedController.DeviceProvisionedListener::onDeviceProvisionedChanged
+        )
+    }
+
+    override fun onFrpActiveChanged() {
+        dispatchChange(
+            DeviceProvisionedController.DeviceProvisionedListener::onFrpActiveChanged
         )
     }
 
@@ -221,6 +245,7 @@
 
     override fun dump(pw: PrintWriter, args: Array<out String>) {
         pw.println("Device provisioned: ${deviceProvisioned.get()}")
+        pw.println("Factory Reset Protection active: ${frpActive.get()}")
         synchronized(lock) {
             pw.println("User setup complete: $userSetupComplete")
             pw.println("Listeners: $listeners")
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java
index 7acdaff..01fabcc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java
@@ -22,13 +22,18 @@
 import android.annotation.Nullable;
 import android.hardware.devicestate.DeviceStateManager;
 import android.os.Trace;
-import android.util.Log;
+import android.util.IndentingPrintWriter;
+
+import androidx.annotation.NonNull;
 
 import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager;
+import com.android.systemui.Dumpable;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.dump.DumpManager;
 import com.android.systemui.util.wrapper.RotationPolicyWrapper;
 
+import java.io.PrintWriter;
 import java.util.concurrent.Executor;
 
 import javax.inject.Inject;
@@ -39,19 +44,19 @@
  */
 @SysUISingleton
 public final class DeviceStateRotationLockSettingController
-        implements Listenable, RotationLockController.RotationLockControllerCallback {
-
-    private static final String TAG = "DSRotateLockSettingCon";
+        implements Listenable, RotationLockController.RotationLockControllerCallback, Dumpable {
 
     private final RotationPolicyWrapper mRotationPolicyWrapper;
     private final DeviceStateManager mDeviceStateManager;
     private final Executor mMainExecutor;
     private final DeviceStateRotationLockSettingsManager mDeviceStateRotationLockSettingsManager;
+    private final DeviceStateRotationLockSettingControllerLogger mLogger;
 
     // On registration for DeviceStateCallback, we will receive a callback with the current state
     // and this will be initialized.
     private int mDeviceState = -1;
-    @Nullable private DeviceStateManager.DeviceStateCallback mDeviceStateCallback;
+    @Nullable
+    private DeviceStateManager.DeviceStateCallback mDeviceStateCallback;
     private DeviceStateRotationLockSettingsManager.DeviceStateRotationLockSettingsListener
             mDeviceStateRotationLockSettingsListener;
 
@@ -60,21 +65,27 @@
             RotationPolicyWrapper rotationPolicyWrapper,
             DeviceStateManager deviceStateManager,
             @Main Executor executor,
-            DeviceStateRotationLockSettingsManager deviceStateRotationLockSettingsManager) {
+            DeviceStateRotationLockSettingsManager deviceStateRotationLockSettingsManager,
+            DeviceStateRotationLockSettingControllerLogger logger,
+            DumpManager dumpManager) {
         mRotationPolicyWrapper = rotationPolicyWrapper;
         mDeviceStateManager = deviceStateManager;
         mMainExecutor = executor;
         mDeviceStateRotationLockSettingsManager = deviceStateRotationLockSettingsManager;
+        mLogger = logger;
+        dumpManager.registerDumpable(this);
     }
 
     @Override
     public void setListening(boolean listening) {
+        mLogger.logListeningChange(listening);
         if (listening) {
             // Note that this is called once with the initial state of the device, even if there
             // is no user action.
             mDeviceStateCallback = this::updateDeviceState;
             mDeviceStateManager.registerCallback(mMainExecutor, mDeviceStateCallback);
-            mDeviceStateRotationLockSettingsListener = () -> readPersistedSetting(mDeviceState);
+            mDeviceStateRotationLockSettingsListener = () ->
+                    readPersistedSetting("deviceStateRotationLockChange", mDeviceState);
             mDeviceStateRotationLockSettingsManager.registerListener(
                     mDeviceStateRotationLockSettingsListener);
         } else {
@@ -89,35 +100,28 @@
     }
 
     @Override
-    public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible) {
-        if (mDeviceState == -1) {
-            Log.wtf(TAG, "Device state was not initialized.");
+    public void onRotationLockStateChanged(boolean newRotationLocked, boolean affordanceVisible) {
+        int deviceState = mDeviceState;
+        boolean currentRotationLocked = mDeviceStateRotationLockSettingsManager
+                .isRotationLocked(deviceState);
+        mLogger.logRotationLockStateChanged(deviceState, newRotationLocked, currentRotationLocked);
+        if (deviceState == -1) {
             return;
         }
-
-        if (rotationLocked
-                == mDeviceStateRotationLockSettingsManager.isRotationLocked(mDeviceState)) {
-            Log.v(TAG, "Rotation lock same as the current setting, no need to update.");
+        if (newRotationLocked == currentRotationLocked) {
             return;
         }
-
-        saveNewRotationLockSetting(rotationLocked);
+        saveNewRotationLockSetting(newRotationLocked);
     }
 
     private void saveNewRotationLockSetting(boolean isRotationLocked) {
-        Log.v(
-                TAG,
-                "saveNewRotationLockSetting [state="
-                        + mDeviceState
-                        + "] [isRotationLocked="
-                        + isRotationLocked
-                        + "]");
-
-        mDeviceStateRotationLockSettingsManager.updateSetting(mDeviceState, isRotationLocked);
+        int deviceState = mDeviceState;
+        mLogger.logSaveNewRotationLockSetting(isRotationLocked, deviceState);
+        mDeviceStateRotationLockSettingsManager.updateSetting(deviceState, isRotationLocked);
     }
 
     private void updateDeviceState(int state) {
-        Log.v(TAG, "updateDeviceState [state=" + state + "]");
+        mLogger.logUpdateDeviceState(mDeviceState, state);
         if (Trace.isEnabled()) {
             Trace.traceBegin(
                     Trace.TRACE_TAG_APP, "updateDeviceState [state=" + state + "]");
@@ -127,22 +131,26 @@
                 return;
             }
 
-            readPersistedSetting(state);
+            readPersistedSetting("updateDeviceState", state);
         } finally {
             Trace.endSection();
         }
     }
 
-    private void readPersistedSetting(int state) {
+    private void readPersistedSetting(String caller, int state) {
         int rotationLockSetting =
                 mDeviceStateRotationLockSettingsManager.getRotationLockSetting(state);
+        boolean shouldBeLocked = rotationLockSetting == DEVICE_STATE_ROTATION_LOCK_LOCKED;
+        boolean isLocked = mRotationPolicyWrapper.isRotationLocked();
+
+        mLogger.readPersistedSetting(caller, state, rotationLockSetting, shouldBeLocked, isLocked);
+
         if (rotationLockSetting == DEVICE_STATE_ROTATION_LOCK_IGNORED) {
             // This should not happen. Device states that have an ignored setting, should also
             // specify a fallback device state which is not ignored.
             // We won't handle this device state. The same rotation lock setting as before should
             // apply and any changes to the rotation lock setting will be written for the previous
             // valid device state.
-            Log.w(TAG, "Missing fallback. Ignoring new device state: " + state);
             return;
         }
 
@@ -150,9 +158,18 @@
         mDeviceState = state;
 
         // Update the rotation policy, if needed, for this new device state
-        boolean newRotationLockSetting = rotationLockSetting == DEVICE_STATE_ROTATION_LOCK_LOCKED;
-        if (newRotationLockSetting != mRotationPolicyWrapper.isRotationLocked()) {
-            mRotationPolicyWrapper.setRotationLock(newRotationLockSetting);
+        if (shouldBeLocked != isLocked) {
+            mRotationPolicyWrapper.setRotationLock(shouldBeLocked);
         }
     }
+
+    @Override
+    public void dump(@NonNull PrintWriter printWriter, @NonNull String[] args) {
+        IndentingPrintWriter pw = new IndentingPrintWriter(printWriter);
+        mDeviceStateRotationLockSettingsManager.dump(pw);
+        pw.println("DeviceStateRotationLockSettingController");
+        pw.increaseIndent();
+        pw.println("mDeviceState: " + mDeviceState);
+        pw.decreaseIndent();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerLogger.kt
new file mode 100644
index 0000000..aa502bc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerLogger.kt
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy
+
+import android.content.Context
+import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_IGNORED
+import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_LOCKED
+import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_UNLOCKED
+import com.android.internal.R
+import com.android.systemui.log.dagger.DeviceStateAutoRotationLog
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel.VERBOSE
+import javax.inject.Inject
+
+class DeviceStateRotationLockSettingControllerLogger
+@Inject
+constructor(@DeviceStateAutoRotationLog private val logBuffer: LogBuffer, context: Context) {
+
+    private val foldedStates = context.resources.getIntArray(R.array.config_foldedDeviceStates)
+    private val halfFoldedStates =
+        context.resources.getIntArray(R.array.config_halfFoldedDeviceStates)
+    private val unfoldedStates = context.resources.getIntArray(R.array.config_openDeviceStates)
+
+    fun logListeningChange(listening: Boolean) {
+        logBuffer.log(TAG, VERBOSE, { bool1 = listening }, { "setListening: $bool1" })
+    }
+
+    fun logRotationLockStateChanged(
+        state: Int,
+        newRotationLocked: Boolean,
+        currentRotationLocked: Boolean
+    ) {
+        logBuffer.log(
+            TAG,
+            VERBOSE,
+            {
+                int1 = state
+                bool1 = newRotationLocked
+                bool2 = currentRotationLocked
+            },
+            {
+                "onRotationLockStateChanged: " +
+                    "state=$int1 [${int1.toDevicePostureString()}], " +
+                    "newRotationLocked=$bool1, " +
+                    "currentRotationLocked=$bool2"
+            }
+        )
+    }
+
+    fun logSaveNewRotationLockSetting(isRotationLocked: Boolean, state: Int) {
+        logBuffer.log(
+            TAG,
+            VERBOSE,
+            {
+                bool1 = isRotationLocked
+                int1 = state
+            },
+            { "saveNewRotationLockSetting: isRotationLocked=$bool1, state=$int1" }
+        )
+    }
+
+    fun logUpdateDeviceState(currentState: Int, newState: Int) {
+        logBuffer.log(
+            TAG,
+            VERBOSE,
+            {
+                int1 = currentState
+                int2 = newState
+            },
+            {
+                "updateDeviceState: " +
+                    "current=$int1 [${int1.toDevicePostureString()}], " +
+                    "new=$int2 [${int2.toDevicePostureString()}]"
+            }
+        )
+    }
+
+    fun readPersistedSetting(
+        caller: String,
+        state: Int,
+        rotationLockSetting: Int,
+        shouldBeLocked: Boolean,
+        isLocked: Boolean
+    ) {
+        logBuffer.log(
+            TAG,
+            VERBOSE,
+            {
+                str1 = caller
+                int1 = state
+                int2 = rotationLockSetting
+                bool1 = shouldBeLocked
+                bool2 = isLocked
+            },
+            {
+                "readPersistedSetting: " +
+                    "caller=$str1, " +
+                    "state=$int1 [${int1.toDevicePostureString()}], " +
+                    "rotationLockSettingForState: ${int2.toRotationLockSettingString()}, " +
+                    "shouldBeLocked=$bool1, " +
+                    "isLocked=$bool2"
+            }
+        )
+    }
+
+    private fun Int.toDevicePostureString(): String {
+        return when (this) {
+            in foldedStates -> "Folded"
+            in unfoldedStates -> "Unfolded"
+            in halfFoldedStates -> "Half-Folded"
+            -1 -> "Uninitialized"
+            else -> "Unknown"
+        }
+    }
+}
+
+private fun Int.toRotationLockSettingString(): String {
+    return when (this) {
+        DEVICE_STATE_ROTATION_LOCK_IGNORED -> "IGNORED"
+        DEVICE_STATE_ROTATION_LOCK_LOCKED -> "LOCKED"
+        DEVICE_STATE_ROTATION_LOCK_UNLOCKED -> "UNLOCKED"
+        else -> "Unknown"
+    }
+}
+
+private const val TAG = "DSRotateLockSettingCon"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
index 805368c..f1269f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -398,6 +398,7 @@
         pw.println("  mFaceAuthEnabled: " + mFaceAuthEnabled);
         pw.println("  isKeyguardFadingAway: " + isKeyguardFadingAway());
         pw.println("  isKeyguardGoingAway: " + isKeyguardGoingAway());
+        pw.println("  isLaunchTransitionFadingAway: " + isLaunchTransitionFadingAway());
     }
 
     private class UpdateMonitorCallback extends KeyguardUpdateMonitorCallback {
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
index 1065d33..59122af 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
@@ -274,6 +274,7 @@
             it.title = newInfo.windowTitle
         }
         newView.keepScreenOn = true
+        logger.logViewAddedToWindowManager(displayInfo.info, newView)
         windowManager.addView(newView, paramsWithTitle)
         animateViewIn(newView)
     }
@@ -286,6 +287,11 @@
         val view = checkNotNull(currentDisplayInfo.view) {
             "First item in activeViews list must have a valid view"
         }
+        logger.logViewRemovedFromWindowManager(
+            currentDisplayInfo.info,
+            view,
+            isReinflation = true,
+        )
         windowManager.removeView(view)
         inflateAndUpdateView(currentDisplayInfo)
     }
@@ -294,6 +300,10 @@
         override fun onDensityOrFontScaleChanged() {
             reinflateView()
         }
+
+        override fun onThemeChanged() {
+            reinflateView()
+        }
     }
 
     private fun addCallbacks() {
@@ -378,6 +388,7 @@
         }
         displayInfo.view = null // Need other places??
         animateViewOut(view, removalReason) {
+            logger.logViewRemovedFromWindowManager(displayInfo.info, view)
             windowManager.removeView(view)
             displayInfo.wakeLock?.release(displayInfo.info.wakeReason)
         }
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewLogger.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewLogger.kt
index 899b0c2..667e22a 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewLogger.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.temporarydisplay
 
+import android.view.View
 import com.android.systemui.plugins.log.LogBuffer
 import com.android.systemui.plugins.log.LogLevel
 
@@ -141,4 +142,46 @@
             { "Removal of view with id=$str2 is ignored because $str1" }
         )
     }
+
+    fun logViewAddedToWindowManager(info: T, view: View) {
+        buffer.log(
+            tag,
+            LogLevel.DEBUG,
+            {
+                str1 = info.id
+                str2 = info.windowTitle
+                str3 = view.javaClass.name
+                int1 = view.getIdForLogging()
+            },
+            {
+                "Adding view to window manager. " +
+                    "id=$str1 window=$str2 view=$str3(id=${Integer.toHexString(int1)})"
+            }
+        )
+    }
+
+    fun logViewRemovedFromWindowManager(info: T, view: View, isReinflation: Boolean = false) {
+        buffer.log(
+            tag,
+            LogLevel.DEBUG,
+            {
+                str1 = info.id
+                str2 = info.windowTitle
+                str3 = view.javaClass.name
+                int1 = view.getIdForLogging()
+                bool1 = isReinflation
+            },
+            {
+                "Removing view from window manager${if (bool1) " due to reinflation" else ""}. " +
+                    "id=$str1 window=$str2 view=$str3(id=${Integer.toHexString(int1)})"
+            }
+        )
+    }
+
+    companion object {
+        private fun View.getIdForLogging(): Int {
+            // The identityHashCode is guaranteed to be constant for the lifetime of the object.
+            return System.identityHashCode(this)
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt
index 125cc76..6e58f22 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt
@@ -18,7 +18,8 @@
 
 import android.os.VibrationEffect
 import android.view.View
-import androidx.annotation.AttrRes
+import androidx.annotation.ColorRes
+import com.android.systemui.R
 import com.android.systemui.common.shared.model.Text
 import com.android.systemui.common.shared.model.TintedIcon
 import com.android.systemui.temporarydisplay.TemporaryViewInfo
@@ -48,7 +49,7 @@
     override val priority: ViewPriority,
 ) : TemporaryViewInfo() {
     companion object {
-        @AttrRes const val DEFAULT_ICON_TINT_ATTR = android.R.attr.textColorPrimary
+        @ColorRes val DEFAULT_ICON_TINT = R.color.chipbar_text_and_icon_color
     }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
index 19a0866..6f2ac2e 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
@@ -87,6 +87,7 @@
     private var isFolded: Boolean = false
     private var isUnfoldHandled: Boolean = true
     private var overlayAddReason: AddOverlayReason? = null
+    private var isTouchBlocked: Boolean = true
 
     private var currentRotation: Int = context.display!!.rotation
 
@@ -253,7 +254,15 @@
         params.layoutInDisplayCutoutMode =
             WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
         params.fitInsetsTypes = 0
-        params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+
+        val touchFlags =
+            if (isTouchBlocked) {
+                // Touchable by default, so it will block the touches
+                0
+            } else {
+                WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
+            }
+        params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or touchFlags
         params.setTrustedOverlay()
 
         val packageName: String = context.opPackageName
@@ -262,6 +271,24 @@
         return params
     }
 
+    private fun updateTouchBlockIfNeeded(progress: Float) {
+        // When unfolding unblock touches a bit earlier than the animation end as the
+        // interpolation has a long tail of very slight movement at the end which should not
+        // affect much the usage of the device
+        val shouldBlockTouches =
+            if (overlayAddReason == UNFOLD) {
+                progress < UNFOLD_BLOCK_TOUCHES_UNTIL_PROGRESS
+            } else {
+                true
+            }
+
+        if (isTouchBlocked != shouldBlockTouches) {
+            isTouchBlocked = shouldBlockTouches
+
+            traceSection("$TAG#relayoutToUpdateTouch") { root?.relayout(getLayoutParams()) }
+        }
+    }
+
     private fun createLightRevealEffect(): LightRevealEffect {
         val isVerticalFold =
             currentRotation == Surface.ROTATION_0 || currentRotation == Surface.ROTATION_180
@@ -288,7 +315,10 @@
     private inner class TransitionListener : TransitionProgressListener {
 
         override fun onTransitionProgress(progress: Float) {
-            executeInBackground { scrimView?.revealAmount = calculateRevealAmount(progress) }
+            executeInBackground {
+                scrimView?.revealAmount = calculateRevealAmount(progress)
+                updateTouchBlockIfNeeded(progress)
+            }
         }
 
         override fun onTransitionFinished() {
@@ -360,5 +390,7 @@
         // constants for revealAmount.
         const val TRANSPARENT = 1f
         const val BLACK = 0f
+
+        private const val UNFOLD_BLOCK_TOUCHES_UNTIL_PROGRESS = 0.8f
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
index 3f895ad..02d4479 100644
--- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
@@ -32,6 +32,8 @@
 import android.provider.Settings
 import android.util.Log
 import com.android.internal.util.UserIcons
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.keyguard.KeyguardUpdateMonitorCallback
 import com.android.systemui.R
 import com.android.systemui.SystemUISecondaryUserService
 import com.android.systemui.animation.Expandable
@@ -90,6 +92,7 @@
     @Application private val applicationScope: CoroutineScope,
     telephonyInteractor: TelephonyInteractor,
     broadcastDispatcher: BroadcastDispatcher,
+    keyguardUpdateMonitor: KeyguardUpdateMonitor,
     @Background private val backgroundDispatcher: CoroutineDispatcher,
     private val activityManager: ActivityManager,
     private val refreshUsersScheduler: RefreshUsersScheduler,
@@ -286,6 +289,12 @@
 
     val isSimpleUserSwitcher: Boolean
         get() = repository.isSimpleUserSwitcher()
+    val keyguardUpdateMonitorCallback =
+        object : KeyguardUpdateMonitorCallback() {
+            override fun onKeyguardGoingAway() {
+                dismissDialog()
+            }
+        }
 
     init {
         refreshUsersScheduler.refreshIfNotPaused()
@@ -316,6 +325,7 @@
                 onBroadcastReceived(intent, previousSelectedUser)
             }
             .launchIn(applicationScope)
+        keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
     }
 
     fun addCallback(callback: UserCallback) {
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java
index 81ae6e8..c72853e 100644
--- a/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java
@@ -115,6 +115,17 @@
     }
 
     /**
+     * Provide a Long running Executor.
+     */
+    @Provides
+    @SysUISingleton
+    @LongRunning
+    public static DelayableExecutor provideLongRunningDelayableExecutor(
+            @LongRunning Looper looper) {
+        return new ExecutorImpl(looper);
+    }
+
+    /**
      * Provide a Background-Thread Executor.
      */
     @Provides
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/PostureDependentProximitySensor.java b/packages/SystemUI/src/com/android/systemui/util/sensors/PostureDependentProximitySensor.java
index 460b7d9..a5828c7 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/PostureDependentProximitySensor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/PostureDependentProximitySensor.java
@@ -23,6 +23,8 @@
 import com.android.systemui.util.concurrency.DelayableExecutor;
 import com.android.systemui.util.concurrency.Execution;
 
+import java.util.HashSet;
+
 import javax.inject.Inject;
 
 /**
@@ -37,6 +39,7 @@
     private final ThresholdSensor[] mPostureToPrimaryProxSensorMap;
     private final ThresholdSensor[] mPostureToSecondaryProxSensorMap;
 
+    private final HashSet<Listener> mListenersRegisteredWhenProxUnavailable = new HashSet<>();
     private final DevicePostureController mDevicePostureController;
 
     @Inject
@@ -69,6 +72,25 @@
         mDevicePostureController.removeCallback(mDevicePostureCallback);
     }
 
+    @Override
+    public void register(ThresholdSensor.Listener listener) {
+        if (!isLoaded()) {
+            logDebug("No prox sensor when registering listener=" + listener);
+            mListenersRegisteredWhenProxUnavailable.add(listener);
+        }
+
+        super.register(listener);
+    }
+
+    @Override
+    public void unregister(ThresholdSensor.Listener listener) {
+        if (mListenersRegisteredWhenProxUnavailable.remove(listener)) {
+            logDebug("Removing listener from mListenersRegisteredWhenProxUnavailable "
+                    + listener);
+        }
+        super.unregister(listener);
+    }
+
     private void chooseSensors() {
         if (mDevicePosture >= mPostureToPrimaryProxSensorMap.length
                 || mDevicePosture >= mPostureToSecondaryProxSensorMap.length) {
@@ -98,6 +120,14 @@
 
             mInitializedListeners = false;
             registerInternal();
+
+            final Listener[] listenersToReregister =
+                    mListenersRegisteredWhenProxUnavailable.toArray(new Listener[0]);
+            mListenersRegisteredWhenProxUnavailable.clear();
+            for (Listener listener : listenersToReregister) {
+                logDebug("Re-register listener " + listener);
+                register(listener);
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/util/service/ObservableServiceConnection.java b/packages/SystemUI/src/com/android/systemui/util/service/ObservableServiceConnection.java
index 064c224..c6da55c 100644
--- a/packages/SystemUI/src/com/android/systemui/util/service/ObservableServiceConnection.java
+++ b/packages/SystemUI/src/com/android/systemui/util/service/ObservableServiceConnection.java
@@ -119,11 +119,11 @@
 
     /**
      * Default constructor for {@link ObservableServiceConnection}.
-     * @param context The context from which the service will be bound with.
+     * @param context       The context from which the service will be bound with.
      * @param serviceIntent The intent to  bind service with.
-     * @param executor The executor for connection callbacks to be delivered on
-     * @param transformer A {@link ServiceTransformer} for transforming the resulting service
-     *                    into a desired type.
+     * @param executor      The executor for connection callbacks to be delivered on
+     * @param transformer   A {@link ServiceTransformer} for transforming the resulting service
+     *                      into a desired type.
      */
     @Inject
     public ObservableServiceConnection(Context context, Intent serviceIntent,
@@ -143,7 +143,13 @@
      * @return {@code true} if initiating binding succeed, {@code false} otherwise.
      */
     public boolean bind() {
-        final boolean bindResult = mContext.bindService(mServiceIntent, mFlags, mExecutor, this);
+        boolean bindResult = false;
+        try {
+            bindResult = mContext.bindService(mServiceIntent, mFlags, mExecutor, this);
+        } catch (SecurityException e) {
+            Log.d(TAG, "Could not bind to service", e);
+            mContext.unbindService(this);
+        }
         mBoundCalled = true;
         if (DEBUG) {
             Log.d(TAG, "bind. bound:" + bindResult);
@@ -197,7 +203,7 @@
             Log.d(TAG, "removeCallback:" + callback);
         }
 
-        mExecutor.execute(()-> mCallbacks.removeIf(el -> el.get() == callback));
+        mExecutor.execute(() -> mCallbacks.removeIf(el-> el.get() == callback));
     }
 
     private void onDisconnected(@DisconnectReason int reason) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index b847d67..1cfcf8c 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -1473,6 +1473,7 @@
         mHandler.removeMessages(H.SHOW);
         if (mIsAnimatingDismiss) {
             Log.d(TAG, "dismissH: isAnimatingDismiss");
+            Trace.endSection();
             return;
         }
         mIsAnimatingDismiss = true;
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java
index a062e7b..492f231 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java
@@ -77,8 +77,11 @@
     private final FalsingManager mFalsingManager;
     private final UiEventLogger mUiEventLogger;
 
-    @VisibleForTesting String mSelectedCardId;
-    @VisibleForTesting boolean mIsDismissed;
+
+    @VisibleForTesting
+    String mSelectedCardId;
+    @VisibleForTesting
+    boolean mIsDismissed;
 
     public WalletScreenController(
             Context context,
@@ -124,9 +127,20 @@
         }
         Log.i(TAG, "Successfully retrieved wallet cards.");
         List<WalletCard> walletCards = response.getWalletCards();
-        List<WalletCardViewInfo> data = new ArrayList<>(walletCards.size());
+
+        boolean allUnknown = true;
         for (WalletCard card : walletCards) {
-            data.add(new QAWalletCardViewInfo(mContext, card));
+            if (card.getCardType() != WalletCard.CARD_TYPE_UNKNOWN) {
+                allUnknown = false;
+                break;
+            }
+        }
+
+        List<WalletCardViewInfo> paymentCardData = new ArrayList<>();
+        for (WalletCard card : walletCards) {
+            if (allUnknown || card.getCardType() == WalletCard.CARD_TYPE_PAYMENT) {
+                paymentCardData.add(new QAWalletCardViewInfo(mContext, card));
+            }
         }
 
         // Get on main thread for UI updates.
@@ -134,18 +148,18 @@
             if (mIsDismissed) {
                 return;
             }
-            if (data.isEmpty()) {
+            if (paymentCardData.isEmpty()) {
                 showEmptyStateView();
             } else {
                 int selectedIndex = response.getSelectedIndex();
-                if (selectedIndex >= data.size()) {
+                if (selectedIndex >= paymentCardData.size()) {
                     Log.w(TAG, "Invalid selected card index, showing empty state.");
                     showEmptyStateView();
                 } else {
                     boolean isUdfpsEnabled = mKeyguardUpdateMonitor.isUdfpsEnrolled()
                             && mKeyguardUpdateMonitor.isFingerprintDetectionRunning();
                     mWalletView.showCardCarousel(
-                            data,
+                            paymentCardData,
                             selectedIndex,
                             !mKeyguardStateController.isUnlocked(),
                             isUdfpsEnabled);
@@ -213,7 +227,6 @@
     }
 
 
-
     @Override
     public void onCardClicked(@NonNull WalletCardViewInfo cardInfo) {
         if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
index 8b925b7..b962148 100644
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
@@ -35,7 +35,7 @@
 import androidx.annotation.NonNull;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.LongRunning;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 
@@ -61,17 +61,16 @@
     private final UserTracker mUserTracker;
 
     // used for most tasks (call canvas.drawBitmap, load/unload the bitmap)
-    @Background
-    private final DelayableExecutor mBackgroundExecutor;
+    @LongRunning
+    private final DelayableExecutor mLongExecutor;
 
     // wait at least this duration before unloading the bitmap
     private static final int DELAY_UNLOAD_BITMAP = 2000;
 
     @Inject
-    public ImageWallpaper(@Background DelayableExecutor backgroundExecutor,
-            UserTracker userTracker) {
+    public ImageWallpaper(@LongRunning DelayableExecutor longExecutor, UserTracker userTracker) {
         super();
-        mBackgroundExecutor = backgroundExecutor;
+        mLongExecutor = longExecutor;
         mUserTracker = userTracker;
     }
 
@@ -105,7 +104,7 @@
             setFixedSizeAllowed(true);
             setShowForAllUsers(true);
             mWallpaperLocalColorExtractor = new WallpaperLocalColorExtractor(
-                    mBackgroundExecutor,
+                    mLongExecutor,
                     new WallpaperLocalColorExtractor.WallpaperLocalColorExtractorCallback() {
                         @Override
                         public void onColorsProcessed(List<RectF> regions,
@@ -202,7 +201,7 @@
         }
 
         private void drawFrame() {
-            mBackgroundExecutor.execute(this::drawFrameSynchronized);
+            mLongExecutor.execute(this::drawFrameSynchronized);
         }
 
         private void drawFrameSynchronized() {
@@ -257,7 +256,7 @@
         }
 
         private void unloadBitmapIfNotUsed() {
-            mBackgroundExecutor.execute(this::unloadBitmapIfNotUsedSynchronized);
+            mLongExecutor.execute(this::unloadBitmapIfNotUsedSynchronized);
         }
 
         private void unloadBitmapIfNotUsedSynchronized() {
@@ -341,7 +340,7 @@
                  *   - the mini bitmap from color extractor is recomputed
                  *   - the DELAY_UNLOAD_BITMAP has passed
                  */
-                mBackgroundExecutor.executeDelayed(
+                mLongExecutor.executeDelayed(
                         this::unloadBitmapIfNotUsedSynchronized, DELAY_UNLOAD_BITMAP);
             }
             // even if the bitmap cannot be loaded, call reportEngineShown
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/WallpaperLocalColorExtractor.java b/packages/SystemUI/src/com/android/systemui/wallpapers/WallpaperLocalColorExtractor.java
index 988fd71..1e8446f 100644
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/WallpaperLocalColorExtractor.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/WallpaperLocalColorExtractor.java
@@ -29,7 +29,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
 
-import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.LongRunning;
 import com.android.systemui.util.Assert;
 
 import java.io.FileDescriptor;
@@ -66,8 +66,8 @@
     private final List<RectF> mPendingRegions = new ArrayList<>();
     private final Set<RectF> mProcessedRegions = new ArraySet<>();
 
-    @Background
-    private final Executor mBackgroundExecutor;
+    @LongRunning
+    private final Executor mLongExecutor;
 
     private final WallpaperLocalColorExtractorCallback mWallpaperLocalColorExtractorCallback;
 
@@ -101,13 +101,13 @@
 
     /**
      * Creates a new color extractor.
-     * @param backgroundExecutor the executor on which the color extraction will be performed
+     * @param longExecutor the executor on which the color extraction will be performed
      * @param wallpaperLocalColorExtractorCallback an interface to handle the callbacks from
      *                                        the color extractor.
      */
-    public WallpaperLocalColorExtractor(@Background Executor backgroundExecutor,
+    public WallpaperLocalColorExtractor(@LongRunning Executor longExecutor,
             WallpaperLocalColorExtractorCallback wallpaperLocalColorExtractorCallback) {
-        mBackgroundExecutor = backgroundExecutor;
+        mLongExecutor = longExecutor;
         mWallpaperLocalColorExtractorCallback = wallpaperLocalColorExtractorCallback;
     }
 
@@ -117,7 +117,7 @@
      * not recomputed.
      */
     public void setDisplayDimensions(int displayWidth, int displayHeight) {
-        mBackgroundExecutor.execute(() ->
+        mLongExecutor.execute(() ->
                 setDisplayDimensionsSynchronized(displayWidth, displayHeight));
     }
 
@@ -144,7 +144,7 @@
      * @param bitmap the new wallpaper
      */
     public void onBitmapChanged(@NonNull Bitmap bitmap) {
-        mBackgroundExecutor.execute(() -> onBitmapChangedSynchronized(bitmap));
+        mLongExecutor.execute(() -> onBitmapChangedSynchronized(bitmap));
     }
 
     private void onBitmapChangedSynchronized(@NonNull Bitmap bitmap) {
@@ -167,7 +167,7 @@
      * @param pages the total number of pages of the launcher
      */
     public void onPageChanged(int pages) {
-        mBackgroundExecutor.execute(() -> onPageChangedSynchronized(pages));
+        mLongExecutor.execute(() -> onPageChangedSynchronized(pages));
     }
 
     private void onPageChangedSynchronized(int pages) {
@@ -194,7 +194,7 @@
      */
     public void addLocalColorsAreas(@NonNull List<RectF> regions) {
         if (regions.size() > 0) {
-            mBackgroundExecutor.execute(() -> addLocalColorsAreasSynchronized(regions));
+            mLongExecutor.execute(() -> addLocalColorsAreasSynchronized(regions));
         } else {
             Log.w(TAG, "Attempt to add colors with an empty list");
         }
@@ -218,7 +218,7 @@
      * @param regions The areas of interest in our wallpaper (in screen pixel coordinates)
      */
     public void removeLocalColorAreas(@NonNull List<RectF> regions) {
-        mBackgroundExecutor.execute(() -> removeLocalColorAreasSynchronized(regions));
+        mLongExecutor.execute(() -> removeLocalColorAreasSynchronized(regions));
     }
 
     private void removeLocalColorAreasSynchronized(@NonNull List<RectF> regions) {
@@ -236,7 +236,7 @@
      * Clean up the memory (in particular, the mini bitmap) used by this class.
      */
     public void cleanUp() {
-        mBackgroundExecutor.execute(this::cleanUpSynchronized);
+        mLongExecutor.execute(this::cleanUpSynchronized);
     }
 
     private void cleanUpSynchronized() {
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index 5d896cb..56df3e1 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -25,7 +25,6 @@
 import static android.service.notification.NotificationStats.DISMISSAL_BUBBLE;
 import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
 
-import static com.android.systemui.flags.Flags.WM_BUBBLE_BAR;
 import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
 import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
 
@@ -358,7 +357,6 @@
                 });
             }
         };
-        mBubbles.setBubbleBarEnabled(featureFlags.isEnabled(WM_BUBBLE_BAR));
         mBubbles.setSysuiProxy(mSysuiProxy);
     }
 
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index d4e06bc..690f63c 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -108,6 +108,11 @@
             android:excludeFromRecents="true"
             />
 
+        <activity android:name="com.android.systemui.controls.ui.TestableControlsActivity"
+            android:exported="false"
+            android:excludeFromRecents="true"
+            />
+
         <activity android:name="com.android.systemui.screenshot.ScrollViewActivity"
                   android:exported="false" />
 
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index a5f90f8..b15ac39 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -17,6 +17,7 @@
 package com.android.keyguard;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.eq;
@@ -365,6 +366,12 @@
         assertEquals(View.VISIBLE, mFakeWeatherView.getVisibility());
     }
 
+    @Test
+    public void testGetClockAnimations_nullClock_returnsNull() {
+        when(mClockEventController.getClock()).thenReturn(null);
+        assertNull(mController.getClockAnimations());
+    }
+
     private void verifyAttachment(VerificationMode times) {
         verify(mClockRegistry, times).registerClockChangeListener(
                 any(ClockRegistry.ClockChangeListener.class));
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java
index 0e837d2..a35e5b5 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java
@@ -18,12 +18,15 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -37,6 +40,7 @@
 import org.mockito.MockitoAnnotations;
 
 @SmallTest
+@TestableLooper.RunWithLooper
 @RunWith(AndroidTestingRunner.class)
 public class KeyguardMessageAreaControllerTest extends SysuiTestCase {
     @Mock
@@ -45,14 +49,14 @@
     private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     @Mock
     private KeyguardMessageArea mKeyguardMessageArea;
-
     private KeyguardMessageAreaController mMessageAreaController;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
         mMessageAreaController = new KeyguardMessageAreaController.Factory(
-                mKeyguardUpdateMonitor, mConfigurationController).create(mKeyguardMessageArea);
+                mKeyguardUpdateMonitor, mConfigurationController).create(
+                mKeyguardMessageArea);
     }
 
     @Test
@@ -89,6 +93,19 @@
     }
 
     @Test
+    public void testSetMessage_AnnounceForAccessibility() {
+        ArgumentCaptor<Runnable> argumentCaptor = ArgumentCaptor.forClass(Runnable.class);
+        when(mKeyguardMessageArea.getText()).thenReturn("abc");
+        mMessageAreaController.setMessage("abc");
+
+        verify(mKeyguardMessageArea).setMessage("abc", /* animate= */ true);
+        verify(mKeyguardMessageArea).removeCallbacks(any(Runnable.class));
+        verify(mKeyguardMessageArea).postDelayed(argumentCaptor.capture(), anyLong());
+        argumentCaptor.getValue().run();
+        verify(mKeyguardMessageArea).announceForAccessibility("abc");
+    }
+
+    @Test
     public void testSetBouncerVisible() {
         mMessageAreaController.setIsVisible(true);
         verify(mKeyguardMessageArea).setIsVisible(true);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
index bbc7bc9..d492758 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
@@ -66,6 +66,7 @@
 import com.android.systemui.classifier.FalsingA11yDelegate;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.log.SessionTracker;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.FalsingManager;
@@ -195,6 +196,7 @@
                 .thenReturn(mKeyguardMessageAreaController);
         when(mKeyguardPasswordView.getWindowInsetsController()).thenReturn(mWindowInsetsController);
         when(mKeyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(SecurityMode.PIN);
+        when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true);
         mKeyguardPasswordViewController = new KeyguardPasswordViewController(
                 (KeyguardPasswordView) mKeyguardPasswordView, mKeyguardUpdateMonitor,
                 SecurityMode.Password, mLockPatternUtils, null,
@@ -519,6 +521,54 @@
     }
 
     @Test
+    public void testWillRunDismissFromKeyguardIsTrue() {
+        ActivityStarter.OnDismissAction action = mock(ActivityStarter.OnDismissAction.class);
+        when(action.willRunAnimationOnKeyguard()).thenReturn(true);
+        mKeyguardSecurityContainerController.setOnDismissAction(action, null /* cancelAction */);
+
+        mKeyguardSecurityContainerController.finish(false /* strongAuth */, 0 /* currentUser */);
+
+        assertThat(mKeyguardSecurityContainerController.willRunDismissFromKeyguard()).isTrue();
+    }
+
+    @Test
+    public void testWillRunDismissFromKeyguardIsFalse() {
+        ActivityStarter.OnDismissAction action = mock(ActivityStarter.OnDismissAction.class);
+        when(action.willRunAnimationOnKeyguard()).thenReturn(false);
+        mKeyguardSecurityContainerController.setOnDismissAction(action, null /* cancelAction */);
+
+        mKeyguardSecurityContainerController.finish(false /* strongAuth */, 0 /* currentUser */);
+
+        assertThat(mKeyguardSecurityContainerController.willRunDismissFromKeyguard()).isFalse();
+    }
+
+    @Test
+    public void testWillRunDismissFromKeyguardIsFalseWhenNoDismissActionSet() {
+        mKeyguardSecurityContainerController.setOnDismissAction(null /* action */,
+                null /* cancelAction */);
+
+        mKeyguardSecurityContainerController.finish(false /* strongAuth */, 0 /* currentUser */);
+
+        assertThat(mKeyguardSecurityContainerController.willRunDismissFromKeyguard()).isFalse();
+    }
+
+    @Test
+    public void testSecurityCallbackFinish() {
+        when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true);
+        when(mKeyguardUpdateMonitor.isUserUnlocked(0)).thenReturn(true);
+        mKeyguardSecurityContainerController.finish(true, 0);
+        verify(mViewMediatorCallback).keyguardDone(anyBoolean(), anyInt());
+    }
+
+    @Test
+    public void testSecurityCallbackFinish_cannotDismissLockScreenAndNotStrongAuth() {
+        when(mFeatureFlags.isEnabled(Flags.PREVENT_BYPASS_KEYGUARD)).thenReturn(true);
+        when(mKeyguardStateController.canDismissLockScreen()).thenReturn(false);
+        mKeyguardSecurityContainerController.finish(false, 0);
+        verify(mViewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt());
+    }
+
+    @Test
     public void testOnStartingToHide() {
         mKeyguardSecurityContainerController.onStartingToHide();
         verify(mInputViewController).onStartingToHide();
@@ -585,13 +635,26 @@
 
     @Test
     public void testReinflateViewFlipper() {
-        mKeyguardSecurityContainerController.reinflateViewFlipper();
+        mKeyguardSecurityContainerController.reinflateViewFlipper(() -> {});
         verify(mKeyguardSecurityViewFlipperController).clearViews();
         verify(mKeyguardSecurityViewFlipperController).getSecurityView(any(SecurityMode.class),
                 any(KeyguardSecurityCallback.class));
     }
 
     @Test
+    public void testReinflateViewFlipper_asyncBouncerFlagOn() {
+        when(mFeatureFlags.isEnabled(Flags.ASYNC_INFLATE_BOUNCER)).thenReturn(true);
+        KeyguardSecurityViewFlipperController.OnViewInflatedListener onViewInflatedListener =
+                () -> {
+                };
+        mKeyguardSecurityContainerController.reinflateViewFlipper(onViewInflatedListener);
+        verify(mKeyguardSecurityViewFlipperController).clearViews();
+        verify(mKeyguardSecurityViewFlipperController).asynchronouslyInflateView(
+                any(SecurityMode.class),
+                any(KeyguardSecurityCallback.class), eq(onViewInflatedListener));
+    }
+
+    @Test
     public void testSideFpsControllerShow() {
         mKeyguardSecurityContainerController.updateSideFpsVisibility(/* isVisible= */ true);
         verify(mSideFpsController).show(
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
index 531006d..565fc57 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
@@ -263,9 +263,6 @@
         assertThat(viewFlipperConstraint.layout.bottomToBottom).isEqualTo(PARENT_ID);
         assertThat(userSwitcherConstraint.layout.topToTop).isEqualTo(PARENT_ID);
         assertThat(userSwitcherConstraint.layout.bottomToBottom).isEqualTo(PARENT_ID);
-        assertThat(userSwitcherConstraint.layout.bottomMargin).isEqualTo(
-                getContext().getResources().getDimensionPixelSize(
-                        R.dimen.bouncer_user_switcher_y_trans));
         assertThat(viewFlipperConstraint.layout.horizontalChainStyle).isEqualTo(CHAIN_SPREAD);
         assertThat(userSwitcherConstraint.layout.horizontalChainStyle).isEqualTo(CHAIN_SPREAD);
         assertThat(viewFlipperConstraint.layout.mHeight).isEqualTo(MATCH_CONSTRAINT);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java
index 1614b57..afb54d2 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java
@@ -31,10 +31,12 @@
 import android.view.ViewGroup;
 import android.view.WindowInsetsController;
 
+import androidx.asynclayoutinflater.view.AsyncLayoutInflater;
 import androidx.test.filters.SmallTest;
 
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.flags.FeatureFlags;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -57,6 +59,8 @@
     @Mock
     private LayoutInflater mLayoutInflater;
     @Mock
+    private AsyncLayoutInflater mAsyncLayoutInflater;
+    @Mock
     private KeyguardInputViewController.Factory mKeyguardSecurityViewControllerFactory;
     @Mock
     private EmergencyButtonController.Factory mEmergencyButtonControllerFactory;
@@ -70,6 +74,8 @@
     private WindowInsetsController mWindowInsetsController;
     @Mock
     private KeyguardSecurityCallback mKeyguardSecurityCallback;
+    @Mock
+    private FeatureFlags mFeatureFlags;
 
     private KeyguardSecurityViewFlipperController mKeyguardSecurityViewFlipperController;
 
@@ -82,10 +88,11 @@
         when(mView.getWindowInsetsController()).thenReturn(mWindowInsetsController);
         when(mEmergencyButtonControllerFactory.create(any(EmergencyButton.class)))
                 .thenReturn(mEmergencyButtonController);
+        when(mView.getContext()).thenReturn(getContext());
 
         mKeyguardSecurityViewFlipperController = new KeyguardSecurityViewFlipperController(mView,
-                mLayoutInflater, mKeyguardSecurityViewControllerFactory,
-                mEmergencyButtonControllerFactory);
+                mLayoutInflater, mAsyncLayoutInflater, mKeyguardSecurityViewControllerFactory,
+                mEmergencyButtonControllerFactory, mFeatureFlags);
     }
 
     @Test
@@ -108,6 +115,14 @@
     }
 
     @Test
+    public void asynchronouslyInflateView() {
+        mKeyguardSecurityViewFlipperController.asynchronouslyInflateView(SecurityMode.PIN,
+                mKeyguardSecurityCallback, null);
+        verify(mAsyncLayoutInflater).inflate(anyInt(), eq(mView), any(
+                AsyncLayoutInflater.OnInflateFinishedListener.class));
+    }
+
+    @Test
     public void onDensityOrFontScaleChanged() {
         mKeyguardSecurityViewFlipperController.clearViews();
         verify(mView).removeAllViews();
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt
new file mode 100644
index 0000000..eb86c05
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard
+
+import android.telephony.PinResult
+import android.telephony.TelephonyManager
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.LayoutInflater
+import androidx.test.filters.SmallTest
+import com.android.internal.util.LatencyTracker
+import com.android.internal.widget.LockPatternUtils
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.util.mockito.any
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyString
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class KeyguardSimPinViewControllerTest : SysuiTestCase() {
+    private lateinit var simPinView: KeyguardSimPinView
+    private lateinit var underTest: KeyguardSimPinViewController
+    @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
+    @Mock private lateinit var securityMode: KeyguardSecurityModel.SecurityMode
+    @Mock private lateinit var lockPatternUtils: LockPatternUtils
+    @Mock private lateinit var keyguardSecurityCallback: KeyguardSecurityCallback
+    @Mock private lateinit var messageAreaControllerFactory: KeyguardMessageAreaController.Factory
+    @Mock private lateinit var latencyTracker: LatencyTracker
+    @Mock private lateinit var liftToActivateListener: LiftToActivateListener
+    @Mock private lateinit var telephonyManager: TelephonyManager
+    @Mock private lateinit var falsingCollector: FalsingCollector
+    @Mock private lateinit var emergencyButtonController: EmergencyButtonController
+    @Mock
+    private lateinit var keyguardMessageAreaController:
+        KeyguardMessageAreaController<BouncerKeyguardMessageArea>
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+        `when`(messageAreaControllerFactory.create(Mockito.any(KeyguardMessageArea::class.java)))
+            .thenReturn(keyguardMessageAreaController)
+        `when`(telephonyManager.createForSubscriptionId(anyInt())).thenReturn(telephonyManager)
+        `when`(telephonyManager.supplyIccLockPin(anyString()))
+            .thenReturn(mock(PinResult::class.java))
+        simPinView =
+            LayoutInflater.from(context).inflate(R.layout.keyguard_sim_pin_view, null)
+                as KeyguardSimPinView
+        underTest =
+            KeyguardSimPinViewController(
+                simPinView,
+                keyguardUpdateMonitor,
+                securityMode,
+                lockPatternUtils,
+                keyguardSecurityCallback,
+                messageAreaControllerFactory,
+                latencyTracker,
+                liftToActivateListener,
+                telephonyManager,
+                falsingCollector,
+                emergencyButtonController
+            )
+        underTest.init()
+    }
+
+    @Test
+    fun onViewAttached() {
+        underTest.onViewAttached()
+    }
+
+    @Test
+    fun onViewDetached() {
+        underTest.onViewDetached()
+    }
+
+    @Test
+    fun onResume() {
+        underTest.onResume(KeyguardSecurityView.VIEW_REVEALED)
+        verify(keyguardUpdateMonitor)
+            .registerCallback(any(KeyguardUpdateMonitorCallback::class.java))
+    }
+
+    @Test
+    fun onPause() {
+        underTest.onPause()
+        verify(keyguardUpdateMonitor).removeCallback(any(KeyguardUpdateMonitorCallback::class.java))
+    }
+
+    @Test
+    fun startAppearAnimation() {
+        underTest.startAppearAnimation()
+        verify(keyguardMessageAreaController)
+            .setMessage(context.resources.getString(R.string.keyguard_enter_your_pin), false)
+    }
+
+    @Test
+    fun startDisappearAnimation() {
+        underTest.startDisappearAnimation {}
+    }
+
+    @Test
+    fun resetState() {
+        underTest.resetState()
+        verify(keyguardMessageAreaController).setMessage("")
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt
new file mode 100644
index 0000000..2dcca55
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard
+
+import android.telephony.PinResult
+import android.telephony.TelephonyManager
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.LayoutInflater
+import androidx.test.filters.SmallTest
+import com.android.internal.util.LatencyTracker
+import com.android.internal.widget.LockPatternUtils
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.util.mockito.any
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyString
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class KeyguardSimPukViewControllerTest : SysuiTestCase() {
+    private lateinit var simPukView: KeyguardSimPukView
+    private lateinit var underTest: KeyguardSimPukViewController
+    @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
+    @Mock private lateinit var securityMode: KeyguardSecurityModel.SecurityMode
+    @Mock private lateinit var lockPatternUtils: LockPatternUtils
+    @Mock private lateinit var keyguardSecurityCallback: KeyguardSecurityCallback
+    @Mock private lateinit var messageAreaControllerFactory: KeyguardMessageAreaController.Factory
+    @Mock private lateinit var latencyTracker: LatencyTracker
+    @Mock private lateinit var liftToActivateListener: LiftToActivateListener
+    @Mock private lateinit var telephonyManager: TelephonyManager
+    @Mock private lateinit var falsingCollector: FalsingCollector
+    @Mock private lateinit var emergencyButtonController: EmergencyButtonController
+    @Mock
+    private lateinit var keyguardMessageAreaController:
+        KeyguardMessageAreaController<BouncerKeyguardMessageArea>
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+        Mockito.`when`(
+                messageAreaControllerFactory.create(Mockito.any(KeyguardMessageArea::class.java))
+            )
+            .thenReturn(keyguardMessageAreaController)
+        Mockito.`when`(telephonyManager.createForSubscriptionId(Mockito.anyInt()))
+            .thenReturn(telephonyManager)
+        Mockito.`when`(telephonyManager.supplyIccLockPuk(anyString(), anyString()))
+            .thenReturn(Mockito.mock(PinResult::class.java))
+        simPukView =
+            LayoutInflater.from(context).inflate(R.layout.keyguard_sim_puk_view, null)
+                as KeyguardSimPukView
+        underTest =
+            KeyguardSimPukViewController(
+                simPukView,
+                keyguardUpdateMonitor,
+                securityMode,
+                lockPatternUtils,
+                keyguardSecurityCallback,
+                messageAreaControllerFactory,
+                latencyTracker,
+                liftToActivateListener,
+                telephonyManager,
+                falsingCollector,
+                emergencyButtonController
+            )
+        underTest.init()
+    }
+
+    @Test
+    fun onViewAttached() {
+        underTest.onViewAttached()
+        Mockito.verify(keyguardUpdateMonitor)
+            .registerCallback(any(KeyguardUpdateMonitorCallback::class.java))
+    }
+
+    @Test
+    fun onViewDetached() {
+        underTest.onViewDetached()
+        Mockito.verify(keyguardUpdateMonitor)
+            .removeCallback(any(KeyguardUpdateMonitorCallback::class.java))
+    }
+
+    @Test
+    fun onResume() {
+        underTest.onResume(KeyguardSecurityView.VIEW_REVEALED)
+    }
+
+    @Test
+    fun onPause() {
+        underTest.onPause()
+    }
+
+    @Test
+    fun startAppearAnimation() {
+        underTest.startAppearAnimation()
+        Mockito.verify(keyguardMessageAreaController)
+            .setMessage(context.resources.getString(R.string.keyguard_enter_your_pin), false)
+    }
+
+    @Test
+    fun startDisappearAnimation() {
+        underTest.startDisappearAnimation {}
+    }
+
+    @Test
+    fun resetState() {
+        underTest.resetState()
+        Mockito.verify(keyguardMessageAreaController)
+            .setMessage(context.resources.getString(R.string.kg_puk_enter_puk_hint))
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 3c80dad..b1051af 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -17,7 +17,6 @@
 package com.android.keyguard;
 
 import static android.app.StatusBarManager.SESSION_KEYGUARD;
-import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_LOCKOUT_TIMED;
 import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT;
 import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT_PERMANENT;
 import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_POWER_BUTTON;
@@ -2200,6 +2199,32 @@
     }
 
     @Test
+    public void testPostureChangeToUnsupported_stopsFaceListeningState() {
+        // GIVEN device is listening for face
+        mKeyguardUpdateMonitor.mConfigFaceAuthSupportedPosture = DEVICE_POSTURE_CLOSED;
+        deviceInPostureStateClosed();
+        mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
+        mTestableLooper.processAllMessages();
+        keyguardIsVisible();
+
+        verifyFaceAuthenticateCall();
+
+        final CancellationSignal faceCancel = spy(mKeyguardUpdateMonitor.mFaceCancelSignal);
+        mKeyguardUpdateMonitor.mFaceCancelSignal = faceCancel;
+        KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class);
+        mKeyguardUpdateMonitor.registerCallback(callback);
+
+        // WHEN device is opened
+        deviceInPostureStateOpened();
+        mTestableLooper.processAllMessages();
+
+        // THEN face listening is stopped.
+        verify(faceCancel).cancel();
+        verify(callback).onBiometricRunningStateChanged(
+                eq(false), eq(BiometricSourceType.FACE));
+    }
+
+    @Test
     public void testShouldListenForFace_withLockedDown_returnsFalse()
             throws RemoteException {
         keyguardNotGoingAway();
@@ -2220,6 +2245,26 @@
     }
 
     @Test
+    public void assistantVisible_requestActiveUnlock() {
+        // GIVEN active unlock requests from the assistant are allowed
+        when(mActiveUnlockConfig.shouldAllowActiveUnlockFromOrigin(
+                ActiveUnlockConfig.ActiveUnlockRequestOrigin.ASSISTANT)).thenReturn(true);
+
+        // GIVEN should trigger active unlock
+        keyguardIsVisible();
+        keyguardNotGoingAway();
+        statusBarShadeIsNotLocked();
+        when(mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())).thenReturn(true);
+
+        // WHEN the assistant is visible
+        mKeyguardUpdateMonitor.setAssistantVisible(true);
+
+        // THEN request unlock with keyguard dismissal
+        verify(mTrustManager).reportUserRequestedUnlock(eq(KeyguardUpdateMonitor.getCurrentUser()),
+                eq(true));
+    }
+
+    @Test
     public void fingerprintFailure_requestActiveUnlock_dismissKeyguard()
             throws RemoteException {
         // GIVEN shouldTriggerActiveUnlock
@@ -2408,6 +2453,57 @@
     }
 
     @Test
+    public void unfoldFromPostureChange_requestActiveUnlock_forceDismissKeyguard()
+            throws RemoteException {
+        // GIVEN shouldTriggerActiveUnlock
+        keyguardIsVisible();
+        when(mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())).thenReturn(true);
+
+        // GIVEN active unlock triggers on wakeup
+        when(mActiveUnlockConfig.shouldAllowActiveUnlockFromOrigin(
+                ActiveUnlockConfig.ActiveUnlockRequestOrigin.WAKE))
+                .thenReturn(true);
+
+        // GIVEN an unfold should force dismiss the keyguard
+        when(mActiveUnlockConfig.shouldWakeupForceDismissKeyguard(
+                PowerManager.WAKE_REASON_UNFOLD_DEVICE)).thenReturn(true);
+
+        // WHEN device posture changes to unfold
+        deviceInPostureStateOpened();
+        mTestableLooper.processAllMessages();
+
+        // THEN request unlock with a keyguard dismissal
+        verify(mTrustManager).reportUserRequestedUnlock(eq(KeyguardUpdateMonitor.getCurrentUser()),
+                eq(true));
+    }
+
+
+    @Test
+    public void unfoldFromPostureChange_requestActiveUnlock_noDismissKeyguard()
+            throws RemoteException {
+        // GIVEN shouldTriggerActiveUnlock on wake from UNFOLD_DEVICE
+        keyguardIsVisible();
+        when(mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())).thenReturn(true);
+
+        // GIVEN active unlock triggers on wakeup
+        when(mActiveUnlockConfig.shouldAllowActiveUnlockFromOrigin(
+                ActiveUnlockConfig.ActiveUnlockRequestOrigin.WAKE))
+                .thenReturn(true);
+
+        // GIVEN an unfold should NOT force dismiss the keyguard
+        when(mActiveUnlockConfig.shouldWakeupForceDismissKeyguard(
+                PowerManager.WAKE_REASON_UNFOLD_DEVICE)).thenReturn(false);
+
+        // WHEN device posture changes to unfold
+        deviceInPostureStateOpened();
+        mTestableLooper.processAllMessages();
+
+        // THEN request unlock WITHOUT a keyguard dismissal
+        verify(mTrustManager).reportUserRequestedUnlock(eq(KeyguardUpdateMonitor.getCurrentUser()),
+                eq(false));
+    }
+
+    @Test
     public void detectFingerprint_onTemporaryLockoutReset_authenticateFingerprint() {
         ArgumentCaptor<FingerprintManager.LockoutResetCallback> fpLockoutResetCallbackCaptor =
                 ArgumentCaptor.forClass(FingerprintManager.LockoutResetCallback.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/FontInterpolatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/FontInterpolatorTest.kt
index f01da2d..8a5c5b5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/FontInterpolatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/FontInterpolatorTest.kt
@@ -61,7 +61,7 @@
         val interp = FontInterpolator()
         assertSameAxes(startFont, interp.lerp(startFont, endFont, 0f))
         assertSameAxes(endFont, interp.lerp(startFont, endFont, 1f))
-        assertSameAxes("'wght' 500, 'ital' 0.5, 'GRAD' 450", interp.lerp(startFont, endFont, 0.5f))
+        assertSameAxes("'wght' 496, 'ital' 0.5, 'GRAD' 450", interp.lerp(startFont, endFont, 0.5f))
     }
 
     @Test
@@ -74,7 +74,7 @@
                 .build()
 
         val interp = FontInterpolator()
-        assertSameAxes("'wght' 250, 'ital' 0.5", interp.lerp(startFont, endFont, 0.5f))
+        assertSameAxes("'wght' 249, 'ital' 0.5", interp.lerp(startFont, endFont, 0.5f))
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/FontVariationUtilsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/FontVariationUtilsTest.kt
new file mode 100644
index 0000000..070cad7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/FontVariationUtilsTest.kt
@@ -0,0 +1,62 @@
+package com.android.systemui.animation
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import junit.framework.Assert
+import org.junit.Test
+import org.junit.runner.RunWith
+
+private const val TAG_WGHT = "wght"
+private const val TAG_WDTH = "wdth"
+private const val TAG_OPSZ = "opsz"
+private const val TAG_ROND = "ROND"
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class FontVariationUtilsTest : SysuiTestCase() {
+    @Test
+    fun testUpdateFontVariation_getCorrectFvarStr() {
+        val fontVariationUtils = FontVariationUtils()
+        val initFvar =
+            fontVariationUtils.updateFontVariation(
+                weight = 100,
+                width = 100,
+                opticalSize = -1,
+                roundness = 100
+            )
+        Assert.assertEquals("'$TAG_WGHT' 100, '$TAG_WDTH' 100, '$TAG_ROND' 100", initFvar)
+        val updatedFvar =
+            fontVariationUtils.updateFontVariation(
+                weight = 200,
+                width = 100,
+                opticalSize = 0,
+                roundness = 100
+            )
+        Assert.assertEquals(
+            "'$TAG_WGHT' 200, '$TAG_WDTH' 100, '$TAG_OPSZ' 0, '$TAG_ROND' 100",
+            updatedFvar
+        )
+    }
+
+    @Test
+    fun testStyleValueUnchange_getBlankStr() {
+        val fontVariationUtils = FontVariationUtils()
+        fontVariationUtils.updateFontVariation(
+            weight = 100,
+            width = 100,
+            opticalSize = 0,
+            roundness = 100
+        )
+        val updatedFvar1 =
+            fontVariationUtils.updateFontVariation(
+                weight = 100,
+                width = 100,
+                opticalSize = 0,
+                roundness = 100
+            )
+        Assert.assertEquals("", updatedFvar1)
+        val updatedFvar2 = fontVariationUtils.updateFontVariation()
+        Assert.assertEquals("", updatedFvar2)
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/TextAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/TextAnimatorTest.kt
index 31d0d12..ed0cd7e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/TextAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/TextAnimatorTest.kt
@@ -19,7 +19,6 @@
 import android.animation.AnimatorListenerAdapter
 import android.animation.ValueAnimator
 import android.graphics.Typeface
-import android.graphics.fonts.FontVariationAxis
 import android.testing.AndroidTestingRunner
 import android.text.Layout
 import android.text.StaticLayout
@@ -179,71 +178,4 @@
 
         assertThat(paint.typeface).isSameInstanceAs(prevTypeface)
     }
-
-    @Test
-    fun testSetTextStyle_addWeight() {
-        testWeightChange("", 100, FontVariationAxis.fromFontVariationSettings("'wght' 100")!!)
-    }
-
-    @Test
-    fun testSetTextStyle_changeWeight() {
-        testWeightChange(
-                "'wght' 500",
-                100,
-                FontVariationAxis.fromFontVariationSettings("'wght' 100")!!
-        )
-    }
-
-    @Test
-    fun testSetTextStyle_addWeightWithOtherAxis() {
-        testWeightChange(
-                "'wdth' 100",
-                100,
-                FontVariationAxis.fromFontVariationSettings("'wght' 100, 'wdth' 100")!!
-        )
-    }
-
-    @Test
-    fun testSetTextStyle_changeWeightWithOtherAxis() {
-        testWeightChange(
-                "'wght' 500, 'wdth' 100",
-                100,
-                FontVariationAxis.fromFontVariationSettings("'wght' 100, 'wdth' 100")!!
-        )
-    }
-
-    private fun testWeightChange(
-            initialFontVariationSettings: String,
-            weight: Int,
-            expectedFontVariationSettings: Array<FontVariationAxis>
-    ) {
-        val layout = makeLayout("Hello, World", PAINT)
-        val valueAnimator = mock(ValueAnimator::class.java)
-        val textInterpolator = mock(TextInterpolator::class.java)
-        val paint =
-                TextPaint().apply {
-                    typeface = Typeface.createFromFile("/system/fonts/Roboto-Regular.ttf")
-                    fontVariationSettings = initialFontVariationSettings
-                }
-        `when`(textInterpolator.targetPaint).thenReturn(paint)
-
-        val textAnimator =
-                TextAnimator(layout, {}).apply {
-                    this.textInterpolator = textInterpolator
-                    this.animator = valueAnimator
-                }
-        textAnimator.setTextStyle(weight = weight, animate = false)
-
-        val resultFontVariationList =
-                FontVariationAxis.fromFontVariationSettings(
-                        textInterpolator.targetPaint.fontVariationSettings
-                )
-        expectedFontVariationSettings.forEach { expectedAxis ->
-            val resultAxis = resultFontVariationList?.filter { it.tag == expectedAxis.tag }?.get(0)
-            assertThat(resultAxis).isNotNull()
-            if (resultAxis != null) {
-                assertThat(resultAxis.styleValue).isEqualTo(expectedAxis.styleValue)
-            }
-        }
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintViewTest.kt
index 0574838..bce98cf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintViewTest.kt
@@ -15,49 +15,27 @@
  */
 package com.android.systemui.biometrics
 
-import android.content.Context
 import android.hardware.biometrics.BiometricAuthenticator
-import android.hardware.biometrics.SensorLocationInternal
-import android.hardware.biometrics.SensorProperties
-import android.hardware.display.DisplayManagerGlobal
-import android.hardware.fingerprint.FingerprintManager
-import android.hardware.fingerprint.FingerprintSensorProperties
-import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
 import android.os.Bundle
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.testing.TestableLooper.RunWithLooper
-import android.view.Display
-import android.view.DisplayAdjustments
-import android.view.DisplayInfo
-import android.view.Surface
 import android.view.View
-import android.view.ViewGroup
 import androidx.test.filters.SmallTest
-import com.airbnb.lottie.LottieAnimationView
 import com.android.systemui.R
-import com.android.systemui.biometrics.AuthBiometricView.STATE_AUTHENTICATING_ANIMATING_IN
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.SysuiTestableContext
 import com.google.common.truth.Truth.assertThat
 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.ArgumentMatchers
 import org.mockito.ArgumentMatchers.eq
 import org.mockito.Mock
-import org.mockito.Mockito.mock
 import org.mockito.Mockito.never
-import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
 import org.mockito.junit.MockitoJUnit
-import org.mockito.Mockito.`when` as whenEver
-
-private const val DISPLAY_ID = 2
-private const val SENSOR_ID = 1
 
 @RunWith(AndroidTestingRunner::class)
 @RunWithLooper(setAsMainLooper = true)
@@ -72,22 +50,9 @@
     private lateinit var callback: AuthBiometricView.Callback
 
     @Mock
-    private lateinit var fingerprintManager: FingerprintManager
-
-    @Mock
-    private lateinit var iconView: LottieAnimationView
-
-    @Mock
-    private lateinit var iconViewOverlay: LottieAnimationView
-
-    @Mock
-    private lateinit var iconLayoutParamSize: Pair<Int, Int>
-
-    @Mock
     private lateinit var panelController: AuthPanelController
 
     private lateinit var biometricView: AuthBiometricView
-    private lateinit var iconController: AuthBiometricFingerprintIconController
 
     private fun createView(allowDeviceCredential: Boolean = false): AuthBiometricFingerprintView {
         val view: AuthBiometricFingerprintView =
@@ -312,186 +277,5 @@
         verify(callback).onAction(AuthBiometricView.Callback.ACTION_USE_DEVICE_CREDENTIAL)
     }
 
-    private fun testWithSfpsDisplay(
-        isReverseDefaultRotation: Boolean = false,
-        inRearDisplayMode: Boolean = false,
-        isFolded: Boolean = false,
-        initInfo: DisplayInfo.() -> Unit = {},
-        block: () -> Unit
-    ) {
-        val displayInfo = DisplayInfo()
-        displayInfo.initInfo()
-
-        val dmGlobal = mock(DisplayManagerGlobal::class.java)
-        val display = Display(dmGlobal, DISPLAY_ID, displayInfo,
-            DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS)
-
-        whenEver(dmGlobal.getDisplayInfo(eq(DISPLAY_ID))).thenReturn(displayInfo)
-
-        val iconControllerContext = context.createDisplayContext(display) as SysuiTestableContext
-        iconControllerContext.orCreateTestableResources.addOverride(
-            com.android.internal.R.bool.config_reverseDefaultRotation,
-            isReverseDefaultRotation
-        )
-
-        val rearDisplayDeviceStates = if (inRearDisplayMode) intArrayOf(3) else intArrayOf()
-        iconControllerContext.orCreateTestableResources.addOverride(
-            com.android.internal.R.array.config_rearDisplayDeviceStates,
-            rearDisplayDeviceStates
-        )
-
-        val layoutParams = mock(ViewGroup.LayoutParams::class.java)
-        whenEver(iconView.layoutParams).thenReturn(layoutParams)
-        whenEver(iconViewOverlay.layoutParams).thenReturn(layoutParams)
-
-        var locations = listOf(SensorLocationInternal("", 2500, 0, 0))
-        whenEver(fingerprintManager.sensorPropertiesInternal)
-            .thenReturn(
-                listOf(
-                    FingerprintSensorPropertiesInternal(
-                        SENSOR_ID,
-                        SensorProperties.STRENGTH_STRONG,
-                        5 /* maxEnrollmentsPerUser */,
-                        listOf() /* componentInfo */,
-                        FingerprintSensorProperties.TYPE_POWER_BUTTON,
-                        true /* halControlsIllumination */,
-                        true /* resetLockoutRequiresHardwareAuthToken */,
-                        locations
-                    )
-                )
-            )
-        iconControllerContext.addMockSystemService(Context.FINGERPRINT_SERVICE, fingerprintManager)
-
-        iconController = AuthBiometricFingerprintIconController(
-            iconControllerContext,
-            iconView,
-            iconViewOverlay
-        )
-        iconController.onFoldUpdated(isFolded)
-
-        biometricView.mIconController = iconController
-        block()
-    }
-
-    @Test
-    fun sfpsRearDisplay_showsCorrectAnimationAssetsAcrossRotations() {
-        testWithSfpsDisplay(
-            isReverseDefaultRotation = false,
-            inRearDisplayMode = true,
-            isFolded = false,
-            { rotation = Surface.ROTATION_0 }
-        ) { biometricView.updateState(STATE_AUTHENTICATING_ANIMATING_IN) }
-        testWithSfpsDisplay(
-            isReverseDefaultRotation = false,
-            inRearDisplayMode = true,
-            isFolded = false,
-            { rotation = Surface.ROTATION_90 }
-        ) { biometricView.updateState(STATE_AUTHENTICATING_ANIMATING_IN) }
-        testWithSfpsDisplay(
-            isReverseDefaultRotation = false,
-            inRearDisplayMode = true,
-            isFolded = false,
-            { rotation = Surface.ROTATION_180 }
-        ) { biometricView.updateState(STATE_AUTHENTICATING_ANIMATING_IN) }
-        testWithSfpsDisplay(
-            isReverseDefaultRotation = false,
-            inRearDisplayMode = true,
-            isFolded = false,
-            { rotation = Surface.ROTATION_270 }
-        ) { biometricView.updateState(STATE_AUTHENTICATING_ANIMATING_IN) }
-        val expectedLottieAssetOrder: List<Int> = listOf(
-            R.raw.biometricprompt_rear_landscape_base,
-            R.raw.biometricprompt_rear_portrait_reverse_base,
-            R.raw.biometricprompt_rear_landscape_base,
-            R.raw.biometricprompt_rear_portrait_base,
-        )
-
-        val lottieAssetCaptor: ArgumentCaptor<Int> = ArgumentCaptor.forClass(Int::class.java)
-        verify(iconView, times(4)).setAnimation(lottieAssetCaptor.capture())
-        val observedLottieAssetOrder: List<Int> = lottieAssetCaptor.getAllValues()
-        assertThat(observedLottieAssetOrder).containsExactlyElementsIn(expectedLottieAssetOrder)
-                .inOrder()
-    }
-
-    @Test
-    fun sfpsDefaultDisplayFolded_showsAnimationsAssetsCorrectlyAcrossRotations() {
-        testWithSfpsDisplay(
-            isReverseDefaultRotation = false,
-            inRearDisplayMode = false,
-            isFolded = true,
-            { rotation = Surface.ROTATION_0 }
-        ) { biometricView.updateState(STATE_AUTHENTICATING_ANIMATING_IN) }
-            testWithSfpsDisplay(
-            isReverseDefaultRotation = false,
-            inRearDisplayMode = false,
-            isFolded = true,
-            { rotation = Surface.ROTATION_90 }
-        ) { biometricView.updateState(STATE_AUTHENTICATING_ANIMATING_IN); }
-            testWithSfpsDisplay(
-            isReverseDefaultRotation = false,
-            inRearDisplayMode = false,
-            isFolded = true,
-            { rotation = Surface.ROTATION_180 }
-        ) { biometricView.updateState(STATE_AUTHENTICATING_ANIMATING_IN); }
-            testWithSfpsDisplay(
-            isReverseDefaultRotation = false,
-            inRearDisplayMode = false,
-            isFolded = true,
-            { rotation = Surface.ROTATION_270 }
-        ) { biometricView.updateState(STATE_AUTHENTICATING_ANIMATING_IN); }
-        val expectedLottieAssetOrder: List<Int> = listOf(
-            R.raw.biometricprompt_folded_base_default,
-            R.raw.biometricprompt_folded_base_topleft,
-            R.raw.biometricprompt_folded_base_default,
-            R.raw.biometricprompt_folded_base_bottomright,
-        )
-
-        val lottieAssetCaptor: ArgumentCaptor<Int> = ArgumentCaptor.forClass(Int::class.java)
-        verify(iconView, times(4)).setAnimation(lottieAssetCaptor.capture())
-        val observedLottieAssetOrder: List<Int> = lottieAssetCaptor.getAllValues()
-        assertThat(observedLottieAssetOrder).containsExactlyElementsIn(expectedLottieAssetOrder)
-                .inOrder()
-    }
-
-    @Test
-    fun sfpsDefaultDisplayUnfolded_showsAnimationsAssetsCorrectlyAcrossRotations() {
-        testWithSfpsDisplay(
-            isReverseDefaultRotation = false,
-            inRearDisplayMode = false,
-            isFolded = false,
-            { rotation = Surface.ROTATION_0 }
-        ) { biometricView.updateState(STATE_AUTHENTICATING_ANIMATING_IN) }
-        testWithSfpsDisplay(
-            isReverseDefaultRotation = false,
-            inRearDisplayMode = false,
-            isFolded = false,
-            { rotation = Surface.ROTATION_90 }
-        ) { biometricView.updateState(STATE_AUTHENTICATING_ANIMATING_IN) }
-        testWithSfpsDisplay(
-            isReverseDefaultRotation = false,
-            inRearDisplayMode = false,
-            isFolded = false,
-            { rotation = Surface.ROTATION_180 }
-        ) { biometricView.updateState(STATE_AUTHENTICATING_ANIMATING_IN) }
-        testWithSfpsDisplay(
-            isReverseDefaultRotation = false,
-            inRearDisplayMode = false,
-            isFolded = false,
-            { rotation = Surface.ROTATION_270 }
-        ) { biometricView.updateState(STATE_AUTHENTICATING_ANIMATING_IN) }
-        val expectedLottieAssetOrder: List<Int> = listOf(
-            R.raw.biometricprompt_landscape_base,
-            R.raw.biometricprompt_portrait_base_topleft,
-            R.raw.biometricprompt_landscape_base,
-            R.raw.biometricprompt_portrait_base_bottomright,
-        )
-
-        val lottieAssetCaptor: ArgumentCaptor<Int> = ArgumentCaptor.forClass(Int::class.java)
-        verify(iconView, times(4)).setAnimation(lottieAssetCaptor.capture())
-        val observedLottieAssetOrder: List<Int> = lottieAssetCaptor.getAllValues()
-        assertThat(observedLottieAssetOrder).containsExactlyElementsIn(expectedLottieAssetOrder)
-                .inOrder()
-    }
-
     override fun waitForIdleSync() = TestableLooper.get(this).processAllMessages()
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
index b765ab3..a245c01 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
@@ -25,7 +25,9 @@
 import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.keyguard.KeyguardUpdateMonitorCallback
+import com.android.keyguard.logging.KeyguardLogger
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.logcatLogBuffer
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.keyguard.WakefulnessLifecycle
 import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -109,6 +111,7 @@
             udfpsControllerProvider,
             statusBarStateController,
             featureFlags,
+            KeyguardLogger(logcatLogBuffer(AuthRippleController.TAG)),
             rippleView
         )
         controller.init()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
index 3ec49b2..0ab675c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
@@ -62,6 +62,7 @@
 import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
 import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
 import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor
+import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.recents.OverviewProxyService
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.concurrency.FakeExecutor
@@ -98,7 +99,6 @@
 
     @JvmField @Rule var rule = MockitoJUnit.rule()
 
-    @Mock lateinit var keyguardStateController: KeyguardStateController
     @Mock lateinit var layoutInflater: LayoutInflater
     @Mock lateinit var fingerprintManager: FingerprintManager
     @Mock lateinit var windowManager: WindowManager
@@ -138,7 +138,8 @@
         keyguardBouncerRepository = FakeKeyguardBouncerRepository()
         alternateBouncerInteractor =
             AlternateBouncerInteractor(
-                keyguardStateController,
+                mock(StatusBarStateController::class.java),
+                mock(KeyguardStateController::class.java),
                 keyguardBouncerRepository,
                 FakeBiometricSettingsRepository(),
                 FakeDeviceEntryFingerprintAuthRepository(),
@@ -172,7 +173,6 @@
         isReverseDefaultRotation: Boolean = false,
         initInfo: DisplayInfo.() -> Unit = {},
         windowInsets: WindowInsets = insetsForSmallNavbar(),
-        inRearDisplayMode: Boolean = false,
         block: () -> Unit
     ) {
         this.deviceConfig = deviceConfig
@@ -233,12 +233,6 @@
             isReverseDefaultRotation
         )
 
-        val rearDisplayDeviceStates = if (inRearDisplayMode) intArrayOf(3) else intArrayOf()
-        sideFpsControllerContext.orCreateTestableResources.addOverride(
-            com.android.internal.R.array.config_rearDisplayDeviceStates,
-            rearDisplayDeviceStates
-        )
-
         sideFpsController =
             SideFpsController(
                 sideFpsControllerContext,
@@ -596,62 +590,10 @@
             verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true)
         }
 
-    @Test
-    fun verifiesSfpsIndicatorNotAddedInRearDisplayMode_0() =
-        testWithDisplay(
-            deviceConfig = DeviceConfig.Y_ALIGNED,
-            isReverseDefaultRotation = false,
-            { rotation = Surface.ROTATION_0 },
-            inRearDisplayMode = true,
-        ) {
-            verifySfpsIndicator_notAdded_InRearDisplayMode()
-        }
-
-    @Test
-    fun verifiesSfpsIndicatorNotAddedInRearDisplayMode_90() =
-        testWithDisplay(
-            deviceConfig = DeviceConfig.Y_ALIGNED,
-            isReverseDefaultRotation = false,
-            { rotation = Surface.ROTATION_90 },
-            inRearDisplayMode = true,
-        ) {
-            verifySfpsIndicator_notAdded_InRearDisplayMode()
-        }
-
-    @Test
-    fun verifiesSfpsIndicatorNotAddedInRearDisplayMode_180() =
-        testWithDisplay(
-            deviceConfig = DeviceConfig.Y_ALIGNED,
-            isReverseDefaultRotation = false,
-            { rotation = Surface.ROTATION_180 },
-            inRearDisplayMode = true,
-        ) {
-            verifySfpsIndicator_notAdded_InRearDisplayMode()
-        }
-
-    @Test
-    fun verifiesSfpsIndicatorNotAddedInRearDisplayMode_270() =
-        testWithDisplay(
-            deviceConfig = DeviceConfig.Y_ALIGNED,
-            isReverseDefaultRotation = false,
-            { rotation = Surface.ROTATION_270 },
-            inRearDisplayMode = true,
-        ) {
-            verifySfpsIndicator_notAdded_InRearDisplayMode()
-        }
-
     private fun verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible: Boolean) {
         sideFpsController.overlayOffsets = sensorLocation
     }
 
-    private fun verifySfpsIndicator_notAdded_InRearDisplayMode() {
-        sideFpsController.overlayOffsets = sensorLocation
-        overlayController.show(SENSOR_ID, REASON_UNKNOWN)
-        executor.runAllReady()
-
-        verify(windowManager, never()).addView(any(), any())
-    }
-
     fun alternateBouncerVisibility_showAndHideSideFpsUI() = testWithDisplay {
         // WHEN alternate bouncer is visible
         keyguardBouncerRepository.setAlternateVisible(true)
@@ -688,7 +630,7 @@
      * in other rotations have been omitted.
      */
     @Test
-    fun verifiesIndicatorPlacementForXAlignedSensor_0() =
+    fun verifiesIndicatorPlacementForXAlignedSensor_0() {
         testWithDisplay(
             deviceConfig = DeviceConfig.X_ALIGNED,
             isReverseDefaultRotation = false,
@@ -705,6 +647,7 @@
             assertThat(overlayViewParamsCaptor.value.x).isEqualTo(sensorLocation.sensorLocationX)
             assertThat(overlayViewParamsCaptor.value.y).isEqualTo(0)
         }
+    }
 
     /**
      * {@link SideFpsController#updateOverlayParams} calculates indicator placement for ROTATION_270
@@ -713,7 +656,7 @@
      * correctly, tests for indicator placement in other rotations have been omitted.
      */
     @Test
-    fun verifiesIndicatorPlacementForXAlignedSensor_InReverseDefaultRotation_270() =
+    fun verifiesIndicatorPlacementForXAlignedSensor_InReverseDefaultRotation_270() {
         testWithDisplay(
             deviceConfig = DeviceConfig.X_ALIGNED,
             isReverseDefaultRotation = true,
@@ -730,6 +673,7 @@
             assertThat(overlayViewParamsCaptor.value.x).isEqualTo(sensorLocation.sensorLocationX)
             assertThat(overlayViewParamsCaptor.value.y).isEqualTo(0)
         }
+    }
 
     /**
      * {@link SideFpsController#updateOverlayParams} calculates indicator placement for ROTATION_0,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt
index 86fb279..cefa9b1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt
@@ -35,6 +35,7 @@
 import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor
 import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants
 import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.statusbar.StatusBarState
 import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -93,6 +94,7 @@
             )
         mAlternateBouncerInteractor =
             AlternateBouncerInteractor(
+                mock(StatusBarStateController::class.java),
                 mock(KeyguardStateController::class.java),
                 keyguardBouncerRepository,
                 mock(BiometricSettingsRepository::class.java),
@@ -138,7 +140,7 @@
 
             // WHEN the bouncer expansion is VISIBLE
             val job = mController.listenForBouncerExpansion(this)
-            keyguardBouncerRepository.setPrimaryVisible(true)
+            keyguardBouncerRepository.setPrimaryShow(true)
             keyguardBouncerRepository.setPanelExpansion(KeyguardBouncerConstants.EXPANSION_VISIBLE)
             yield()
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogTest.java
index 3503902..9d16185 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogTest.java
@@ -45,8 +45,8 @@
 public class BroadcastDialogTest extends SysuiTestCase {
 
     private static final String CURRENT_BROADCAST_APP = "Music";
-    private static final String SWITCH_APP = "Files by Google";
-    private static final String TEST_PACKAGE = "com.google.android.apps.nbu.files";
+    private static final String SWITCH_APP = "System UI";
+    private static final String TEST_PACKAGE = "com.android.systemui";
     private BroadcastDialog mBroadcastDialog;
     private View mDialogView;
     private TextView mTitle;
@@ -59,6 +59,7 @@
         MockitoAnnotations.initMocks(this);
         mBroadcastDialog = new BroadcastDialog(mContext, mock(MediaOutputDialogFactory.class),
                 CURRENT_BROADCAST_APP, TEST_PACKAGE, mock(UiEventLogger.class));
+
         mBroadcastDialog.show();
         mDialogView = mBroadcastDialog.mDialogView;
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java
index faa5db4..ab6d5b7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java
@@ -94,7 +94,9 @@
         mClassifier.onTouchEvent(appendMoveEvent(1, 16, 3));
         mClassifier.onTouchEvent(appendMoveEvent(1, 17, 300));
         mClassifier.onTouchEvent(appendMoveEvent(1, 18, 301));
-        mClassifier.onTouchEvent(appendUpEvent(1, 19, 501));
+        mClassifier.onTouchEvent(appendMoveEvent(1, 19, 501));
+        mClassifier.onTouchEvent(appendUpEvent(1, 19, 501)); //event will be dropped
+
         assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isTrue();
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
index 2edc3d3..8eadadf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
@@ -75,16 +75,17 @@
     }
 
     @Test
-    public void test_trackMotionEvents() {
+    public void test_trackMotionEvents_dropUpEvent() {
         mDataProvider.onMotionEvent(appendDownEvent(2, 9));
         mDataProvider.onMotionEvent(appendMoveEvent(4, 7));
-        mDataProvider.onMotionEvent(appendUpEvent(6, 5));
+        mDataProvider.onMotionEvent(appendMoveEvent(6, 5));
+        mDataProvider.onMotionEvent(appendUpEvent(0, 0)); // event will be dropped
         List<MotionEvent> motionEventList = mDataProvider.getRecentMotionEvents();
 
         assertThat(motionEventList.size()).isEqualTo(3);
         assertThat(motionEventList.get(0).getActionMasked()).isEqualTo(MotionEvent.ACTION_DOWN);
         assertThat(motionEventList.get(1).getActionMasked()).isEqualTo(MotionEvent.ACTION_MOVE);
-        assertThat(motionEventList.get(2).getActionMasked()).isEqualTo(MotionEvent.ACTION_UP);
+        assertThat(motionEventList.get(2).getActionMasked()).isEqualTo(MotionEvent.ACTION_MOVE);
         assertThat(motionEventList.get(0).getEventTime()).isEqualTo(1L);
         assertThat(motionEventList.get(1).getEventTime()).isEqualTo(2L);
         assertThat(motionEventList.get(2).getEventTime()).isEqualTo(3L);
@@ -97,6 +98,28 @@
     }
 
     @Test
+    public void test_trackMotionEvents_keepUpEvent() {
+        mDataProvider.onMotionEvent(appendDownEvent(2, 9));
+        mDataProvider.onMotionEvent(appendMoveEvent(4, 7));
+        mDataProvider.onMotionEvent(appendUpEvent(0, 0, 100));
+        List<MotionEvent> motionEventList = mDataProvider.getRecentMotionEvents();
+
+        assertThat(motionEventList.size()).isEqualTo(3);
+        assertThat(motionEventList.get(0).getActionMasked()).isEqualTo(MotionEvent.ACTION_DOWN);
+        assertThat(motionEventList.get(1).getActionMasked()).isEqualTo(MotionEvent.ACTION_MOVE);
+        assertThat(motionEventList.get(2).getActionMasked()).isEqualTo(MotionEvent.ACTION_UP);
+        assertThat(motionEventList.get(0).getEventTime()).isEqualTo(1L);
+        assertThat(motionEventList.get(1).getEventTime()).isEqualTo(2L);
+        assertThat(motionEventList.get(2).getEventTime()).isEqualTo(100);
+        assertThat(motionEventList.get(0).getX()).isEqualTo(2f);
+        assertThat(motionEventList.get(1).getX()).isEqualTo(4f);
+        assertThat(motionEventList.get(2).getX()).isEqualTo(0f);
+        assertThat(motionEventList.get(0).getY()).isEqualTo(9f);
+        assertThat(motionEventList.get(1).getY()).isEqualTo(7f);
+        assertThat(motionEventList.get(2).getY()).isEqualTo(0f);
+    }
+
+    @Test
     public void test_trackRecentMotionEvents() {
         mDataProvider.onMotionEvent(appendDownEvent(2, 9, 1));
         mDataProvider.onMotionEvent(appendMoveEvent(4, 7, 800));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java
index c343c20..ae2b8bb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java
@@ -68,6 +68,15 @@
     }
 
     @Test
+    public void testPass_dropClosingUpEvent() {
+        appendMoveEvent(0, 0);
+        appendMoveEvent(0, 100);
+        appendMoveEvent(0, 200);
+        appendUpEvent(0, 180); // this event would push us over the maxDevianceY
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
+    }
+
+    @Test
     public void testPass_fewTouchesHorizontal() {
         assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
         appendMoveEvent(0, 0);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java
index 2099281..ffd75fb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java
@@ -35,6 +35,7 @@
 import static org.mockito.Mockito.when;
 
 import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.app.RemoteAction;
 import android.content.ClipData;
 import android.content.ClipDescription;
@@ -101,6 +102,9 @@
     private ArgumentCaptor<ClipboardOverlayView.ClipboardOverlayCallbacks> mOverlayCallbacksCaptor;
     private ClipboardOverlayView.ClipboardOverlayCallbacks mCallbacks;
 
+    @Captor
+    private ArgumentCaptor<AnimatorListenerAdapter> mAnimatorArgumentCaptor;
+
     private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
 
     @Before
@@ -446,7 +450,7 @@
         mFeatureFlags.set(CLIPBOARD_REMOTE_BEHAVIOR, true);
         when(mClipboardUtils.isRemoteCopy(any(Context.class), any(ClipData.class), anyString()))
                 .thenReturn(true);
-        when(mClipboardUtils.getAction(any(CharSequence.class), any(TextLinks.class), anyString()))
+        when(mClipboardUtils.getAction(any(TextLinks.class), anyString()))
                 .thenReturn(Optional.of(Mockito.mock(RemoteAction.class)));
         when(mClipboardOverlayView.post(any(Runnable.class))).thenAnswer(new Answer<Object>() {
             @Override
@@ -478,12 +482,16 @@
         when(mClipboardOverlayWindow.getWindowInsets()).thenReturn(
                 getImeInsets(new Rect(0, 0, 0, 1)));
         mOverlayController.setClipData(mSampleClipData, "");
+        Animator mockFadeoutAnimator = Mockito.mock(Animator.class);
+        when(mClipboardOverlayView.getMinimizedFadeoutAnimation()).thenReturn(mockFadeoutAnimator);
 
         verify(mClipboardOverlayView).setMinimized(true);
         verify(mClipboardOverlayView, never()).setMinimized(false);
         verify(mClipboardOverlayView, never()).showTextPreview(any(), anyBoolean());
 
         mCallbacks.onMinimizedViewTapped();
+        verify(mockFadeoutAnimator).addListener(mAnimatorArgumentCaptor.capture());
+        mAnimatorArgumentCaptor.getValue().onAnimationEnd(mockFadeoutAnimator);
 
         verify(mClipboardOverlayView).setMinimized(false);
         verify(mClipboardOverlayView).showTextPreview("Test Item", false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java
index aea6be3..3d8f04e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java
@@ -21,6 +21,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.Mockito.when;
 
@@ -77,6 +78,74 @@
 
     @Test
     public void test_getAction_noLinks_returnsEmptyOptional() {
+        Optional<RemoteAction> action =
+                mClipboardUtils.getAction(Mockito.mock(TextLinks.class), "abc");
+
+        assertTrue(action.isEmpty());
+    }
+
+    @Test
+    public void test_getAction_returnsFirstLink() {
+        TextLinks links = getFakeTextLinksBuilder().build();
+        RemoteAction actionA = constructRemoteAction("abc");
+        RemoteAction actionB = constructRemoteAction("def");
+        TextClassification classificationA = Mockito.mock(TextClassification.class);
+        when(classificationA.getActions()).thenReturn(Lists.newArrayList(actionA));
+        TextClassification classificationB = Mockito.mock(TextClassification.class);
+        when(classificationB.getActions()).thenReturn(Lists.newArrayList(actionB));
+        when(mTextClassifier.classifyText(anyString(), anyInt(), anyInt(), isNull())).thenReturn(
+                classificationA, classificationB);
+
+        RemoteAction result = mClipboardUtils.getAction(links, "test").orElse(null);
+
+        assertEquals(actionA, result);
+    }
+
+    @Test
+    public void test_getAction_skipsMatchingComponent() {
+        TextLinks links = getFakeTextLinksBuilder().build();
+        RemoteAction actionA = constructRemoteAction("abc");
+        RemoteAction actionB = constructRemoteAction("def");
+        TextClassification classificationA = Mockito.mock(TextClassification.class);
+        when(classificationA.getActions()).thenReturn(Lists.newArrayList(actionA));
+        TextClassification classificationB = Mockito.mock(TextClassification.class);
+        when(classificationB.getActions()).thenReturn(Lists.newArrayList(actionB));
+        when(mTextClassifier.classifyText(anyString(), anyInt(), anyInt(), isNull())).thenReturn(
+                classificationA, classificationB);
+
+        RemoteAction result = mClipboardUtils.getAction(links, "abc").orElse(null);
+
+        assertEquals(actionB, result);
+    }
+
+    @Test
+    public void test_getAction_skipsShortEntity() {
+        TextLinks.Builder textLinks = new TextLinks.Builder("test text of length 22");
+        final Map<String, Float> scores = new ArrayMap<>();
+        scores.put(TextClassifier.TYPE_EMAIL, 1f);
+        textLinks.addLink(20, 22, scores);
+        textLinks.addLink(0, 22, scores);
+
+        RemoteAction actionA = constructRemoteAction("abc");
+        RemoteAction actionB = constructRemoteAction("def");
+        TextClassification classificationA = Mockito.mock(TextClassification.class);
+        when(classificationA.getActions()).thenReturn(Lists.newArrayList(actionA));
+        TextClassification classificationB = Mockito.mock(TextClassification.class);
+        when(classificationB.getActions()).thenReturn(Lists.newArrayList(actionB));
+        when(mTextClassifier.classifyText(anyString(), eq(20), eq(22), isNull())).thenReturn(
+                classificationA);
+        when(mTextClassifier.classifyText(anyString(), eq(0), eq(22), isNull())).thenReturn(
+                classificationB);
+
+        RemoteAction result = mClipboardUtils.getAction(textLinks.build(), "test").orElse(null);
+
+        assertEquals(actionB, result);
+    }
+
+    // TODO(b/267162944): Next four tests (marked "legacy") are obsolete once
+    //  CLIPBOARD_MINIMIZED_LAYOUT flag is released and removed
+    @Test
+    public void test_getAction_noLinks_returnsEmptyOptional_legacy() {
         ClipData.Item item = new ClipData.Item("no text links");
         item.setTextLinks(Mockito.mock(TextLinks.class));
 
@@ -86,8 +155,8 @@
     }
 
     @Test
-    public void test_getAction_returnsFirstLink() {
-        when(mClipDataItem.getTextLinks()).thenReturn(getFakeTextLinks());
+    public void test_getAction_returnsFirstLink_legacy() {
+        when(mClipDataItem.getTextLinks()).thenReturn(getFakeTextLinksBuilder().build());
         when(mClipDataItem.getText()).thenReturn("");
         RemoteAction actionA = constructRemoteAction("abc");
         RemoteAction actionB = constructRemoteAction("def");
@@ -98,14 +167,14 @@
         when(mTextClassifier.classifyText(anyString(), anyInt(), anyInt(), isNull())).thenReturn(
                 classificationA, classificationB);
 
-        RemoteAction result = mClipboardUtils.getAction(mClipDataItem, "def").orElse(null);
+        RemoteAction result = mClipboardUtils.getAction(mClipDataItem, "test").orElse(null);
 
         assertEquals(actionA, result);
     }
 
     @Test
-    public void test_getAction_skipsMatchingComponent() {
-        when(mClipDataItem.getTextLinks()).thenReturn(getFakeTextLinks());
+    public void test_getAction_skipsMatchingComponent_legacy() {
+        when(mClipDataItem.getTextLinks()).thenReturn(getFakeTextLinksBuilder().build());
         when(mClipDataItem.getText()).thenReturn("");
         RemoteAction actionA = constructRemoteAction("abc");
         RemoteAction actionB = constructRemoteAction("def");
@@ -122,6 +191,33 @@
     }
 
     @Test
+    public void test_getAction_skipsShortEntity_legacy() {
+        TextLinks.Builder textLinks = new TextLinks.Builder("test text of length 22");
+        final Map<String, Float> scores = new ArrayMap<>();
+        scores.put(TextClassifier.TYPE_EMAIL, 1f);
+        textLinks.addLink(20, 22, scores);
+        textLinks.addLink(0, 22, scores);
+
+        when(mClipDataItem.getTextLinks()).thenReturn(textLinks.build());
+        when(mClipDataItem.getText()).thenReturn(textLinks.build().getText());
+
+        RemoteAction actionA = constructRemoteAction("abc");
+        RemoteAction actionB = constructRemoteAction("def");
+        TextClassification classificationA = Mockito.mock(TextClassification.class);
+        when(classificationA.getActions()).thenReturn(Lists.newArrayList(actionA));
+        TextClassification classificationB = Mockito.mock(TextClassification.class);
+        when(classificationB.getActions()).thenReturn(Lists.newArrayList(actionB));
+        when(mTextClassifier.classifyText(anyString(), eq(20), eq(22), isNull())).thenReturn(
+                classificationA);
+        when(mTextClassifier.classifyText(anyString(), eq(0), eq(22), isNull())).thenReturn(
+                classificationB);
+
+        RemoteAction result = mClipboardUtils.getAction(mClipDataItem, "test").orElse(null);
+
+        assertEquals(actionB, result);
+    }
+
+    @Test
     public void test_extra_withPackage_returnsTrue() {
         PersistableBundle b = new PersistableBundle();
         b.putBoolean(ClipDescription.EXTRA_IS_REMOTE_DEVICE, true);
@@ -184,12 +280,12 @@
         return action;
     }
 
-    private static TextLinks getFakeTextLinks() {
-        TextLinks.Builder textLinks = new TextLinks.Builder("test");
+    private static TextLinks.Builder getFakeTextLinksBuilder() {
+        TextLinks.Builder textLinks = new TextLinks.Builder("test text of length 22");
         final Map<String, Float> scores = new ArrayMap<>();
         scores.put(TextClassifier.TYPE_EMAIL, 1f);
-        textLinks.addLink(0, 0, scores);
-        textLinks.addLink(0, 0, scores);
-        return textLinks.build();
+        textLinks.addLink(0, 22, scores);
+        textLinks.addLink(0, 22, scores);
+        return textLinks;
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
index 28e80057..c98d537 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
@@ -34,6 +34,7 @@
 import com.android.systemui.controls.ControlsServiceInfo
 import com.android.systemui.controls.management.ControlsListingController
 import com.android.systemui.controls.panels.AuthorizedPanelsRepository
+import com.android.systemui.controls.panels.FakeSelectedComponentRepository
 import com.android.systemui.controls.ui.ControlsUiController
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.settings.UserFileManager
@@ -56,7 +57,6 @@
 import org.mockito.Captor
 import org.mockito.Mock
 import org.mockito.Mockito
-import org.mockito.Mockito.`when`
 import org.mockito.Mockito.anyInt
 import org.mockito.Mockito.clearInvocations
 import org.mockito.Mockito.inOrder
@@ -66,6 +66,7 @@
 import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.verifyNoMoreInteractions
+import org.mockito.Mockito.`when`
 import org.mockito.MockitoAnnotations
 import java.io.File
 import java.util.*
@@ -108,6 +109,8 @@
     private lateinit var listingCallbackCaptor:
             ArgumentCaptor<ControlsListingController.ControlsListingCallback>
 
+    private val preferredPanelRepository = FakeSelectedComponentRepository()
+
     private lateinit var delayableExecutor: FakeExecutor
     private lateinit var controller: ControlsControllerImpl
     private lateinit var canceller: DidRunRunnable
@@ -168,6 +171,7 @@
                 wrapper,
                 delayableExecutor,
                 uiController,
+                preferredPanelRepository,
                 bindingController,
                 listingController,
                 userFileManager,
@@ -221,6 +225,7 @@
                 mContext,
                 delayableExecutor,
                 uiController,
+                preferredPanelRepository,
                 bindingController,
                 listingController,
                 userFileManager,
@@ -240,6 +245,7 @@
                 mContext,
                 delayableExecutor,
                 uiController,
+                preferredPanelRepository,
                 bindingController,
                 listingController,
                 userFileManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
index 35cd3d2..10bfc1b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
@@ -45,6 +45,8 @@
 import com.android.systemui.util.mockito.capture
 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.After
 import org.junit.Assert.assertEquals
 import org.junit.Assert.assertNull
@@ -62,7 +64,6 @@
 import org.mockito.Mockito.reset
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
-import java.util.concurrent.Executor
 
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
@@ -106,6 +107,7 @@
         MockitoAnnotations.initMocks(this)
 
         `when`(userTracker.userId).thenReturn(user)
+        `when`(userTracker.userHandle).thenReturn(UserHandle.of(user))
         `when`(userTracker.userContext).thenReturn(context)
         // Return disabled by default
         `when`(packageManager.getComponentEnabledSetting(any()))
@@ -564,6 +566,79 @@
         assertTrue(controller.getCurrentServices().isEmpty())
     }
 
+    @Test
+    fun testForceReloadQueriesPackageManager() {
+        val user = 10
+        `when`(userTracker.userHandle).thenReturn(UserHandle.of(user))
+
+        controller.forceReload()
+        verify(packageManager).queryIntentServicesAsUser(
+                argThat(IntentMatcherAction(ControlsProviderService.SERVICE_CONTROLS)),
+                argThat(FlagsMatcher(
+                        PackageManager.GET_META_DATA.toLong() or
+                                PackageManager.GET_SERVICES.toLong() or
+                                PackageManager.MATCH_DIRECT_BOOT_AWARE.toLong() or
+                                PackageManager.MATCH_DIRECT_BOOT_UNAWARE.toLong()
+                )),
+                eq(UserHandle.of(user))
+        )
+    }
+
+    @Test
+    fun testForceReloadUpdatesList() {
+        val resolveInfo = ResolveInfo()
+        resolveInfo.serviceInfo = ServiceInfo(componentName)
+
+        `when`(packageManager.queryIntentServicesAsUser(
+                argThat(IntentMatcherAction(ControlsProviderService.SERVICE_CONTROLS)),
+                argThat(FlagsMatcher(
+                        PackageManager.GET_META_DATA.toLong() or
+                                PackageManager.GET_SERVICES.toLong() or
+                                PackageManager.MATCH_DIRECT_BOOT_AWARE.toLong() or
+                                PackageManager.MATCH_DIRECT_BOOT_UNAWARE.toLong()
+                )),
+                any<UserHandle>()
+        )).thenReturn(listOf(resolveInfo))
+
+        controller.forceReload()
+
+        val services = controller.getCurrentServices()
+        assertThat(services.size).isEqualTo(1)
+        assertThat(services[0].serviceInfo.componentName).isEqualTo(componentName)
+    }
+
+    @Test
+    fun testForceReloadCallsListeners() {
+        controller.addCallback(mockCallback)
+        executor.runAllReady()
+
+        @Suppress("unchecked_cast")
+        val captor: ArgumentCaptor<List<ControlsServiceInfo>> =
+                ArgumentCaptor.forClass(List::class.java)
+                        as ArgumentCaptor<List<ControlsServiceInfo>>
+
+        val resolveInfo = ResolveInfo()
+        resolveInfo.serviceInfo = ServiceInfo(componentName)
+
+        `when`(packageManager.queryIntentServicesAsUser(
+                any(),
+                any<PackageManager.ResolveInfoFlags>(),
+                any<UserHandle>()
+        )).thenReturn(listOf(resolveInfo))
+
+        reset(mockCallback)
+        controller.forceReload()
+
+        verify(mockCallback).onServicesUpdated(capture(captor))
+
+        val services = captor.value
+
+        assertThat(services.size).isEqualTo(1)
+        assertThat(services[0].serviceInfo.componentName).isEqualTo(componentName)
+    }
+
+
+
     private fun ServiceInfo(
             componentName: ComponentName,
             panelActivityComponentName: ComponentName? = null
@@ -600,7 +675,7 @@
     private fun setUpQueryResult(infos: List<ActivityInfo>) {
         `when`(
                 packageManager.queryIntentActivitiesAsUser(
-                        argThat(IntentMatcher(activityName)),
+                        argThat(IntentMatcherComponent(activityName)),
                         argThat(FlagsMatcher(FLAGS)),
                         eq(UserHandle.of(user))
                 )
@@ -609,7 +684,7 @@
         })
     }
 
-    private class IntentMatcher(
+    private class IntentMatcherComponent(
             private val componentName: ComponentName
     ) : ArgumentMatcher<Intent> {
         override fun matches(argument: Intent?): Boolean {
@@ -617,6 +692,14 @@
         }
     }
 
+    private class IntentMatcherAction(
+            private val action: String
+    ) : ArgumentMatcher<Intent> {
+        override fun matches(argument: Intent?): Boolean {
+            return argument?.action == action
+        }
+    }
+
     private class FlagsMatcher(
             private val flags: Long
     ) : ArgumentMatcher<PackageManager.ResolveInfoFlags> {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImplTest.kt
index 7ac1953..272f589 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImplTest.kt
@@ -22,6 +22,8 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.Flags
 import com.android.systemui.settings.UserFileManager
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.util.FakeSharedPreferences
@@ -40,6 +42,8 @@
 
     @Mock private lateinit var userTracker: UserTracker
 
+    private val featureFlags = FakeFeatureFlags()
+
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
@@ -48,6 +52,7 @@
             arrayOf<String>()
         )
         whenever(userTracker.userId).thenReturn(0)
+        featureFlags.set(Flags.APP_PANELS_REMOVE_APPS_ALLOWED, true)
     }
 
     @Test
@@ -127,8 +132,25 @@
         assertThat(sharedPrefs.getStringSet(KEY, null)).isEmpty()
     }
 
+    @Test
+    fun testSetAuthorizedPackageAfterFeatureDisabled() {
+        mContext.orCreateTestableResources.addOverride(
+            R.array.config_controlsPreferredPackages,
+            arrayOf(TEST_PACKAGE)
+        )
+        val sharedPrefs = FakeSharedPreferences()
+        val fileManager = FakeUserFileManager(mapOf(0 to sharedPrefs))
+        val repository = createRepository(fileManager)
+
+        repository.removeAuthorizedPanels(setOf(TEST_PACKAGE))
+
+        featureFlags.set(Flags.APP_PANELS_REMOVE_APPS_ALLOWED, false)
+
+        assertThat(repository.getAuthorizedPanels()).isEqualTo(setOf(TEST_PACKAGE))
+    }
+
     private fun createRepository(userFileManager: UserFileManager): AuthorizedPanelsRepositoryImpl {
-        return AuthorizedPanelsRepositoryImpl(mContext, userFileManager, userTracker)
+        return AuthorizedPanelsRepositoryImpl(mContext, userFileManager, userTracker, featureFlags)
     }
 
     private class FakeUserFileManager(private val sharedPrefs: Map<Int, SharedPreferences>) :
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/panels/FakeSelectedComponentRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/panels/FakeSelectedComponentRepository.kt
new file mode 100644
index 0000000..a7677cc
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/panels/FakeSelectedComponentRepository.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.controls.panels
+
+class FakeSelectedComponentRepository : SelectedComponentRepository {
+
+    private var selectedComponent: SelectedComponentRepository.SelectedComponent? = null
+    private var shouldAddDefaultPanel: Boolean = true
+
+    override fun getSelectedComponent(): SelectedComponentRepository.SelectedComponent? =
+        selectedComponent
+
+    override fun setSelectedComponent(
+        selectedComponent: SelectedComponentRepository.SelectedComponent
+    ) {
+        this.selectedComponent = selectedComponent
+    }
+
+    override fun removeSelectedComponent() {
+        selectedComponent = null
+    }
+
+    override fun shouldAddDefaultComponent(): Boolean = shouldAddDefaultPanel
+
+    override fun setShouldAddDefaultComponent(shouldAdd: Boolean) {
+        shouldAddDefaultPanel = shouldAdd
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/panels/SelectedComponentRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/panels/SelectedComponentRepositoryTest.kt
new file mode 100644
index 0000000..0c7b9cb
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/panels/SelectedComponentRepositoryTest.kt
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.controls.panels
+
+import android.content.ComponentName
+import android.content.SharedPreferences
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.settings.UserFileManager
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl
+import com.android.systemui.util.FakeSharedPreferences
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class SelectedComponentRepositoryTest : SysuiTestCase() {
+
+    private companion object {
+        val COMPONENT_A =
+            SelectedComponentRepository.SelectedComponent(
+                name = "a",
+                componentName = ComponentName.unflattenFromString("pkg/.cls_a"),
+                isPanel = false,
+            )
+        val COMPONENT_B =
+            SelectedComponentRepository.SelectedComponent(
+                name = "b",
+                componentName = ComponentName.unflattenFromString("pkg/.cls_b"),
+                isPanel = false,
+            )
+    }
+
+    @Mock private lateinit var userTracker: UserTracker
+    @Mock private lateinit var userFileManager: UserFileManager
+
+    private val featureFlags = FakeFeatureFlags()
+    private val sharedPreferences: SharedPreferences = FakeSharedPreferences()
+
+    // under test
+    private lateinit var repository: SelectedComponentRepository
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        whenever(userFileManager.getSharedPreferences(any(), any(), any()))
+            .thenReturn(sharedPreferences)
+
+        repository = SelectedComponentRepositoryImpl(userFileManager, userTracker, featureFlags)
+    }
+
+    @Test
+    fun testUnsetIsNull() {
+        assertThat(repository.getSelectedComponent()).isNull()
+    }
+
+    @Test
+    fun testGetReturnsSet() {
+        repository.setSelectedComponent(COMPONENT_A)
+
+        assertThat(repository.getSelectedComponent()).isEqualTo(COMPONENT_A)
+    }
+
+    @Test
+    fun testSetOverrides() {
+        repository.setSelectedComponent(COMPONENT_A)
+        repository.setSelectedComponent(COMPONENT_B)
+
+        assertThat(repository.getSelectedComponent()).isEqualTo(COMPONENT_B)
+    }
+
+    @Test
+    fun testRemove() {
+        repository.setSelectedComponent(COMPONENT_A)
+
+        repository.removeSelectedComponent()
+
+        assertThat(repository.getSelectedComponent()).isNull()
+    }
+
+    @Test
+    fun testFeatureEnabled_shouldAddDefaultPanelDefaultsToTrue() {
+        featureFlags.set(Flags.APP_PANELS_REMOVE_APPS_ALLOWED, true)
+
+        assertThat(repository.shouldAddDefaultComponent()).isTrue()
+    }
+
+    @Test
+    fun testFeatureDisabled_shouldAddDefaultPanelDefaultsToTrue() {
+        featureFlags.set(Flags.APP_PANELS_REMOVE_APPS_ALLOWED, false)
+
+        assertThat(repository.shouldAddDefaultComponent()).isTrue()
+    }
+
+    @Test
+    fun testFeatureEnabled_shouldAddDefaultPanelChecked() {
+        featureFlags.set(Flags.APP_PANELS_REMOVE_APPS_ALLOWED, true)
+        repository.setShouldAddDefaultComponent(false)
+
+        assertThat(repository.shouldAddDefaultComponent()).isFalse()
+    }
+
+    @Test
+    fun testFeatureDisabled_shouldAlwaysAddDefaultPanelAlwaysTrue() {
+        featureFlags.set(Flags.APP_PANELS_REMOVE_APPS_ALLOWED, false)
+        repository.setShouldAddDefaultComponent(false)
+
+        assertThat(repository.shouldAddDefaultComponent()).isTrue()
+    }
+
+    @Test
+    fun testGetPreferredStructure_differentUserId() {
+        sharedPreferences.savePanel(COMPONENT_A)
+        whenever(
+                userFileManager.getSharedPreferences(
+                    DeviceControlsControllerImpl.PREFS_CONTROLS_FILE,
+                    0,
+                    1,
+                )
+            )
+            .thenReturn(FakeSharedPreferences().also { it.savePanel(COMPONENT_B) })
+
+        val previousPreferredStructure = repository.getSelectedComponent()
+        whenever(userTracker.userId).thenReturn(1)
+        val currentPreferredStructure = repository.getSelectedComponent()
+
+        assertThat(previousPreferredStructure).isEqualTo(COMPONENT_A)
+        assertThat(currentPreferredStructure).isNotEqualTo(previousPreferredStructure)
+        assertThat(currentPreferredStructure).isEqualTo(COMPONENT_B)
+    }
+
+    private fun SharedPreferences.savePanel(panel: SelectedComponentRepository.SelectedComponent) {
+        edit()
+            .putString("controls_component", panel.componentName?.flattenToString())
+            .putString("controls_structure", panel.name)
+            .putBoolean("controls_is_panel", panel.isPanel)
+            .commit()
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/settings/ControlsSettingsDialogManagerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/settings/ControlsSettingsDialogManagerImplTest.kt
index 5a613aa..590989d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/settings/ControlsSettingsDialogManagerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/settings/ControlsSettingsDialogManagerImplTest.kt
@@ -45,6 +45,7 @@
 import org.mockito.ArgumentMatchers.anyBoolean
 import org.mockito.Mock
 import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.doAnswer
 import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when`
@@ -234,6 +235,36 @@
     }
 
     @Test
+    fun dialogPositiveButtonWhenCalledOnCompleteSettingIsTrue() {
+        sharedPreferences.putAttempts(0)
+        secureSettings.putBool(SETTING_SHOW, true)
+        secureSettings.putBool(SETTING_ACTION, false)
+
+        doAnswer { assertThat(secureSettings.getBool(SETTING_ACTION, false)).isTrue() }
+            .`when`(completedRunnable)
+            .invoke()
+
+        underTest.maybeShowDialog(context, completedRunnable)
+        clickButton(DialogInterface.BUTTON_POSITIVE)
+
+        verify(completedRunnable).invoke()
+    }
+
+    @Test
+    fun dialogPositiveCancelKeyguardStillCallsOnComplete() {
+        `when`(activityStarter.dismissKeyguardThenExecute(any(), nullable(), anyBoolean()))
+            .thenAnswer { (it.arguments[1] as Runnable).run() }
+        sharedPreferences.putAttempts(0)
+        secureSettings.putBool(SETTING_SHOW, true)
+        secureSettings.putBool(SETTING_ACTION, false)
+
+        underTest.maybeShowDialog(context, completedRunnable)
+        clickButton(DialogInterface.BUTTON_POSITIVE)
+
+        verify(completedRunnable).invoke()
+    }
+
+    @Test
     fun dialogCancelDoesntChangeSetting() {
         sharedPreferences.putAttempts(0)
         secureSettings.putBool(SETTING_SHOW, true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/start/ControlsStartableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/start/ControlsStartableTest.kt
index 7ecaca6..bd7e98e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/start/ControlsStartableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/start/ControlsStartableTest.kt
@@ -23,23 +23,27 @@
 import android.content.pm.ServiceInfo
 import android.testing.AndroidTestingRunner
 import androidx.test.filters.SmallTest
-import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.controls.ControlsServiceInfo
 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.controls.panels.AuthorizedPanelsRepository
+import com.android.systemui.controls.panels.FakeSelectedComponentRepository
 import com.android.systemui.controls.ui.SelectedItem
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
 import com.android.systemui.util.time.FakeSystemClock
 import java.util.Optional
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mock
+import org.mockito.Mockito.doAnswer
+import org.mockito.Mockito.doReturn
 import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.verifyZeroInteractions
@@ -53,16 +57,16 @@
     @Mock private lateinit var controlsController: ControlsController
     @Mock private lateinit var controlsListingController: ControlsListingController
     @Mock private lateinit var userTracker: UserTracker
+    @Mock private lateinit var authorizedPanelsRepository: AuthorizedPanelsRepository
+
+    private val preferredPanelsRepository = FakeSelectedComponentRepository()
 
     private lateinit var fakeExecutor: FakeExecutor
 
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
-        context.orCreateTestableResources.addOverride(
-            R.array.config_controlsPreferredPackages,
-            arrayOf<String>()
-        )
+        whenever(authorizedPanelsRepository.getPreferredPackages()).thenReturn(setOf())
 
         fakeExecutor = FakeExecutor(FakeSystemClock())
     }
@@ -78,107 +82,102 @@
     fun testNoPreferredPackagesNoDefaultSelected_noNewSelection() {
         `when`(controlsController.getPreferredSelection()).thenReturn(SelectedItem.EMPTY_SELECTION)
         val listings = listOf(ControlsServiceInfo(TEST_COMPONENT_PANEL, "panel", hasPanel = true))
-        `when`(controlsListingController.getCurrentServices()).thenReturn(listings)
+        setUpControlsListingControls(listings)
 
         createStartable(enabled = true).start()
+        fakeExecutor.runAllReady()
 
         verify(controlsController, never()).setPreferredSelection(any())
     }
 
     @Test
     fun testPreferredPackagesNotInstalled_noNewSelection() {
-        context.orCreateTestableResources.addOverride(
-            R.array.config_controlsPreferredPackages,
-            arrayOf(TEST_PACKAGE_PANEL)
-        )
+        whenever(authorizedPanelsRepository.getPreferredPackages())
+            .thenReturn(setOf(TEST_PACKAGE_PANEL))
         `when`(controlsController.getPreferredSelection()).thenReturn(SelectedItem.EMPTY_SELECTION)
-        `when`(controlsListingController.getCurrentServices()).thenReturn(emptyList())
+        setUpControlsListingControls(emptyList())
 
         createStartable(enabled = true).start()
+        fakeExecutor.runAllReady()
 
         verify(controlsController, never()).setPreferredSelection(any())
     }
 
     @Test
     fun testPreferredPackageNotPanel_noNewSelection() {
-        context.orCreateTestableResources.addOverride(
-            R.array.config_controlsPreferredPackages,
-            arrayOf(TEST_PACKAGE_PANEL)
-        )
+        whenever(authorizedPanelsRepository.getPreferredPackages())
+            .thenReturn(setOf(TEST_PACKAGE_PANEL))
         `when`(controlsController.getPreferredSelection()).thenReturn(SelectedItem.EMPTY_SELECTION)
         val listings = listOf(ControlsServiceInfo(TEST_COMPONENT, "not panel", hasPanel = false))
-        `when`(controlsListingController.getCurrentServices()).thenReturn(listings)
+        setUpControlsListingControls(listings)
 
         createStartable(enabled = true).start()
+        fakeExecutor.runAllReady()
 
         verify(controlsController, never()).setPreferredSelection(any())
     }
 
     @Test
     fun testExistingSelection_noNewSelection() {
-        context.orCreateTestableResources.addOverride(
-            R.array.config_controlsPreferredPackages,
-            arrayOf(TEST_PACKAGE_PANEL)
-        )
+        whenever(authorizedPanelsRepository.getPreferredPackages())
+            .thenReturn(setOf(TEST_PACKAGE_PANEL))
         `when`(controlsController.getPreferredSelection())
             .thenReturn(mock<SelectedItem.PanelItem>())
         val listings = listOf(ControlsServiceInfo(TEST_COMPONENT_PANEL, "panel", hasPanel = true))
-        `when`(controlsListingController.getCurrentServices()).thenReturn(listings)
+        setUpControlsListingControls(listings)
 
         createStartable(enabled = true).start()
+        fakeExecutor.runAllReady()
 
         verify(controlsController, never()).setPreferredSelection(any())
     }
 
     @Test
     fun testPanelAdded() {
-        context.orCreateTestableResources.addOverride(
-            R.array.config_controlsPreferredPackages,
-            arrayOf(TEST_PACKAGE_PANEL)
-        )
+        whenever(authorizedPanelsRepository.getPreferredPackages())
+            .thenReturn(setOf(TEST_PACKAGE_PANEL))
         `when`(controlsController.getPreferredSelection()).thenReturn(SelectedItem.EMPTY_SELECTION)
         val listings = listOf(ControlsServiceInfo(TEST_COMPONENT_PANEL, "panel", hasPanel = true))
-        `when`(controlsListingController.getCurrentServices()).thenReturn(listings)
+        setUpControlsListingControls(listings)
 
         createStartable(enabled = true).start()
+        fakeExecutor.runAllReady()
 
         verify(controlsController).setPreferredSelection(listings[0].toPanelItem())
     }
 
     @Test
     fun testMultiplePreferredOnlyOnePanel_panelAdded() {
-        context.orCreateTestableResources.addOverride(
-            R.array.config_controlsPreferredPackages,
-            arrayOf("other_package", TEST_PACKAGE_PANEL)
-        )
+        whenever(authorizedPanelsRepository.getPreferredPackages())
+            .thenReturn(setOf(TEST_PACKAGE_PANEL))
         `when`(controlsController.getPreferredSelection()).thenReturn(SelectedItem.EMPTY_SELECTION)
         val listings =
             listOf(
                 ControlsServiceInfo(TEST_COMPONENT_PANEL, "panel", hasPanel = true),
                 ControlsServiceInfo(ComponentName("other_package", "cls"), "non panel", false)
             )
-        `when`(controlsListingController.getCurrentServices()).thenReturn(listings)
+        setUpControlsListingControls(listings)
 
         createStartable(enabled = true).start()
+        fakeExecutor.runAllReady()
 
         verify(controlsController).setPreferredSelection(listings[0].toPanelItem())
     }
 
     @Test
     fun testMultiplePreferredMultiplePanels_firstPreferredAdded() {
-        context.orCreateTestableResources.addOverride(
-            R.array.config_controlsPreferredPackages,
-            arrayOf(TEST_PACKAGE_PANEL, "other_package")
-        )
+        whenever(authorizedPanelsRepository.getPreferredPackages())
+            .thenReturn(setOf(TEST_PACKAGE_PANEL))
         `when`(controlsController.getPreferredSelection()).thenReturn(SelectedItem.EMPTY_SELECTION)
         val listings =
             listOf(
                 ControlsServiceInfo(ComponentName("other_package", "cls"), "panel", true),
                 ControlsServiceInfo(TEST_COMPONENT_PANEL, "panel", hasPanel = true)
             )
-        `when`(controlsListingController.getCurrentServices()).thenReturn(listings)
+        setUpControlsListingControls(listings)
 
         createStartable(enabled = true).start()
+        fakeExecutor.runAllReady()
 
         verify(controlsController).setPreferredSelection(listings[1].toPanelItem())
     }
@@ -186,10 +185,11 @@
     @Test
     fun testPreferredSelectionIsPanel_bindOnStart() {
         val listings = listOf(ControlsServiceInfo(TEST_COMPONENT_PANEL, "panel", hasPanel = true))
-        `when`(controlsListingController.getCurrentServices()).thenReturn(listings)
+        setUpControlsListingControls(listings)
         `when`(controlsController.getPreferredSelection()).thenReturn(listings[0].toPanelItem())
 
         createStartable(enabled = true).start()
+        fakeExecutor.runAllReady()
 
         verify(controlsController).bindComponentForPanel(TEST_COMPONENT_PANEL)
     }
@@ -197,11 +197,12 @@
     @Test
     fun testPreferredSelectionPanel_listingNoPanel_notBind() {
         val listings = listOf(ControlsServiceInfo(TEST_COMPONENT_PANEL, "panel", hasPanel = false))
-        `when`(controlsListingController.getCurrentServices()).thenReturn(listings)
+        setUpControlsListingControls(listings)
         `when`(controlsController.getPreferredSelection())
             .thenReturn(SelectedItem.PanelItem("panel", TEST_COMPONENT_PANEL))
 
         createStartable(enabled = true).start()
+        fakeExecutor.runAllReady()
 
         verify(controlsController, never()).bindComponentForPanel(any())
     }
@@ -209,14 +210,35 @@
     @Test
     fun testNotPanelSelection_noBind() {
         val listings = listOf(ControlsServiceInfo(TEST_COMPONENT_PANEL, "panel", hasPanel = false))
-        `when`(controlsListingController.getCurrentServices()).thenReturn(listings)
+        setUpControlsListingControls(listings)
         `when`(controlsController.getPreferredSelection()).thenReturn(SelectedItem.EMPTY_SELECTION)
 
         createStartable(enabled = true).start()
+        fakeExecutor.runAllReady()
 
         verify(controlsController, never()).bindComponentForPanel(any())
     }
 
+    @Test
+    fun testAlreadyAddedPanel_noNewSelection() {
+        preferredPanelsRepository.setShouldAddDefaultComponent(false)
+        whenever(authorizedPanelsRepository.getPreferredPackages())
+            .thenReturn(setOf(TEST_PACKAGE_PANEL))
+        `when`(controlsController.getPreferredSelection()).thenReturn(SelectedItem.EMPTY_SELECTION)
+        val listings = listOf(ControlsServiceInfo(TEST_COMPONENT_PANEL, "panel", hasPanel = true))
+        `when`(controlsListingController.getCurrentServices()).thenReturn(listings)
+
+        createStartable(enabled = true).start()
+
+        verify(controlsController, never()).setPreferredSelection(any())
+    }
+
+    private fun setUpControlsListingControls(listings: List<ControlsServiceInfo>) {
+        doAnswer { doReturn(listings).`when`(controlsListingController).getCurrentServices() }
+            .`when`(controlsListingController)
+            .forceReload()
+    }
+
     private fun createStartable(enabled: Boolean): ControlsStartable {
         val component: ControlsComponent =
             mock() {
@@ -230,7 +252,13 @@
                     `when`(getControlsListingController()).thenReturn(Optional.empty())
                 }
             }
-        return ControlsStartable(context.resources, fakeExecutor, component, userTracker)
+        return ControlsStartable(
+            fakeExecutor,
+            component,
+            userTracker,
+            authorizedPanelsRepository,
+            preferredPanelsRepository,
+        )
     }
 
     private fun ControlsServiceInfo(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsActivityTest.kt
new file mode 100644
index 0000000..0f62b24
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsActivityTest.kt
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.controls.ui
+
+import android.content.Intent
+import android.content.res.Configuration
+import android.service.dreams.IDreamManager
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import androidx.test.rule.ActivityTestRule
+import androidx.test.runner.intercepting.SingleActivityFactory
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.controls.settings.ControlsSettingsDialogManager
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class ControlsActivityTest : SysuiTestCase() {
+    @Mock private lateinit var uiController: ControlsUiController
+    @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher
+    @Mock private lateinit var dreamManager: IDreamManager
+    @Mock private lateinit var featureFlags: FeatureFlags
+    @Mock private lateinit var controlsSettingsDialogManager: ControlsSettingsDialogManager
+    @Mock private lateinit var keyguardStateController: KeyguardStateController
+
+    @Rule
+    @JvmField
+    var activityRule =
+        ActivityTestRule(
+            object :
+                SingleActivityFactory<TestableControlsActivity>(
+                    TestableControlsActivity::class.java
+                ) {
+                override fun create(intent: Intent?): TestableControlsActivity {
+                    return TestableControlsActivity(
+                        uiController,
+                        broadcastDispatcher,
+                        dreamManager,
+                        featureFlags,
+                        controlsSettingsDialogManager,
+                        keyguardStateController,
+                    )
+                }
+            },
+            false,
+            false
+        )
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+        activityRule.launchActivity(Intent())
+    }
+
+    @Test
+    fun testOrientationChangeForwardsToUiController() {
+        val currentConfig = activityRule.activity.resources.configuration
+        val newConfig = Configuration(currentConfig)
+        newConfig.orientation = switchOrientation(currentConfig.orientation)
+        activityRule.runOnUiThread { activityRule.activity.onConfigurationChanged(newConfig) }
+
+        verify(uiController).onSizeChange()
+    }
+
+    @Test
+    fun testScreenChangeForwardsToUiController() {
+        val currentConfig = activityRule.activity.resources.configuration
+        val newConfig = Configuration(currentConfig)
+        swapHeightWidth(newConfig)
+        activityRule.runOnUiThread { activityRule.activity.onConfigurationChanged(newConfig) }
+
+        verify(uiController).onSizeChange()
+    }
+
+    @Test
+    fun testChangeSmallestScreenSizeForwardsToUiController() {
+        val currentConfig = activityRule.activity.resources.configuration
+        val newConfig = Configuration(currentConfig)
+        newConfig.smallestScreenWidthDp *= 2
+        newConfig.screenWidthDp *= 2
+        activityRule.runOnUiThread { activityRule.activity.onConfigurationChanged(newConfig) }
+
+        verify(uiController).onSizeChange()
+    }
+
+    private fun switchOrientation(orientation: Int): Int {
+        return if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
+            Configuration.ORIENTATION_PORTRAIT
+        } else {
+            Configuration.ORIENTATION_LANDSCAPE
+        }
+    }
+
+    private fun swapHeightWidth(configuration: Configuration) {
+        val oldHeight = configuration.screenHeightDp
+        val oldWidth = configuration.screenWidthDp
+        configuration.screenHeightDp = oldWidth
+        configuration.screenWidthDp = oldHeight
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt
index 23faa99..91f279c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt
@@ -42,16 +42,14 @@
 import com.android.systemui.controls.management.ControlsListingController
 import com.android.systemui.controls.management.ControlsProviderSelectorActivity
 import com.android.systemui.controls.panels.AuthorizedPanelsRepository
+import com.android.systemui.controls.panels.FakeSelectedComponentRepository
+import com.android.systemui.controls.panels.SelectedComponentRepository
 import com.android.systemui.controls.settings.FakeControlsSettingsRepository
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.settings.UserFileManager
 import com.android.systemui.settings.UserTracker
-import com.android.systemui.shade.ShadeController
-import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl
 import com.android.systemui.statusbar.policy.KeyguardStateController
-import com.android.systemui.util.FakeSharedPreferences
 import com.android.systemui.util.FakeSystemUIDialogController
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.mockito.any
@@ -64,20 +62,18 @@
 import com.android.wm.shell.TaskView
 import com.android.wm.shell.TaskViewFactory
 import com.google.common.truth.Truth.assertThat
+import java.util.Optional
+import java.util.function.Consumer
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mock
-import org.mockito.Mockito.`when`
-import org.mockito.Mockito.anyInt
-import org.mockito.Mockito.anyString
 import org.mockito.Mockito.clearInvocations
 import org.mockito.Mockito.never
 import org.mockito.Mockito.spy
 import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
 import org.mockito.MockitoAnnotations
-import java.util.Optional
-import java.util.function.Consumer
 
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
@@ -87,11 +83,9 @@
     @Mock lateinit var controlsListingController: ControlsListingController
     @Mock lateinit var controlActionCoordinator: ControlActionCoordinator
     @Mock lateinit var activityStarter: ActivityStarter
-    @Mock lateinit var shadeController: ShadeController
     @Mock lateinit var iconCache: CustomIconCache
     @Mock lateinit var controlsMetricsLogger: ControlsMetricsLogger
     @Mock lateinit var keyguardStateController: KeyguardStateController
-    @Mock lateinit var userFileManager: UserFileManager
     @Mock lateinit var userTracker: UserTracker
     @Mock lateinit var taskViewFactory: TaskViewFactory
     @Mock lateinit var dumpManager: DumpManager
@@ -99,7 +93,7 @@
     @Mock lateinit var featureFlags: FeatureFlags
     @Mock lateinit var packageManager: PackageManager
 
-    private val sharedPreferences = FakeSharedPreferences()
+    private val preferredPanelRepository = FakeSelectedComponentRepository()
     private val fakeDialogController = FakeSystemUIDialogController()
     private val uiExecutor = FakeExecutor(FakeSystemClock())
     private val bgExecutor = FakeExecutor(FakeSystemClock())
@@ -138,94 +132,30 @@
                 iconCache,
                 controlsMetricsLogger,
                 keyguardStateController,
-                userFileManager,
                 userTracker,
                 Optional.of(taskViewFactory),
                 controlsSettingsRepository,
                 authorizedPanelsRepository,
+                preferredPanelRepository,
                 featureFlags,
                 ControlsDialogsFactory { fakeDialogController.dialog },
                 dumpManager,
             )
-        `when`(
-                userFileManager.getSharedPreferences(
-                    DeviceControlsControllerImpl.PREFS_CONTROLS_FILE,
-                    0,
-                    0
-                )
-            )
-            .thenReturn(sharedPreferences)
-        `when`(userFileManager.getSharedPreferences(anyString(), anyInt(), anyInt()))
-            .thenReturn(sharedPreferences)
         `when`(userTracker.userId).thenReturn(0)
         `when`(userTracker.userHandle).thenReturn(UserHandle.of(0))
     }
 
     @Test
-    fun testGetPreferredStructure() {
-        val structureInfo = mock<StructureInfo>()
-        underTest.getPreferredSelectedItem(listOf(structureInfo))
-        verify(userFileManager)
-            .getSharedPreferences(
-                fileName = DeviceControlsControllerImpl.PREFS_CONTROLS_FILE,
-                mode = 0,
-                userId = 0
-            )
-    }
-
-    @Test
-    fun testGetPreferredStructure_differentUserId() {
-        val selectedItems =
-            listOf(
-                SelectedItem.StructureItem(
-                    StructureInfo(ComponentName.unflattenFromString("pkg/.cls1"), "a", ArrayList())
-                ),
-                SelectedItem.StructureItem(
-                    StructureInfo(ComponentName.unflattenFromString("pkg/.cls2"), "b", ArrayList())
-                ),
-            )
-        val structures = selectedItems.map { it.structure }
-        sharedPreferences
-            .edit()
-            .putString("controls_component", selectedItems[0].componentName.flattenToString())
-            .putString("controls_structure", selectedItems[0].name.toString())
-            .commit()
-
-        val differentSharedPreferences = FakeSharedPreferences()
-        differentSharedPreferences
-            .edit()
-            .putString("controls_component", selectedItems[1].componentName.flattenToString())
-            .putString("controls_structure", selectedItems[1].name.toString())
-            .commit()
-
-        val previousPreferredStructure = underTest.getPreferredSelectedItem(structures)
-
-        `when`(
-                userFileManager.getSharedPreferences(
-                    DeviceControlsControllerImpl.PREFS_CONTROLS_FILE,
-                    0,
-                    1
-                )
-            )
-            .thenReturn(differentSharedPreferences)
-        `when`(userTracker.userId).thenReturn(1)
-
-        val currentPreferredStructure = underTest.getPreferredSelectedItem(structures)
-
-        assertThat(previousPreferredStructure).isEqualTo(selectedItems[0])
-        assertThat(currentPreferredStructure).isEqualTo(selectedItems[1])
-        assertThat(currentPreferredStructure).isNotEqualTo(previousPreferredStructure)
-    }
-
-    @Test
     fun testGetPreferredPanel() {
         val panel = SelectedItem.PanelItem("App name", ComponentName("pkg", "cls"))
-        sharedPreferences
-            .edit()
-            .putString("controls_component", panel.componentName.flattenToString())
-            .putString("controls_structure", panel.appName.toString())
-            .putBoolean("controls_is_panel", true)
-            .commit()
+
+        preferredPanelRepository.setSelectedComponent(
+            SelectedComponentRepository.SelectedComponent(
+                name = panel.appName.toString(),
+                componentName = panel.componentName,
+                isPanel = true,
+            )
+        )
 
         val selected = underTest.getPreferredSelectedItem(emptyList())
 
@@ -271,6 +201,56 @@
     }
 
     @Test
+    fun testSingleAppHeaderIsNotClickable() {
+        mockLayoutInflater()
+        val packageName = "pkg"
+        `when`(authorizedPanelsRepository.getAuthorizedPanels()).thenReturn(setOf(packageName))
+        val panel = SelectedItem.PanelItem("App name", ComponentName(packageName, "cls"))
+        val serviceInfo = setUpPanel(panel)
+
+        underTest.show(parent, {}, context)
+
+        val captor = argumentCaptor<ControlsListingController.ControlsListingCallback>()
+
+        verify(controlsListingController).addCallback(capture(captor))
+
+        captor.value.onServicesUpdated(listOf(serviceInfo))
+        FakeExecutor.exhaustExecutors(uiExecutor, bgExecutor)
+
+        val header: View = parent.requireViewById(R.id.controls_header)
+        assertThat(header.isClickable).isFalse()
+        assertThat(header.hasOnClickListeners()).isFalse()
+    }
+
+    @Test
+    fun testMultipleAppHeaderIsClickable() {
+        mockLayoutInflater()
+        val packageName1 = "pkg"
+        val panel1 = SelectedItem.PanelItem("App name 1", ComponentName(packageName1, "cls"))
+        val serviceInfo1 = setUpPanel(panel1)
+
+        val packageName2 = "pkg"
+        val panel2 = SelectedItem.PanelItem("App name 2", ComponentName(packageName2, "cls"))
+        val serviceInfo2 = setUpPanel(panel2)
+
+        `when`(authorizedPanelsRepository.getAuthorizedPanels())
+                .thenReturn(setOf(packageName1, packageName2))
+
+        underTest.show(parent, {}, context)
+
+        val captor = argumentCaptor<ControlsListingController.ControlsListingCallback>()
+
+        verify(controlsListingController).addCallback(capture(captor))
+
+        captor.value.onServicesUpdated(listOf(serviceInfo1, serviceInfo2))
+        FakeExecutor.exhaustExecutors(uiExecutor, bgExecutor)
+
+        val header: View = parent.requireViewById(R.id.controls_header)
+        assertThat(header.isClickable).isTrue()
+        assertThat(header.hasOnClickListeners()).isTrue()
+    }
+
+    @Test
     fun testPanelControllerStartActivityWithCorrectArguments() {
         mockLayoutInflater()
         val packageName = "pkg"
@@ -369,11 +349,9 @@
                     StructureInfo(ComponentName.unflattenFromString("pkg/.cls1"), "a", ArrayList())
                 ),
             )
-        sharedPreferences
-            .edit()
-            .putString("controls_component", selectedItems[0].componentName.flattenToString())
-            .putString("controls_structure", selectedItems[0].name.toString())
-            .commit()
+        preferredPanelRepository.setSelectedComponent(
+            SelectedComponentRepository.SelectedComponent(selectedItems[0])
+        )
 
         assertThat(underTest.resolveActivity())
             .isEqualTo(ControlsProviderSelectorActivity::class.java)
@@ -418,12 +396,9 @@
         val componentName = ComponentName(context, "cls")
         whenever(controlsController.removeFavorites(eq(componentName))).thenReturn(true)
         val panel = SelectedItem.PanelItem("App name", componentName)
-        sharedPreferences
-            .edit()
-            .putString("controls_component", panel.componentName.flattenToString())
-            .putString("controls_structure", panel.appName.toString())
-            .putBoolean("controls_is_panel", true)
-            .commit()
+        preferredPanelRepository.setSelectedComponent(
+                SelectedComponentRepository.SelectedComponent(panel)
+        )
         underTest.show(parent, {}, context)
         underTest.startRemovingApp(componentName, "Test App")
 
@@ -432,11 +407,8 @@
         verify(controlsController).removeFavorites(eq(componentName))
         assertThat(underTest.getPreferredSelectedItem(emptyList()))
             .isEqualTo(SelectedItem.EMPTY_SELECTION)
-        with(sharedPreferences) {
-            assertThat(contains("controls_component")).isFalse()
-            assertThat(contains("controls_structure")).isFalse()
-            assertThat(contains("controls_is_panel")).isFalse()
-        }
+        assertThat(preferredPanelRepository.shouldAddDefaultComponent()).isFalse()
+        assertThat(preferredPanelRepository.getSelectedComponent()).isNull()
     }
 
     @Test
@@ -450,14 +422,43 @@
         verify(fakeDialogController.dialog).cancel()
     }
 
+    @Test
+    fun testOnRotationWithPanelUpdateBoundsCalled() {
+        mockLayoutInflater()
+        val packageName = "pkg"
+        `when`(authorizedPanelsRepository.getAuthorizedPanels()).thenReturn(setOf(packageName))
+        val panel = SelectedItem.PanelItem("App name", ComponentName(packageName, "cls"))
+        val serviceInfo = setUpPanel(panel)
+
+        underTest.show(parent, {}, context)
+
+        val captor = argumentCaptor<ControlsListingController.ControlsListingCallback>()
+
+        verify(controlsListingController).addCallback(capture(captor))
+        captor.value.onServicesUpdated(listOf(serviceInfo))
+        FakeExecutor.exhaustExecutors(uiExecutor, bgExecutor)
+
+        val taskViewConsumerCaptor = argumentCaptor<Consumer<TaskView>>()
+        verify(taskViewFactory).create(eq(context), eq(uiExecutor), capture(taskViewConsumerCaptor))
+
+        val taskView: TaskView = mock {
+            `when`(this.post(any())).thenAnswer {
+                uiExecutor.execute(it.arguments[0] as Runnable)
+                true
+            }
+        }
+
+        taskViewConsumerCaptor.value.accept(taskView)
+
+        underTest.onSizeChange()
+        verify(taskView).onLocationChanged()
+    }
+
     private fun setUpPanel(panel: SelectedItem.PanelItem): ControlsServiceInfo {
         val activity = ComponentName(context, "activity")
-        sharedPreferences
-            .edit()
-            .putString("controls_component", panel.componentName.flattenToString())
-            .putString("controls_structure", panel.appName.toString())
-            .putBoolean("controls_is_panel", true)
-            .commit()
+        preferredPanelRepository.setSelectedComponent(
+                SelectedComponentRepository.SelectedComponent(panel)
+        )
         return ControlsServiceInfo(panel.componentName, panel.appName, activity)
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/PanelTaskViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/PanelTaskViewControllerTest.kt
index de04ef8..9df7992 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/PanelTaskViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/PanelTaskViewControllerTest.kt
@@ -152,4 +152,12 @@
         listenerCaptor.value.onTaskRemovalStarted(0)
         verify(taskView).release()
     }
+
+    @Test
+    fun testOnRefreshBounds() {
+        underTest.launchTaskView()
+
+        underTest.refreshBounds()
+        verify(taskView).onLocationChanged()
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/TestableControlsActivity.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/TestableControlsActivity.kt
new file mode 100644
index 0000000..f0b4732
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/TestableControlsActivity.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.controls.ui
+
+import android.service.dreams.IDreamManager
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.controls.settings.ControlsSettingsDialogManager
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.statusbar.policy.KeyguardStateController
+
+class TestableControlsActivity(
+    uiController: ControlsUiController,
+    broadcastDispatcher: BroadcastDispatcher,
+    dreamManager: IDreamManager,
+    featureFlags: FeatureFlags,
+    controlsSettingsDialogManager: ControlsSettingsDialogManager,
+    keyguardStateController: KeyguardStateController
+) :
+    ControlsActivity(
+        uiController,
+        broadcastDispatcher,
+        dreamManager,
+        featureFlags,
+        controlsSettingsDialogManager,
+        keyguardStateController
+    )
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
index a636b7f..b87647e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
@@ -408,6 +408,17 @@
     }
 
     @Test
+    public void testPulsing_dozeSuspendTriggers_pulseDone_doesntCrash() {
+        mMachine.requestState(INITIALIZED);
+
+        mMachine.requestState(DOZE);
+        mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
+        mMachine.requestState(DOZE_PULSING);
+        mMachine.requestState(DOZE_SUSPEND_TRIGGERS);
+        mMachine.requestState(DOZE_PULSE_DONE);
+    }
+
+    @Test
     public void testSuppressingPulse_doesntCrash() {
         mMachine.requestState(INITIALIZED);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
index 6c23254..0a94706 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
@@ -1,6 +1,8 @@
 package com.android.systemui.dreams
 
+import android.animation.Animator
 import android.animation.AnimatorSet
+import android.animation.ValueAnimator
 import android.testing.AndroidTestingRunner
 import android.view.View
 import androidx.test.filters.SmallTest
@@ -10,13 +12,16 @@
 import com.android.systemui.statusbar.BlurUtils
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.util.mockito.argumentCaptor
 import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.runBlocking
+import org.junit.Assert.assertTrue
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
 import org.mockito.Mock
 import org.mockito.Mockito.anyLong
 import org.mockito.Mockito.eq
@@ -71,6 +76,19 @@
     }
 
     @Test
+    fun testExitAnimationUpdatesState() {
+        controller.startExitAnimations(animatorBuilder = { mockAnimator })
+
+        verify(stateController).setExitAnimationsRunning(true)
+
+        val captor = argumentCaptor<Animator.AnimatorListener>()
+        verify(mockAnimator).addListener(captor.capture())
+
+        captor.value.onAnimationEnd(mockAnimator)
+        verify(stateController).setExitAnimationsRunning(false)
+    }
+
+    @Test
     fun testWakeUpCallsExecutor() {
         val mockExecutor: DelayableExecutor = mock()
         val mockCallback: Runnable = mock()
@@ -87,7 +105,7 @@
     fun testWakeUpAfterStartWillCancel() {
         val mockStartAnimator: AnimatorSet = mock()
 
-        controller.startEntryAnimations(animatorBuilder = { mockStartAnimator })
+        controller.startEntryAnimations(false, animatorBuilder = { mockStartAnimator })
 
         verify(mockStartAnimator, never()).cancel()
 
@@ -100,4 +118,50 @@
         // animator.
         verify(mockStartAnimator, times(1)).cancel()
     }
+
+    @Test
+    fun testEntryAnimations_translatesUpwards() {
+        val mockStartAnimator: AnimatorSet = mock()
+
+        controller.startEntryAnimations(
+            /* downwards= */ false,
+            animatorBuilder = { mockStartAnimator }
+        )
+
+        val animatorCaptor = ArgumentCaptor.forClass(Animator::class.java)
+        verify(mockStartAnimator).playTogether(animatorCaptor.capture())
+
+        // Check if there's a ValueAnimator starting at the expected Y distance.
+        val animators: List<ValueAnimator> = animatorCaptor.allValues as List<ValueAnimator>
+        assertTrue(
+            animators.any {
+                // Call setCurrentFraction so the animated value jumps to the initial value.
+                it.setCurrentFraction(0f)
+                it.animatedValue == DREAM_IN_TRANSLATION_Y_DISTANCE.toFloat()
+            }
+        )
+    }
+
+    @Test
+    fun testEntryAnimations_translatesDownwards() {
+        val mockStartAnimator: AnimatorSet = mock()
+
+        controller.startEntryAnimations(
+            /* downwards= */ true,
+            animatorBuilder = { mockStartAnimator }
+        )
+
+        val animatorCaptor = ArgumentCaptor.forClass(Animator::class.java)
+        verify(mockStartAnimator).playTogether(animatorCaptor.capture())
+
+        // Check if there's a ValueAnimator starting at the expected Y distance.
+        val animators: List<ValueAnimator> = animatorCaptor.allValues as List<ValueAnimator>
+        assertTrue(
+            animators.any {
+                // Call setCurrentFraction so the animated value jumps to the initial value.
+                it.setCurrentFraction(0f)
+                it.animatedValue == -DREAM_IN_TRANSLATION_Y_DISTANCE.toFloat()
+            }
+        )
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
index 6b095ff..2a72e7d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
@@ -17,6 +17,7 @@
 package com.android.systemui.dreams;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
@@ -33,6 +34,7 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.dream.lowlight.LowLightTransitionCoordinator;
 import com.android.keyguard.BouncerPanelExpansionCalculator;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.dreams.complication.ComplicationHostViewController;
@@ -65,6 +67,9 @@
     DreamOverlayStatusBarViewController mDreamOverlayStatusBarViewController;
 
     @Mock
+    LowLightTransitionCoordinator mLowLightTransitionCoordinator;
+
+    @Mock
     DreamOverlayContainerView mDreamOverlayContainerView;
 
     @Mock
@@ -109,6 +114,7 @@
                 mComplicationHostViewController,
                 mDreamOverlayContentView,
                 mDreamOverlayStatusBarViewController,
+                mLowLightTransitionCoordinator,
                 mBlurUtils,
                 mHandler,
                 mResources,
@@ -200,7 +206,7 @@
 
         mController.onViewAttached();
 
-        verify(mAnimationsController).startEntryAnimations();
+        verify(mAnimationsController).startEntryAnimations(false);
         verify(mAnimationsController, never()).cancelAnimations();
     }
 
@@ -210,11 +216,11 @@
 
         mController.onViewAttached();
 
-        verify(mAnimationsController, never()).startEntryAnimations();
+        verify(mAnimationsController, never()).startEntryAnimations(anyBoolean());
     }
 
     @Test
-    public void testSkipEntryAnimationsWhenExitingLowLight() {
+    public void testDownwardEntryAnimationsWhenExitingLowLight() {
         ArgumentCaptor<DreamOverlayStateController.Callback> callbackCaptor =
                 ArgumentCaptor.forClass(DreamOverlayStateController.Callback.class);
         when(mStateController.isLowLightActive()).thenReturn(false);
@@ -230,8 +236,14 @@
         mController.onViewAttached();
 
         // Entry animations should be started then immediately ended to skip to the end.
-        verify(mAnimationsController).startEntryAnimations();
-        verify(mAnimationsController).endAnimations();
+        verify(mAnimationsController).startEntryAnimations(true);
+    }
+
+    @Test
+    public void testStartsExitAnimationsBeforeEnteringLowLight() {
+        mController.onBeforeEnterLowLight();
+
+        verify(mAnimationsController).startExitAnimations();
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
index de70033..6443621 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
@@ -20,7 +20,9 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
@@ -60,6 +62,7 @@
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Captor;
+import org.mockito.InOrder;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
@@ -254,6 +257,7 @@
         // Inform the overlay service of dream starting.
         client.startDream(mWindowParams, mDreamOverlayCallback, DREAM_COMPONENT,
                 true /*shouldShowComplication*/);
+        mMainExecutor.runAllReady();
 
         assertThat(mService.shouldShowComplications()).isTrue();
     }
@@ -297,6 +301,48 @@
     }
 
     @Test
+    public void testImmediateEndDream() throws Exception {
+        final IDreamOverlayClient client = getClient();
+
+        // Start the dream, but don't execute any Runnables put on the executor yet. We delay
+        // executing Runnables as the timing isn't guaranteed and we want to verify that the overlay
+        // starts and finishes in the proper order even if Runnables are delayed.
+        client.startDream(mWindowParams, mDreamOverlayCallback, DREAM_COMPONENT,
+                false /*shouldShowComplication*/);
+        // Immediately end the dream.
+        client.endDream();
+        // Run any scheduled Runnables.
+        mMainExecutor.runAllReady();
+
+        // The overlay starts then finishes.
+        InOrder inOrder = inOrder(mWindowManager);
+        inOrder.verify(mWindowManager).addView(mViewCaptor.capture(), any());
+        inOrder.verify(mWindowManager).removeView(mViewCaptor.getValue());
+    }
+
+    @Test
+    public void testEndDreamDuringStartDream() throws Exception {
+        final IDreamOverlayClient client = getClient();
+
+        // Schedule the endDream call in the middle of the startDream implementation, as any
+        // ordering is possible.
+        doAnswer(invocation -> {
+            client.endDream();
+            return null;
+        }).when(mStateController).setOverlayActive(true);
+
+        // Start the dream.
+        client.startDream(mWindowParams, mDreamOverlayCallback, DREAM_COMPONENT,
+                false /*shouldShowComplication*/);
+        mMainExecutor.runAllReady();
+
+        // The overlay starts then finishes.
+        InOrder inOrder = inOrder(mWindowManager);
+        inOrder.verify(mWindowManager).addView(mViewCaptor.capture(), any());
+        inOrder.verify(mWindowManager).removeView(mViewCaptor.getValue());
+    }
+
+    @Test
     public void testDestroy() throws RemoteException {
         final IDreamOverlayClient client = getClient();
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
index b7d0f29..34fa76f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
@@ -32,6 +32,8 @@
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.dreams.complication.Complication;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.time.FakeSystemClock;
 
@@ -53,17 +55,21 @@
     @Mock
     Complication mComplication;
 
+    @Mock
+    private FeatureFlags mFeatureFlags;
+
     final FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
 
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
+
+        when(mFeatureFlags.isEnabled(Flags.ALWAYS_SHOW_HOME_CONTROLS_ON_DREAMS)).thenReturn(false);
     }
 
     @Test
     public void testStateChange_overlayActive() {
-        final DreamOverlayStateController stateController = new DreamOverlayStateController(
-                mExecutor, true);
+        final DreamOverlayStateController stateController = getDreamOverlayStateController(true);
         stateController.addCallback(mCallback);
         stateController.setOverlayActive(true);
         mExecutor.runAllReady();
@@ -84,8 +90,7 @@
 
     @Test
     public void testCallback() {
-        final DreamOverlayStateController stateController = new DreamOverlayStateController(
-                mExecutor, true);
+        final DreamOverlayStateController stateController = getDreamOverlayStateController(true);
         stateController.addCallback(mCallback);
 
         // Add complication and verify callback is notified.
@@ -110,8 +115,7 @@
 
     @Test
     public void testNotifyOnCallbackAdd() {
-        final DreamOverlayStateController stateController =
-                new DreamOverlayStateController(mExecutor, true);
+        final DreamOverlayStateController stateController = getDreamOverlayStateController(true);
 
         stateController.addComplication(mComplication);
         mExecutor.runAllReady();
@@ -124,8 +128,7 @@
 
     @Test
     public void testNotifyOnCallbackAddOverlayDisabled() {
-        final DreamOverlayStateController stateController =
-                new DreamOverlayStateController(mExecutor, false);
+        final DreamOverlayStateController stateController = getDreamOverlayStateController(false);
 
         stateController.addComplication(mComplication);
         mExecutor.runAllReady();
@@ -139,8 +142,7 @@
 
     @Test
     public void testComplicationFilteringWhenShouldShowComplications() {
-        final DreamOverlayStateController stateController =
-                new DreamOverlayStateController(mExecutor, true);
+        final DreamOverlayStateController stateController = getDreamOverlayStateController(true);
         stateController.setShouldShowComplications(true);
 
         final Complication alwaysAvailableComplication = Mockito.mock(Complication.class);
@@ -179,8 +181,7 @@
 
     @Test
     public void testComplicationFilteringWhenShouldHideComplications() {
-        final DreamOverlayStateController stateController =
-                new DreamOverlayStateController(mExecutor, true);
+        final DreamOverlayStateController stateController = getDreamOverlayStateController(true);
         stateController.setShouldShowComplications(true);
 
         final Complication alwaysAvailableComplication = Mockito.mock(Complication.class);
@@ -226,8 +227,7 @@
     @Test
     public void testComplicationWithNoTypeNotFiltered() {
         final Complication complication = Mockito.mock(Complication.class);
-        final DreamOverlayStateController stateController =
-                new DreamOverlayStateController(mExecutor, true);
+        final DreamOverlayStateController stateController = getDreamOverlayStateController(true);
         stateController.addComplication(complication);
         mExecutor.runAllReady();
         assertThat(stateController.getComplications(true).contains(complication))
@@ -236,8 +236,7 @@
 
     @Test
     public void testNotifyLowLightChanged() {
-        final DreamOverlayStateController stateController =
-                new DreamOverlayStateController(mExecutor, true);
+        final DreamOverlayStateController stateController = getDreamOverlayStateController(true);
 
         stateController.addCallback(mCallback);
         mExecutor.runAllReady();
@@ -252,8 +251,7 @@
 
     @Test
     public void testNotifyLowLightExit() {
-        final DreamOverlayStateController stateController =
-                new DreamOverlayStateController(mExecutor, true);
+        final DreamOverlayStateController stateController = getDreamOverlayStateController(true);
 
         stateController.addCallback(mCallback);
         mExecutor.runAllReady();
@@ -276,8 +274,7 @@
 
     @Test
     public void testNotifyEntryAnimationsFinishedChanged() {
-        final DreamOverlayStateController stateController =
-                new DreamOverlayStateController(mExecutor, true);
+        final DreamOverlayStateController stateController = getDreamOverlayStateController(true);
 
         stateController.addCallback(mCallback);
         mExecutor.runAllReady();
@@ -289,4 +286,57 @@
         verify(mCallback, times(1)).onStateChanged();
         assertThat(stateController.areEntryAnimationsFinished()).isTrue();
     }
+
+    @Test
+    public void testShouldShowComplicationsSetToFalse_stillShowsSupportedTypes_featureEnabled() {
+        when(mFeatureFlags.isEnabled(Flags.ALWAYS_SHOW_HOME_CONTROLS_ON_DREAMS)).thenReturn(true);
+
+        final DreamOverlayStateController stateController = getDreamOverlayStateController(true);
+        stateController.setShouldShowComplications(true);
+
+        final Complication noneComplication = Mockito.mock(Complication.class);
+        when(noneComplication.getRequiredTypeAvailability())
+                .thenReturn(Complication.COMPLICATION_TYPE_NONE);
+
+        final Complication homeControlsComplication = Mockito.mock(Complication.class);
+        when(homeControlsComplication.getRequiredTypeAvailability())
+                .thenReturn(Complication.COMPLICATION_TYPE_HOME_CONTROLS);
+
+        stateController.addComplication(noneComplication);
+        stateController.addComplication(homeControlsComplication);
+
+        final DreamOverlayStateController.Callback callback =
+                Mockito.mock(DreamOverlayStateController.Callback.class);
+
+        stateController.setAvailableComplicationTypes(
+                Complication.COMPLICATION_TYPE_HOME_CONTROLS);
+        stateController.addCallback(callback);
+        mExecutor.runAllReady();
+
+        {
+            clearInvocations(callback);
+            stateController.setShouldShowComplications(true);
+            mExecutor.runAllReady();
+
+            verify(callback).onAvailableComplicationTypesChanged();
+            final Collection<Complication> complications = stateController.getComplications();
+            assertThat(complications.contains(noneComplication)).isTrue();
+            assertThat(complications.contains(homeControlsComplication)).isTrue();
+        }
+
+        {
+            clearInvocations(callback);
+            stateController.setShouldShowComplications(false);
+            mExecutor.runAllReady();
+
+            verify(callback).onAvailableComplicationTypesChanged();
+            final Collection<Complication> complications = stateController.getComplications();
+            assertThat(complications.contains(noneComplication)).isTrue();
+            assertThat(complications.contains(homeControlsComplication)).isTrue();
+        }
+    }
+
+    private DreamOverlayStateController getDreamOverlayStateController(boolean overlayEnabled) {
+        return new DreamOverlayStateController(mExecutor, overlayEnabled, mFeatureFlags);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationHostViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationHostViewControllerTest.java
index dcd8736..95c6897 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationHostViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationHostViewControllerTest.java
@@ -22,6 +22,8 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.os.UserHandle;
+import android.provider.Settings;
 import android.testing.AndroidTestingRunner;
 import android.view.View;
 
@@ -33,6 +35,8 @@
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.dreams.DreamOverlayStateController;
+import com.android.systemui.util.settings.FakeSettings;
+import com.android.systemui.util.settings.SecureSettings;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -88,14 +92,15 @@
     @Captor
     private ArgumentCaptor<Observer<Collection<ComplicationViewModel>>> mObserverCaptor;
 
-    @Captor
-    private ArgumentCaptor<DreamOverlayStateController.Callback> mCallbackCaptor;
-
     @Complication.Category
     static final int COMPLICATION_CATEGORY = Complication.CATEGORY_SYSTEM;
 
     private ComplicationHostViewController mController;
 
+    private SecureSettings mSecureSettings;
+
+    private static final int CURRENT_USER_ID = UserHandle.USER_SYSTEM;
+
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
@@ -108,12 +113,17 @@
         when(mViewHolder.getLayoutParams()).thenReturn(mComplicationLayoutParams);
         when(mComplicationView.getParent()).thenReturn(mComplicationHostView);
 
+        mSecureSettings = new FakeSettings();
+        mSecureSettings.putFloatForUser(
+                        Settings.Global.ANIMATOR_DURATION_SCALE, 1.0f, CURRENT_USER_ID);
+
         mController = new ComplicationHostViewController(
                 mComplicationHostView,
                 mLayoutEngine,
                 mDreamOverlayStateController,
                 mLifecycleOwner,
-                mViewModel);
+                mViewModel,
+                mSecureSettings);
 
         mController.init();
     }
@@ -176,8 +186,6 @@
 
         // Dream entry animations finished.
         when(mDreamOverlayStateController.areEntryAnimationsFinished()).thenReturn(true);
-        final DreamOverlayStateController.Callback stateCallback = captureOverlayStateCallback();
-        stateCallback.onStateChanged();
 
         // Add a complication after entry animations are finished.
         final HashSet<ComplicationViewModel> complications = new HashSet<>(
@@ -188,14 +196,26 @@
         verify(mComplicationView, never()).setVisibility(View.INVISIBLE);
     }
 
+    @Test
+    public void testAnimationsDisabled_ComplicationsNeverSetToInvisible() {
+        //Disable animations
+        mController.mIsAnimationEnabled = false;
+
+        final Observer<Collection<ComplicationViewModel>> observer =
+                captureComplicationViewModelsObserver();
+
+        // Add a complication before entry animations are finished.
+        final HashSet<ComplicationViewModel> complications = new HashSet<>(
+                Collections.singletonList(mComplicationViewModel));
+        observer.onChanged(complications);
+
+        // The complication view should not be set to invisible.
+        verify(mComplicationView, never()).setVisibility(View.INVISIBLE);
+    }
+
     private Observer<Collection<ComplicationViewModel>> captureComplicationViewModelsObserver() {
         verify(mComplicationViewModelLiveData).observe(eq(mLifecycleOwner),
                 mObserverCaptor.capture());
         return mObserverCaptor.getValue();
     }
-
-    private DreamOverlayStateController.Callback captureOverlayStateCallback() {
-        verify(mDreamOverlayStateController).addCallback(mCallbackCaptor.capture());
-        return mCallbackCaptor.getValue();
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationTypesUpdaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationTypesUpdaterTest.java
index b3329eb..0e16b47 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationTypesUpdaterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationTypesUpdaterTest.java
@@ -17,7 +17,6 @@
 package com.android.systemui.dreams.complication;
 
 import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -36,7 +35,7 @@
 import com.android.systemui.dreams.DreamOverlayStateController;
 import com.android.systemui.shared.condition.Monitor;
 import com.android.systemui.util.concurrency.FakeExecutor;
-import com.android.systemui.util.settings.SecureSettings;
+import com.android.systemui.util.settings.FakeSettings;
 import com.android.systemui.util.time.FakeSystemClock;
 
 import org.junit.Before;
@@ -57,8 +56,7 @@
     private Context mContext;
     @Mock
     private DreamBackend mDreamBackend;
-    @Mock
-    private SecureSettings mSecureSettings;
+    private FakeSettings mSecureSettings;
     @Mock
     private DreamOverlayStateController mDreamOverlayStateController;
     @Captor
@@ -74,6 +72,7 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         when(mDreamBackend.getEnabledComplications()).thenReturn(new HashSet<>());
+        mSecureSettings = new FakeSettings();
 
         mMonitor = SelfExecutingMonitor.createInstance();
         mController = new ComplicationTypesUpdater(mDreamBackend, mExecutor,
@@ -100,19 +99,15 @@
         when(mDreamBackend.getEnabledComplications()).thenReturn(new HashSet<>(Arrays.asList(
                 DreamBackend.COMPLICATION_TYPE_TIME, DreamBackend.COMPLICATION_TYPE_WEATHER,
                 DreamBackend.COMPLICATION_TYPE_AIR_QUALITY)));
-        final ContentObserver settingsObserver = captureSettingsObserver();
-        settingsObserver.onChange(false);
+
+        // Update the setting to trigger any content observers
+        mSecureSettings.putBoolForUser(
+                Settings.Secure.SCREENSAVER_COMPLICATIONS_ENABLED, true,
+                UserHandle.myUserId());
         mExecutor.runAllReady();
 
         verify(mDreamOverlayStateController).setAvailableComplicationTypes(
                 Complication.COMPLICATION_TYPE_TIME | Complication.COMPLICATION_TYPE_WEATHER
                         | Complication.COMPLICATION_TYPE_AIR_QUALITY);
     }
-
-    private ContentObserver captureSettingsObserver() {
-        verify(mSecureSettings).registerContentObserverForUser(
-                eq(Settings.Secure.SCREENSAVER_COMPLICATIONS_ENABLED),
-                mSettingsObserverCaptor.capture(), eq(UserHandle.myUserId()));
-        return mSettingsObserverCaptor.getValue();
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java
index 3312c43..aad49f9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java
@@ -35,7 +35,6 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.logging.UiEventLogger;
-import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.animation.view.LaunchableImageView;
 import com.android.systemui.condition.SelfExecutingMonitor;
@@ -89,9 +88,6 @@
     private ArgumentCaptor<ControlsListingController.ControlsListingCallback> mCallbackCaptor;
 
     @Mock
-    private View mView;
-
-    @Mock
     private LaunchableImageView mHomeControlsView;
 
     @Mock
@@ -115,7 +111,6 @@
         when(mControlsComponent.getControlsListingController()).thenReturn(
                 Optional.of(mControlsListingController));
         when(mControlsComponent.getVisibility()).thenReturn(AVAILABLE);
-        when(mView.findViewById(R.id.home_controls_chip)).thenReturn(mHomeControlsView);
 
         mMonitor = SelfExecutingMonitor.createInstance();
     }
@@ -223,7 +218,7 @@
     public void testClick_logsUiEvent() {
         final DreamHomeControlsComplication.DreamHomeControlsChipViewController viewController =
                 new DreamHomeControlsComplication.DreamHomeControlsChipViewController(
-                        mView,
+                        mHomeControlsView,
                         mActivityStarter,
                         mContext,
                         mControlsComponent,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java
index 19347c7..58eb7d4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java
@@ -21,9 +21,11 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.DreamManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -50,6 +52,9 @@
     @Mock
     Condition.Callback mCallback;
 
+    @Mock
+    DreamManager mDreamManager;
+
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
@@ -59,29 +64,39 @@
      * Ensure a dreaming state immediately triggers the condition.
      */
     @Test
-    public void testInitialState() {
-        final Intent intent = new Intent(Intent.ACTION_DREAMING_STARTED);
-        when(mContext.registerReceiver(any(), any())).thenReturn(intent);
-        final DreamCondition condition = new DreamCondition(mContext);
+    public void testInitialDreamingState() {
+        when(mDreamManager.isDreaming()).thenReturn(true);
+        final DreamCondition condition = new DreamCondition(mContext, mDreamManager);
         condition.addCallback(mCallback);
-        condition.start();
 
         verify(mCallback).onConditionChanged(eq(condition));
         assertThat(condition.isConditionMet()).isTrue();
     }
 
     /**
+     * Ensure a non-dreaming state does not trigger the condition.
+     */
+    @Test
+    public void testInitialNonDreamingState() {
+        when(mDreamManager.isDreaming()).thenReturn(false);
+        final DreamCondition condition = new DreamCondition(mContext, mDreamManager);
+        condition.addCallback(mCallback);
+
+        verify(mCallback, never()).onConditionChanged(eq(condition));
+        assertThat(condition.isConditionMet()).isFalse();
+    }
+
+    /**
      * Ensure that changing dream state triggers condition.
      */
     @Test
     public void testChange() {
-        final Intent intent = new Intent(Intent.ACTION_DREAMING_STARTED);
         final ArgumentCaptor<BroadcastReceiver> receiverCaptor =
                 ArgumentCaptor.forClass(BroadcastReceiver.class);
-        when(mContext.registerReceiver(receiverCaptor.capture(), any())).thenReturn(intent);
-        final DreamCondition condition = new DreamCondition(mContext);
+        when(mDreamManager.isDreaming()).thenReturn(true);
+        final DreamCondition condition = new DreamCondition(mContext, mDreamManager);
         condition.addCallback(mCallback);
-        condition.start();
+        verify(mContext).registerReceiver(receiverCaptor.capture(), any());
         clearInvocations(mCallback);
         receiverCaptor.getValue().onReceive(mContext, new Intent(Intent.ACTION_DREAMING_STOPPED));
         verify(mCallback).onConditionChanged(eq(condition));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/ConditionalRestarterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/ConditionalRestarterTest.kt
new file mode 100644
index 0000000..0e14591
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/ConditionalRestarterTest.kt
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.flags
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.mockito.any
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.advanceUntilIdle
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+/**
+ * Be careful with the {FeatureFlagsReleaseRestarter} in this test. It has a call to System.exit()!
+ */
+@SmallTest
+class ConditionalRestarterTest : SysuiTestCase() {
+    private lateinit var restarter: ConditionalRestarter
+
+    @Mock private lateinit var systemExitRestarter: SystemExitRestarter
+
+    val restartDelayMs = 0L
+    val dispatcher = StandardTestDispatcher()
+    val testScope = TestScope(dispatcher)
+
+    val conditionA = FakeCondition()
+    val conditionB = FakeCondition()
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+        restarter =
+            ConditionalRestarter(
+                systemExitRestarter,
+                setOf(conditionA, conditionB),
+                restartDelayMs,
+                testScope,
+                dispatcher
+            )
+    }
+
+    @Test
+    fun restart_ImmediatelySatisfied() =
+        testScope.runTest {
+            conditionA.canRestart = true
+            conditionB.canRestart = true
+            restarter.restartSystemUI("Restart for test")
+            advanceUntilIdle()
+            verify(systemExitRestarter).restartSystemUI(any())
+        }
+
+    @Test
+    fun restart_WaitsForConditionA() =
+        testScope.runTest {
+            conditionA.canRestart = false
+            conditionB.canRestart = true
+
+            restarter.restartSystemUI("Restart for test")
+            advanceUntilIdle()
+            // No restart occurs yet.
+            verify(systemExitRestarter, never()).restartSystemUI(any())
+
+            conditionA.canRestart = true
+            conditionA.retryFn?.invoke()
+            advanceUntilIdle()
+            verify(systemExitRestarter).restartSystemUI(any())
+        }
+
+    @Test
+    fun restart_WaitsForConditionB() =
+        testScope.runTest {
+            conditionA.canRestart = true
+            conditionB.canRestart = false
+
+            restarter.restartSystemUI("Restart for test")
+            advanceUntilIdle()
+            // No restart occurs yet.
+            verify(systemExitRestarter, never()).restartSystemUI(any())
+
+            conditionB.canRestart = true
+            conditionB.retryFn?.invoke()
+            advanceUntilIdle()
+            verify(systemExitRestarter).restartSystemUI(any())
+        }
+
+    @Test
+    fun restart_WaitsForAllConditions() =
+        testScope.runTest {
+            conditionA.canRestart = true
+            conditionB.canRestart = false
+
+            restarter.restartSystemUI("Restart for test")
+            advanceUntilIdle()
+            // No restart occurs yet.
+            verify(systemExitRestarter, never()).restartSystemUI(any())
+
+            // B becomes true, but A is now false
+            conditionA.canRestart = false
+            conditionB.canRestart = true
+            conditionB.retryFn?.invoke()
+            advanceUntilIdle()
+            // No restart occurs yet.
+            verify(systemExitRestarter, never()).restartSystemUI(any())
+
+            conditionA.canRestart = true
+            conditionA.retryFn?.invoke()
+            advanceUntilIdle()
+            verify(systemExitRestarter).restartSystemUI(any())
+        }
+
+    class FakeCondition : ConditionalRestarter.Condition {
+        var retryFn: (() -> Unit)? = null
+        var canRestart = false
+
+        override fun canRestartNow(retryFn: () -> Unit): Boolean {
+            this.retryFn = retryFn
+
+            return canRestart
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt
index 2bcd75b..18f7db1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt
@@ -37,6 +37,7 @@
 import org.mockito.Mockito.anyBoolean
 import org.mockito.Mockito.anyString
 import org.mockito.Mockito.inOrder
+import org.mockito.Mockito.never
 import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.verifyNoMoreInteractions
@@ -53,7 +54,7 @@
  */
 @SmallTest
 class FeatureFlagsDebugTest : SysuiTestCase() {
-    private lateinit var mFeatureFlagsDebug: FeatureFlagsDebug
+    private lateinit var featureFlagsDebug: FeatureFlagsDebug
 
     @Mock
     private lateinit var flagManager: FlagManager
@@ -85,7 +86,7 @@
         flagMap.put(Flags.TEAMFOOD.name, Flags.TEAMFOOD)
         flagMap.put(teamfoodableFlagA.name, teamfoodableFlagA)
         flagMap.put(teamfoodableFlagB.name, teamfoodableFlagB)
-        mFeatureFlagsDebug = FeatureFlagsDebug(
+        featureFlagsDebug = FeatureFlagsDebug(
             flagManager,
             mockContext,
             globalSettings,
@@ -95,7 +96,7 @@
             flagMap,
             restarter
         )
-        mFeatureFlagsDebug.init()
+        featureFlagsDebug.init()
         verify(flagManager).onSettingsChangedAction = any()
         broadcastReceiver = withArgCaptor {
             verify(mockContext).registerReceiver(
@@ -116,7 +117,7 @@
         whenever(flagManager.readFlagValue<Boolean>(eq("4"), any())).thenReturn(false)
 
         assertThat(
-            mFeatureFlagsDebug.isEnabled(
+            featureFlagsDebug.isEnabled(
                 ReleasedFlag(
                     2,
                     name = "2",
@@ -125,7 +126,7 @@
             )
         ).isTrue()
         assertThat(
-            mFeatureFlagsDebug.isEnabled(
+            featureFlagsDebug.isEnabled(
                 UnreleasedFlag(
                     3,
                     name = "3",
@@ -134,7 +135,7 @@
             )
         ).isTrue()
         assertThat(
-            mFeatureFlagsDebug.isEnabled(
+            featureFlagsDebug.isEnabled(
                 ReleasedFlag(
                     4,
                     name = "4",
@@ -143,7 +144,7 @@
             )
         ).isFalse()
         assertThat(
-            mFeatureFlagsDebug.isEnabled(
+            featureFlagsDebug.isEnabled(
                 UnreleasedFlag(
                     5,
                     name = "5",
@@ -157,8 +158,8 @@
     fun teamFoodFlag_False() {
         whenever(flagManager.readFlagValue<Boolean>(
             eq(Flags.TEAMFOOD.name), any())).thenReturn(false)
-        assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagA)).isFalse()
-        assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagB)).isTrue()
+        assertThat(featureFlagsDebug.isEnabled(teamfoodableFlagA)).isFalse()
+        assertThat(featureFlagsDebug.isEnabled(teamfoodableFlagB)).isTrue()
 
         // Regular boolean flags should still test the same.
         // Only our teamfoodableFlag should change.
@@ -169,8 +170,8 @@
     fun teamFoodFlag_True() {
         whenever(flagManager.readFlagValue<Boolean>(
             eq(Flags.TEAMFOOD.name), any())).thenReturn(true)
-        assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagA)).isTrue()
-        assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagB)).isTrue()
+        assertThat(featureFlagsDebug.isEnabled(teamfoodableFlagA)).isTrue()
+        assertThat(featureFlagsDebug.isEnabled(teamfoodableFlagB)).isTrue()
 
         // Regular boolean flags should still test the same.
         // Only our teamfoodableFlag should change.
@@ -185,8 +186,8 @@
             .thenReturn(false)
         whenever(flagManager.readFlagValue<Boolean>(
             eq(Flags.TEAMFOOD.name), any())).thenReturn(true)
-        assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagA)).isTrue()
-        assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagB)).isFalse()
+        assertThat(featureFlagsDebug.isEnabled(teamfoodableFlagA)).isTrue()
+        assertThat(featureFlagsDebug.isEnabled(teamfoodableFlagB)).isFalse()
 
         // Regular boolean flags should still test the same.
         // Only our teamfoodableFlag should change.
@@ -205,7 +206,7 @@
         whenever(flagManager.readFlagValue<Boolean>(eq("5"), any())).thenReturn(false)
 
         assertThat(
-            mFeatureFlagsDebug.isEnabled(
+            featureFlagsDebug.isEnabled(
                 ResourceBooleanFlag(
                     1,
                     "1",
@@ -214,16 +215,16 @@
                 )
             )
         ).isFalse()
-        assertThat(mFeatureFlagsDebug.isEnabled(ResourceBooleanFlag(2, "2", "test", 1002))).isTrue()
-        assertThat(mFeatureFlagsDebug.isEnabled(ResourceBooleanFlag(3, "3", "test", 1003))).isTrue()
+        assertThat(featureFlagsDebug.isEnabled(ResourceBooleanFlag(2, "2", "test", 1002))).isTrue()
+        assertThat(featureFlagsDebug.isEnabled(ResourceBooleanFlag(3, "3", "test", 1003))).isTrue()
 
         Assert.assertThrows(NameNotFoundException::class.java) {
-            mFeatureFlagsDebug.isEnabled(ResourceBooleanFlag(4, "4", "test", 1004))
+            featureFlagsDebug.isEnabled(ResourceBooleanFlag(4, "4", "test", 1004))
         }
         // Test that resource is loaded (and validated) even when the setting is set.
         //  This prevents developers from not noticing when they reference an invalid resource.
         Assert.assertThrows(NameNotFoundException::class.java) {
-            mFeatureFlagsDebug.isEnabled(ResourceBooleanFlag(5, "5", "test", 1005))
+            featureFlagsDebug.isEnabled(ResourceBooleanFlag(5, "5", "test", 1005))
         }
     }
 
@@ -236,11 +237,11 @@
             return@thenAnswer it.getArgument(1)
         }
 
-        assertThat(mFeatureFlagsDebug.isEnabled(SysPropBooleanFlag(1, "a", "test"))).isFalse()
-        assertThat(mFeatureFlagsDebug.isEnabled(SysPropBooleanFlag(2, "b", "test"))).isTrue()
-        assertThat(mFeatureFlagsDebug.isEnabled(SysPropBooleanFlag(3, "c", "test", true))).isTrue()
+        assertThat(featureFlagsDebug.isEnabled(SysPropBooleanFlag(1, "a", "test"))).isFalse()
+        assertThat(featureFlagsDebug.isEnabled(SysPropBooleanFlag(2, "b", "test"))).isTrue()
+        assertThat(featureFlagsDebug.isEnabled(SysPropBooleanFlag(3, "c", "test", true))).isTrue()
         assertThat(
-            mFeatureFlagsDebug.isEnabled(
+            featureFlagsDebug.isEnabled(
                 SysPropBooleanFlag(
                     4,
                     "d",
@@ -249,17 +250,17 @@
                 )
             )
         ).isFalse()
-        assertThat(mFeatureFlagsDebug.isEnabled(SysPropBooleanFlag(5, "e", "test"))).isFalse()
+        assertThat(featureFlagsDebug.isEnabled(SysPropBooleanFlag(5, "e", "test"))).isFalse()
     }
 
     @Test
     fun readStringFlag() {
         whenever(flagManager.readFlagValue<String>(eq("3"), any())).thenReturn("foo")
         whenever(flagManager.readFlagValue<String>(eq("4"), any())).thenReturn("bar")
-        assertThat(mFeatureFlagsDebug.getString(StringFlag(1, "1", "test", "biz"))).isEqualTo("biz")
-        assertThat(mFeatureFlagsDebug.getString(StringFlag(2, "2", "test", "baz"))).isEqualTo("baz")
-        assertThat(mFeatureFlagsDebug.getString(StringFlag(3, "3", "test", "buz"))).isEqualTo("foo")
-        assertThat(mFeatureFlagsDebug.getString(StringFlag(4, "4", "test", "buz"))).isEqualTo("bar")
+        assertThat(featureFlagsDebug.getString(StringFlag(1, "1", "test", "biz"))).isEqualTo("biz")
+        assertThat(featureFlagsDebug.getString(StringFlag(2, "2", "test", "baz"))).isEqualTo("baz")
+        assertThat(featureFlagsDebug.getString(StringFlag(3, "3", "test", "buz"))).isEqualTo("foo")
+        assertThat(featureFlagsDebug.getString(StringFlag(4, "4", "test", "buz"))).isEqualTo("bar")
     }
 
     @Test
@@ -276,7 +277,7 @@
         whenever(flagManager.readFlagValue<String>(eq("6"), any())).thenReturn("override6")
 
         assertThat(
-            mFeatureFlagsDebug.getString(
+            featureFlagsDebug.getString(
                 ResourceStringFlag(
                     1,
                     "1",
@@ -286,7 +287,7 @@
             )
         ).isEqualTo("")
         assertThat(
-            mFeatureFlagsDebug.getString(
+            featureFlagsDebug.getString(
                 ResourceStringFlag(
                     2,
                     "2",
@@ -296,7 +297,7 @@
             )
         ).isEqualTo("resource2")
         assertThat(
-            mFeatureFlagsDebug.getString(
+            featureFlagsDebug.getString(
                 ResourceStringFlag(
                     3,
                     "3",
@@ -307,15 +308,15 @@
         ).isEqualTo("override3")
 
         Assert.assertThrows(NullPointerException::class.java) {
-            mFeatureFlagsDebug.getString(ResourceStringFlag(4, "4", "test", 1004))
+            featureFlagsDebug.getString(ResourceStringFlag(4, "4", "test", 1004))
         }
         Assert.assertThrows(NameNotFoundException::class.java) {
-            mFeatureFlagsDebug.getString(ResourceStringFlag(5, "5", "test", 1005))
+            featureFlagsDebug.getString(ResourceStringFlag(5, "5", "test", 1005))
         }
         // Test that resource is loaded (and validated) even when the setting is set.
         //  This prevents developers from not noticing when they reference an invalid resource.
         Assert.assertThrows(NameNotFoundException::class.java) {
-            mFeatureFlagsDebug.getString(ResourceStringFlag(6, "6", "test", 1005))
+            featureFlagsDebug.getString(ResourceStringFlag(6, "6", "test", 1005))
         }
     }
 
@@ -323,10 +324,10 @@
     fun readIntFlag() {
         whenever(flagManager.readFlagValue<Int>(eq("3"), any())).thenReturn(22)
         whenever(flagManager.readFlagValue<Int>(eq("4"), any())).thenReturn(48)
-        assertThat(mFeatureFlagsDebug.getInt(IntFlag(1, "1", "test", 12))).isEqualTo(12)
-        assertThat(mFeatureFlagsDebug.getInt(IntFlag(2, "2", "test", 93))).isEqualTo(93)
-        assertThat(mFeatureFlagsDebug.getInt(IntFlag(3, "3", "test", 8))).isEqualTo(22)
-        assertThat(mFeatureFlagsDebug.getInt(IntFlag(4, "4", "test", 234))).isEqualTo(48)
+        assertThat(featureFlagsDebug.getInt(IntFlag(1, "1", "test", 12))).isEqualTo(12)
+        assertThat(featureFlagsDebug.getInt(IntFlag(2, "2", "test", 93))).isEqualTo(93)
+        assertThat(featureFlagsDebug.getInt(IntFlag(3, "3", "test", 8))).isEqualTo(22)
+        assertThat(featureFlagsDebug.getInt(IntFlag(4, "4", "test", 234))).isEqualTo(48)
     }
 
     @Test
@@ -342,17 +343,17 @@
         whenever(flagManager.readFlagValue<Int>(eq(4), any())).thenReturn(500)
         whenever(flagManager.readFlagValue<Int>(eq(5), any())).thenReturn(9519)
 
-        assertThat(mFeatureFlagsDebug.getInt(ResourceIntFlag(1, "1", "test", 1001))).isEqualTo(88)
-        assertThat(mFeatureFlagsDebug.getInt(ResourceIntFlag(2, "2", "test", 1002))).isEqualTo(61)
-        assertThat(mFeatureFlagsDebug.getInt(ResourceIntFlag(3, "3", "test", 1003))).isEqualTo(20)
+        assertThat(featureFlagsDebug.getInt(ResourceIntFlag(1, "1", "test", 1001))).isEqualTo(88)
+        assertThat(featureFlagsDebug.getInt(ResourceIntFlag(2, "2", "test", 1002))).isEqualTo(61)
+        assertThat(featureFlagsDebug.getInt(ResourceIntFlag(3, "3", "test", 1003))).isEqualTo(20)
 
         Assert.assertThrows(NotFoundException::class.java) {
-            mFeatureFlagsDebug.getInt(ResourceIntFlag(4, "4", "test", 1004))
+            featureFlagsDebug.getInt(ResourceIntFlag(4, "4", "test", 1004))
         }
         // Test that resource is loaded (and validated) even when the setting is set.
         //  This prevents developers from not noticing when they reference an invalid resource.
         Assert.assertThrows(NotFoundException::class.java) {
-            mFeatureFlagsDebug.getInt(ResourceIntFlag(5, "5", "test", 1005))
+            featureFlagsDebug.getInt(ResourceIntFlag(5, "5", "test", 1005))
         }
     }
 
@@ -432,11 +433,11 @@
         whenever(flagManager.readFlagValue<String>(eq("1"), any())).thenReturn("original")
 
         // gets the flag & cache it
-        assertThat(mFeatureFlagsDebug.getString(flag1)).isEqualTo("original")
+        assertThat(featureFlagsDebug.getString(flag1)).isEqualTo("original")
         verify(flagManager, times(1)).readFlagValue(eq("1"), eq(StringFlagSerializer))
 
         // hit the cache
-        assertThat(mFeatureFlagsDebug.getString(flag1)).isEqualTo("original")
+        assertThat(featureFlagsDebug.getString(flag1)).isEqualTo("original")
         verifyNoMoreInteractions(flagManager)
 
         // set the flag
@@ -444,7 +445,7 @@
         verifyPutData("1", "{\"type\":\"string\",\"value\":\"new\"}", numReads = 2)
         whenever(flagManager.readFlagValue<String>(eq("1"), any())).thenReturn("new")
 
-        assertThat(mFeatureFlagsDebug.getString(flag1)).isEqualTo("new")
+        assertThat(featureFlagsDebug.getString(flag1)).isEqualTo("new")
         verify(flagManager, times(3)).readFlagValue(eq("1"), eq(StringFlagSerializer))
     }
 
@@ -454,7 +455,7 @@
 
         serverFlagReader.setFlagValue(flag.namespace, flag.name, false)
 
-        assertThat(mFeatureFlagsDebug.isEnabled(flag)).isFalse()
+        assertThat(featureFlagsDebug.isEnabled(flag)).isFalse()
     }
 
     @Test
@@ -462,7 +463,33 @@
         val flag = UnreleasedFlag(100, name = "100", namespace = "test")
 
         serverFlagReader.setFlagValue(flag.namespace, flag.name, true)
-        assertThat(mFeatureFlagsDebug.isEnabled(flag)).isTrue()
+        assertThat(featureFlagsDebug.isEnabled(flag)).isTrue()
+    }
+
+    @Test
+    fun serverSide_OverrideUncached_NoRestart() {
+        // No one has read the flag, so it's not in the cache.
+        serverFlagReader.setFlagValue(
+            teamfoodableFlagA.namespace, teamfoodableFlagA.name, !teamfoodableFlagA.default)
+        verify(restarter, never()).restartSystemUI(anyString())
+    }
+
+    @Test
+    fun serverSide_Override_Restarts() {
+        // Read it to put it in the cache.
+        featureFlagsDebug.isEnabled(teamfoodableFlagA)
+        serverFlagReader.setFlagValue(
+            teamfoodableFlagA.namespace, teamfoodableFlagA.name, !teamfoodableFlagA.default)
+        verify(restarter).restartSystemUI(anyString())
+    }
+
+    @Test
+    fun serverSide_RedundantOverride_NoRestart() {
+        // Read it to put it in the cache.
+        featureFlagsDebug.isEnabled(teamfoodableFlagA)
+        serverFlagReader.setFlagValue(
+            teamfoodableFlagA.namespace, teamfoodableFlagA.name, teamfoodableFlagA.default)
+        verify(restarter, never()).restartSystemUI(anyString())
     }
 
     @Test
@@ -482,13 +509,13 @@
             .thenReturn("override7")
 
         // WHEN the flags have been accessed
-        assertThat(mFeatureFlagsDebug.isEnabled(flag1)).isTrue()
-        assertThat(mFeatureFlagsDebug.isEnabled(flag2)).isTrue()
-        assertThat(mFeatureFlagsDebug.isEnabled(flag3)).isFalse()
-        assertThat(mFeatureFlagsDebug.getString(flag4)).isEmpty()
-        assertThat(mFeatureFlagsDebug.getString(flag5)).isEqualTo("flag5default")
-        assertThat(mFeatureFlagsDebug.getString(flag6)).isEqualTo("resource1006")
-        assertThat(mFeatureFlagsDebug.getString(flag7)).isEqualTo("override7")
+        assertThat(featureFlagsDebug.isEnabled(flag1)).isTrue()
+        assertThat(featureFlagsDebug.isEnabled(flag2)).isTrue()
+        assertThat(featureFlagsDebug.isEnabled(flag3)).isFalse()
+        assertThat(featureFlagsDebug.getString(flag4)).isEmpty()
+        assertThat(featureFlagsDebug.getString(flag5)).isEqualTo("flag5default")
+        assertThat(featureFlagsDebug.getString(flag6)).isEqualTo("resource1006")
+        assertThat(featureFlagsDebug.getString(flag7)).isEqualTo("override7")
 
         // THEN the dump contains the flags and the default values
         val dump = dumpToString()
@@ -527,7 +554,7 @@
     private fun dumpToString(): String {
         val sw = StringWriter()
         val pw = PrintWriter(sw)
-        mFeatureFlagsDebug.dump(pw, emptyArray<String>())
+        featureFlagsDebug.dump(pw, emptyArray<String>())
         pw.flush()
         return sw.toString()
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseRestarterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseRestarterTest.kt
deleted file mode 100644
index 6060afe..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseRestarterTest.kt
+++ /dev/null
@@ -1,146 +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.flags
-
-import android.test.suitebuilder.annotation.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.keyguard.WakefulnessLifecycle
-import com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP
-import com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE
-import com.android.systemui.statusbar.policy.BatteryController
-import com.android.systemui.util.concurrency.FakeExecutor
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.time.FakeSystemClock
-import com.google.common.truth.Truth.assertThat
-import org.junit.Before
-import org.junit.Test
-import org.mockito.ArgumentCaptor
-import org.mockito.Mock
-import org.mockito.Mockito.never
-import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
-import org.mockito.MockitoAnnotations
-
-/**
- * Be careful with the {FeatureFlagsReleaseRestarter} in this test. It has a call to System.exit()!
- */
-@SmallTest
-class FeatureFlagsReleaseRestarterTest : SysuiTestCase() {
-    private lateinit var restarter: FeatureFlagsReleaseRestarter
-
-    @Mock private lateinit var wakefulnessLifecycle: WakefulnessLifecycle
-    @Mock private lateinit var batteryController: BatteryController
-    @Mock private lateinit var systemExitRestarter: SystemExitRestarter
-    private val executor = FakeExecutor(FakeSystemClock())
-
-    @Before
-    fun setup() {
-        MockitoAnnotations.initMocks(this)
-        restarter =
-            FeatureFlagsReleaseRestarter(
-                wakefulnessLifecycle,
-                batteryController,
-                executor,
-                systemExitRestarter
-            )
-    }
-
-    @Test
-    fun testRestart_ScheduledWhenReady() {
-        whenever(wakefulnessLifecycle.wakefulness).thenReturn(WAKEFULNESS_ASLEEP)
-        whenever(batteryController.isPluggedIn).thenReturn(true)
-
-        assertThat(executor.numPending()).isEqualTo(0)
-        restarter.restartSystemUI("Restart for test")
-        assertThat(executor.numPending()).isEqualTo(1)
-    }
-
-    @Test
-    fun testRestart_RestartsWhenIdle() {
-        whenever(wakefulnessLifecycle.wakefulness).thenReturn(WAKEFULNESS_ASLEEP)
-        whenever(batteryController.isPluggedIn).thenReturn(true)
-
-        restarter.restartSystemUI("Restart for test")
-        verify(systemExitRestarter, never()).restartSystemUI("Restart for test")
-        executor.advanceClockToLast()
-        executor.runAllReady()
-        verify(systemExitRestarter).restartSystemUI(any())
-    }
-
-    @Test
-    fun testRestart_NotScheduledWhenAwake() {
-        whenever(wakefulnessLifecycle.wakefulness).thenReturn(WAKEFULNESS_AWAKE)
-        whenever(batteryController.isPluggedIn).thenReturn(true)
-
-        assertThat(executor.numPending()).isEqualTo(0)
-        restarter.restartSystemUI("Restart for test")
-        assertThat(executor.numPending()).isEqualTo(0)
-    }
-
-    @Test
-    fun testRestart_NotScheduledWhenNotPluggedIn() {
-        whenever(wakefulnessLifecycle.wakefulness).thenReturn(WAKEFULNESS_ASLEEP)
-        whenever(batteryController.isPluggedIn).thenReturn(false)
-
-        assertThat(executor.numPending()).isEqualTo(0)
-        restarter.restartSystemUI("Restart for test")
-        assertThat(executor.numPending()).isEqualTo(0)
-    }
-
-    @Test
-    fun testRestart_NotDoubleSheduled() {
-        whenever(wakefulnessLifecycle.wakefulness).thenReturn(WAKEFULNESS_ASLEEP)
-        whenever(batteryController.isPluggedIn).thenReturn(true)
-
-        assertThat(executor.numPending()).isEqualTo(0)
-        restarter.restartSystemUI("Restart for test")
-        restarter.restartSystemUI("Restart for test")
-        assertThat(executor.numPending()).isEqualTo(1)
-    }
-
-    @Test
-    fun testWakefulnessLifecycle_CanRestart() {
-        whenever(wakefulnessLifecycle.wakefulness).thenReturn(WAKEFULNESS_AWAKE)
-        whenever(batteryController.isPluggedIn).thenReturn(true)
-        assertThat(executor.numPending()).isEqualTo(0)
-        restarter.restartSystemUI("Restart for test")
-
-        val captor = ArgumentCaptor.forClass(WakefulnessLifecycle.Observer::class.java)
-        verify(wakefulnessLifecycle).addObserver(captor.capture())
-
-        whenever(wakefulnessLifecycle.wakefulness).thenReturn(WAKEFULNESS_ASLEEP)
-
-        captor.value.onFinishedGoingToSleep()
-        assertThat(executor.numPending()).isEqualTo(1)
-    }
-
-    @Test
-    fun testBatteryController_CanRestart() {
-        whenever(wakefulnessLifecycle.wakefulness).thenReturn(WAKEFULNESS_ASLEEP)
-        whenever(batteryController.isPluggedIn).thenReturn(false)
-        assertThat(executor.numPending()).isEqualTo(0)
-        restarter.restartSystemUI("Restart for test")
-
-        val captor =
-            ArgumentCaptor.forClass(BatteryController.BatteryStateChangeCallback::class.java)
-        verify(batteryController).addCallback(captor.capture())
-
-        whenever(batteryController.isPluggedIn).thenReturn(true)
-
-        captor.value.onBatteryLevelChanged(0, true, true)
-        assertThat(executor.numPending()).isEqualTo(1)
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.kt
index 4c6028c..917147b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.kt
@@ -24,6 +24,8 @@
 import org.junit.Before
 import org.junit.Test
 import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.never
 import org.mockito.MockitoAnnotations
 import org.mockito.Mockito.`when` as whenever
 
@@ -33,7 +35,7 @@
  */
 @SmallTest
 class FeatureFlagsReleaseTest : SysuiTestCase() {
-    private lateinit var mFeatureFlagsRelease: FeatureFlagsRelease
+    private lateinit var featureFlagsRelease: FeatureFlagsRelease
 
     @Mock private lateinit var mResources: Resources
     @Mock private lateinit var mSystemProperties: SystemPropertiesHelper
@@ -41,15 +43,21 @@
     private val flagMap = mutableMapOf<String, Flag<*>>()
     private val serverFlagReader = ServerFlagReaderFake()
 
+
+    private val flagA = ReleasedFlag(501, name = "a", namespace = "test")
+
     @Before
     fun setup() {
         MockitoAnnotations.initMocks(this)
-        mFeatureFlagsRelease = FeatureFlagsRelease(
+        flagMap.put(flagA.name, flagA)
+        featureFlagsRelease = FeatureFlagsRelease(
             mResources,
             mSystemProperties,
             serverFlagReader,
             flagMap,
             restarter)
+
+        featureFlagsRelease.init()
     }
 
     @Test
@@ -60,7 +68,7 @@
         val flagNamespace = "test"
         val flag = ResourceBooleanFlag(flagId, flagName, flagNamespace, flagResourceId)
         whenever(mResources.getBoolean(flagResourceId)).thenReturn(true)
-        assertThat(mFeatureFlagsRelease.isEnabled(flag)).isTrue()
+        assertThat(featureFlagsRelease.isEnabled(flag)).isTrue()
     }
 
     @Test
@@ -70,16 +78,16 @@
         whenever(mResources.getString(1003)).thenReturn(null)
         whenever(mResources.getString(1004)).thenAnswer { throw NameNotFoundException() }
 
-        assertThat(mFeatureFlagsRelease.getString(
+        assertThat(featureFlagsRelease.getString(
             ResourceStringFlag(1, "1", "test", 1001))).isEqualTo("")
-        assertThat(mFeatureFlagsRelease.getString(
+        assertThat(featureFlagsRelease.getString(
             ResourceStringFlag(2, "2", "test", 1002))).isEqualTo("res2")
 
         assertThrows(NullPointerException::class.java) {
-            mFeatureFlagsRelease.getString(ResourceStringFlag(3, "3", "test", 1003))
+            featureFlagsRelease.getString(ResourceStringFlag(3, "3", "test", 1003))
         }
         assertThrows(NameNotFoundException::class.java) {
-            mFeatureFlagsRelease.getString(ResourceStringFlag(4, "4", "test", 1004))
+            featureFlagsRelease.getString(ResourceStringFlag(4, "4", "test", 1004))
         }
     }
 
@@ -92,7 +100,7 @@
 
         val flag = SysPropBooleanFlag(flagId, flagName, flagNamespace, flagDefault)
         whenever(mSystemProperties.getBoolean(flagName, flagDefault)).thenReturn(flagDefault)
-        assertThat(mFeatureFlagsRelease.isEnabled(flag)).isEqualTo(flagDefault)
+        assertThat(featureFlagsRelease.isEnabled(flag)).isEqualTo(flagDefault)
     }
 
     @Test
@@ -101,7 +109,7 @@
 
         serverFlagReader.setFlagValue(flag.namespace, flag.name, false)
 
-        assertThat(mFeatureFlagsRelease.isEnabled(flag)).isFalse()
+        assertThat(featureFlagsRelease.isEnabled(flag)).isFalse()
     }
 
     @Test
@@ -110,6 +118,32 @@
 
         serverFlagReader.setFlagValue(flag.namespace, flag.name, true)
 
-        assertThat(mFeatureFlagsRelease.isEnabled(flag)).isFalse()
+        assertThat(featureFlagsRelease.isEnabled(flag)).isFalse()
+    }
+
+    @Test
+    fun serverSide_OverrideUncached_NoRestart() {
+        // No one has read the flag, so it's not in the cache.
+        serverFlagReader.setFlagValue(
+            flagA.namespace, flagA.name, !flagA.default)
+        Mockito.verify(restarter, never()).restartSystemUI(Mockito.anyString())
+    }
+
+    @Test
+    fun serverSide_Override_Restarts() {
+        // Read it to put it in the cache.
+        featureFlagsRelease.isEnabled(flagA)
+        serverFlagReader.setFlagValue(
+            flagA.namespace, flagA.name, !flagA.default)
+        Mockito.verify(restarter).restartSystemUI(Mockito.anyString())
+    }
+
+    @Test
+    fun serverSide_RedundantOverride_NoRestart() {
+        // Read it to put it in the cache.
+        featureFlagsRelease.isEnabled(flagA)
+        serverFlagReader.setFlagValue(
+            flagA.namespace, flagA.name, flagA.default)
+        Mockito.verify(restarter, never()).restartSystemUI(Mockito.anyString())
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/PluggedInConditionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/PluggedInConditionTest.kt
new file mode 100644
index 0000000..647b05a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/PluggedInConditionTest.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.flags
+
+import android.test.suitebuilder.annotation.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.policy.BatteryController
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.mockito.ArgumentCaptor
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+
+/**
+ * Be careful with the {FeatureFlagsReleaseRestarter} in this test. It has a call to System.exit()!
+ */
+@SmallTest
+class PluggedInConditionTest : SysuiTestCase() {
+    private lateinit var condition: PluggedInCondition
+
+    @Mock private lateinit var batteryController: BatteryController
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+        condition = PluggedInCondition(batteryController)
+    }
+
+    @Test
+    fun testCondition_unplugged() {
+        whenever(batteryController.isPluggedIn).thenReturn(false)
+
+        assertThat(condition.canRestartNow({})).isFalse()
+    }
+
+    @Test
+    fun testCondition_pluggedIn() {
+        whenever(batteryController.isPluggedIn).thenReturn(true)
+
+        assertThat(condition.canRestartNow({})).isTrue()
+    }
+
+    @Test
+    fun testCondition_invokesRetry() {
+        whenever(batteryController.isPluggedIn).thenReturn(false)
+        var retried = false
+        val retryFn = { retried = true }
+
+        // No restart yet, but we do register a listener now.
+        assertThat(condition.canRestartNow(retryFn)).isFalse()
+        val captor =
+            ArgumentCaptor.forClass(BatteryController.BatteryStateChangeCallback::class.java)
+        verify(batteryController).addCallback(captor.capture())
+
+        whenever(batteryController.isPluggedIn).thenReturn(true)
+
+        captor.value.onBatteryLevelChanged(0, true, true)
+        assertThat(retried).isTrue()
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/RestartDozeListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/RestartDozeListenerTest.kt
index de0e511..e287f19 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/RestartDozeListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/RestartDozeListenerTest.kt
@@ -20,12 +20,16 @@
 import android.test.suitebuilder.annotation.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.settings.FakeSettings
 import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
 import org.junit.Test
 import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.anyString
 import org.mockito.Mock
 import org.mockito.Mockito.anyLong
 import org.mockito.Mockito.never
@@ -41,13 +45,14 @@
     @Mock lateinit var statusBarStateController: StatusBarStateController
     @Mock lateinit var powerManager: PowerManager
     val clock = FakeSystemClock()
+    val executor = FakeExecutor(clock)
     lateinit var listener: StatusBarStateController.StateListener
 
     @Before
     fun setup() {
         MockitoAnnotations.initMocks(this)
         restartDozeListener =
-            RestartDozeListener(settings, statusBarStateController, powerManager, clock)
+            RestartDozeListener(settings, statusBarStateController, powerManager, clock, executor)
 
         val captor = ArgumentCaptor.forClass(StatusBarStateController.StateListener::class.java)
         restartDozeListener.init()
@@ -56,30 +61,37 @@
     }
 
     @Test
-    fun testStoreDreamState_onDreamingStarted() {
-        listener.onDreamingChanged(true)
-        assertThat(settings.getBool(RestartDozeListener.RESTART_NAP_KEY)).isTrue()
+    fun testStoreDreamState_onDozingStarted() {
+        listener.onDozingChanged(true)
+        executor.runAllReady()
+        assertThat(settings.getBool(RestartDozeListener.RESTART_SLEEP_KEY)).isTrue()
     }
 
     @Test
-    fun testStoreDreamState_onDreamingStopped() {
-        listener.onDreamingChanged(false)
-        assertThat(settings.getBool(RestartDozeListener.RESTART_NAP_KEY)).isFalse()
+    fun testStoreDozeState_onDozingStopped() {
+        listener.onDozingChanged(false)
+        executor.runAllReady()
+        assertThat(settings.getBool(RestartDozeListener.RESTART_SLEEP_KEY)).isFalse()
     }
 
     @Test
-    fun testRestoreDreamState_dreamingShouldStart() {
-        settings.putBool(RestartDozeListener.RESTART_NAP_KEY, true)
+    fun testRestoreDozeState_dozingShouldStart() {
+        settings.putBool(RestartDozeListener.RESTART_SLEEP_KEY, true)
         restartDozeListener.maybeRestartSleep()
-        verify(powerManager).wakeUp(clock.uptimeMillis())
+        executor.advanceClockToLast()
+        executor.runAllReady()
+        verify(powerManager)
+            .wakeUp(eq(clock.uptimeMillis()), eq(PowerManager.WAKE_REASON_APPLICATION), anyString())
         verify(powerManager).goToSleep(clock.uptimeMillis())
     }
 
     @Test
-    fun testRestoreDreamState_dreamingShouldNot() {
-        settings.putBool(RestartDozeListener.RESTART_NAP_KEY, false)
+    fun testRestoreDozeState_dozingShouldNotStart() {
+        settings.putBool(RestartDozeListener.RESTART_SLEEP_KEY, false)
         restartDozeListener.maybeRestartSleep()
-        verify(powerManager, never()).wakeUp(anyLong())
+        executor.advanceClockToLast()
+        executor.runAllReady()
+        verify(powerManager, never()).wakeUp(anyLong(), anyInt(), anyString())
         verify(powerManager, never()).goToSleep(anyLong())
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugRestarterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/ScreenIdleConditionTest.kt
similarity index 66%
rename from packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugRestarterTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/flags/ScreenIdleConditionTest.kt
index 686782f..f7a773e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugRestarterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/ScreenIdleConditionTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,12 +20,11 @@
 import com.android.systemui.keyguard.WakefulnessLifecycle
 import com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP
 import com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE
-import com.android.systemui.util.mockito.any
+import com.google.common.truth.Truth.assertThat
 import org.junit.Before
 import org.junit.Test
 import org.mockito.ArgumentCaptor
 import org.mockito.Mock
-import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when` as whenever
 import org.mockito.MockitoAnnotations
@@ -34,37 +33,45 @@
  * Be careful with the {FeatureFlagsReleaseRestarter} in this test. It has a call to System.exit()!
  */
 @SmallTest
-class FeatureFlagsDebugRestarterTest : SysuiTestCase() {
-    private lateinit var restarter: FeatureFlagsDebugRestarter
+class ScreenIdleConditionTest : SysuiTestCase() {
+    private lateinit var condition: ScreenIdleCondition
 
     @Mock private lateinit var wakefulnessLifecycle: WakefulnessLifecycle
-    @Mock private lateinit var systemExitRestarter: SystemExitRestarter
 
     @Before
     fun setup() {
         MockitoAnnotations.initMocks(this)
-        restarter = FeatureFlagsDebugRestarter(wakefulnessLifecycle, systemExitRestarter)
+        condition = ScreenIdleCondition(wakefulnessLifecycle)
     }
 
     @Test
-    fun testRestart_ImmediateWhenAsleep() {
-        whenever(wakefulnessLifecycle.wakefulness).thenReturn(WAKEFULNESS_ASLEEP)
-        restarter.restartSystemUI("Restart for test")
-        verify(systemExitRestarter).restartSystemUI(any())
-    }
-
-    @Test
-    fun testRestart_WaitsForSceenOff() {
+    fun testCondition_awake() {
         whenever(wakefulnessLifecycle.wakefulness).thenReturn(WAKEFULNESS_AWAKE)
 
-        restarter.restartSystemUI("Restart for test")
-        verify(systemExitRestarter, never()).restartSystemUI(any())
+        assertThat(condition.canRestartNow {}).isFalse()
+    }
 
+    @Test
+    fun testCondition_asleep() {
+        whenever(wakefulnessLifecycle.wakefulness).thenReturn(WAKEFULNESS_ASLEEP)
+
+        assertThat(condition.canRestartNow {}).isTrue()
+    }
+
+    @Test
+    fun testCondition_invokesRetry() {
+        whenever(wakefulnessLifecycle.wakefulness).thenReturn(WAKEFULNESS_AWAKE)
+        var retried = false
+        val retryFn = { retried = true }
+
+        // No restart yet, but we do register a listener now.
+        assertThat(condition.canRestartNow(retryFn)).isFalse()
         val captor = ArgumentCaptor.forClass(WakefulnessLifecycle.Observer::class.java)
         verify(wakefulnessLifecycle).addObserver(captor.capture())
 
-        captor.value.onFinishedGoingToSleep()
+        whenever(wakefulnessLifecycle.wakefulness).thenReturn(WAKEFULNESS_ASLEEP)
 
-        verify(systemExitRestarter).restartSystemUI(any())
+        captor.value.onFinishedGoingToSleep()
+        assertThat(retried).isTrue()
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt
index 2e98006..953b7fb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt
@@ -21,11 +21,13 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.util.DeviceConfigProxyFake
 import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.any
 import com.android.systemui.util.time.FakeSystemClock
 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.MockitoAnnotations
@@ -57,18 +59,18 @@
         deviceConfig.setProperty(NAMESPACE, "flag_1", "1", false)
         executor.runAllReady()
 
-        verify(changeListener).onChange(flag)
+        verify(changeListener).onChange(flag, "1")
     }
 
     @Test
     fun testChange_ignoresListenersDuringTest() {
         val serverFlagReader = ServerFlagReaderImpl(NAMESPACE, deviceConfig, executor, true)
-        val flag = ReleasedFlag(1, "1", "test")
+        val flag = ReleasedFlag(1, "1", "   test")
         serverFlagReader.listenForChanges(listOf(flag), changeListener)
 
         deviceConfig.setProperty(NAMESPACE, "flag_override_1", "1", false)
         executor.runAllReady()
 
-        verify(changeListener, never()).onChange(flag)
+        verify(changeListener, never()).onChange(any(), anyString())
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractorTest.kt
new file mode 100644
index 0000000..ec94cde
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractorTest.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyboard.backlight.domain.interactor
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyboard.data.repository.FakeKeyboardRepository
+import com.android.systemui.keyboard.shared.model.BacklightModel
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class KeyboardBacklightInteractorTest : SysuiTestCase() {
+
+    private val keyboardRepository = FakeKeyboardRepository()
+    private lateinit var underTest: KeyboardBacklightInteractor
+
+    @Before
+    fun setUp() {
+        underTest = KeyboardBacklightInteractor(keyboardRepository)
+    }
+
+    @Test
+    fun emitsNull_whenKeyboardJustConnected() = runTest {
+        val latest by collectLastValue(underTest.backlight)
+        keyboardRepository.setKeyboardConnected(true)
+
+        assertThat(latest).isNull()
+    }
+
+    @Test
+    fun emitsBacklight_whenKeyboardConnectedAndBacklightChanged() = runTest {
+        keyboardRepository.setKeyboardConnected(true)
+        keyboardRepository.setBacklight(BacklightModel(1, 5))
+
+        assertThat(underTest.backlight.first()).isEqualTo(BacklightModel(1, 5))
+    }
+
+    @Test
+    fun emitsNull_afterKeyboardDisconnecting() = runTest {
+        val latest by collectLastValue(underTest.backlight)
+        keyboardRepository.setKeyboardConnected(true)
+        keyboardRepository.setBacklight(BacklightModel(1, 5))
+
+        keyboardRepository.setKeyboardConnected(false)
+
+        assertThat(latest).isNull()
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModelTest.kt
new file mode 100644
index 0000000..ec05d10
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModelTest.kt
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyboard.backlight.ui.viewmodel
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyboard.backlight.domain.interactor.KeyboardBacklightInteractor
+import com.android.systemui.keyboard.data.repository.FakeKeyboardRepository
+import com.android.systemui.keyboard.shared.model.BacklightModel
+import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.test.advanceTimeBy
+import kotlinx.coroutines.test.runTest
+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
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class BacklightDialogViewModelTest : SysuiTestCase() {
+
+    private val keyboardRepository = FakeKeyboardRepository()
+    private lateinit var underTest: BacklightDialogViewModel
+    @Mock private lateinit var accessibilityManagerWrapper: AccessibilityManagerWrapper
+    private val timeoutMillis = 3000L
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        whenever(accessibilityManagerWrapper.getRecommendedTimeoutMillis(any(), any()))
+            .thenReturn(timeoutMillis.toInt())
+        underTest =
+            BacklightDialogViewModel(
+                KeyboardBacklightInteractor(keyboardRepository),
+                accessibilityManagerWrapper
+            )
+        keyboardRepository.setKeyboardConnected(true)
+    }
+
+    @Test
+    fun emitsViewModel_whenBacklightChanged() = runTest {
+        keyboardRepository.setBacklight(BacklightModel(1, 5))
+
+        assertThat(underTest.dialogContent.first()).isEqualTo(BacklightDialogContentViewModel(1, 5))
+    }
+
+    @Test
+    fun emitsNull_afterTimeout() = runTest {
+        val latest by collectLastValue(underTest.dialogContent)
+        keyboardRepository.setBacklight(BacklightModel(1, 5))
+
+        assertThat(latest).isEqualTo(BacklightDialogContentViewModel(1, 5))
+        advanceTimeBy(timeoutMillis + 1)
+        assertThat(latest).isNull()
+    }
+
+    @Test
+    fun emitsNull_after5secDelay_fromLastBacklightChange() = runTest {
+        val latest by collectLastValue(underTest.dialogContent)
+        keyboardRepository.setKeyboardConnected(true)
+
+        keyboardRepository.setBacklight(BacklightModel(1, 5))
+        assertThat(latest).isEqualTo(BacklightDialogContentViewModel(1, 5))
+
+        advanceTimeBy(timeoutMillis * 2 / 3)
+        // timeout yet to pass, no new emission
+        keyboardRepository.setBacklight(BacklightModel(2, 5))
+        assertThat(latest).isEqualTo(BacklightDialogContentViewModel(2, 5))
+
+        advanceTimeBy(timeoutMillis * 2 / 3)
+        // timeout refreshed because of last `setBacklight`, still content present
+        assertThat(latest).isEqualTo(BacklightDialogContentViewModel(2, 5))
+
+        advanceTimeBy(timeoutMillis * 2 / 3)
+        // finally timeout reached and null emitted
+        assertThat(latest).isNull()
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
index a4e5bca..3accefd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
@@ -189,6 +189,7 @@
             )
         underTest.previewManager =
             KeyguardRemotePreviewManager(
+                applicationScope = testScope.backgroundScope,
                 previewRendererFactory = previewRendererFactory,
                 mainDispatcher = testDispatcher,
                 backgroundHandler = backgroundHandler,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepositoryTest.kt
index ff22f1e..4e7b3b9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepositoryTest.kt
@@ -55,7 +55,7 @@
 
     @Test
     fun changingFlowValueTriggersLogging() = runBlocking {
-        underTest.setPrimaryHide(true)
-        verify(bouncerLogger).logChange("", "PrimaryBouncerHide", false)
+        underTest.setPrimaryShow(true)
+        verify(bouncerLogger).logChange("", "PrimaryBouncerShow", false)
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
index ae227b4..d9d4013 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
@@ -21,6 +21,7 @@
 import android.util.Log.TerribleFailure
 import android.util.Log.TerribleFailureHandler
 import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.FlakyTest
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.Interpolators
@@ -47,6 +48,7 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
+@FlakyTest(bugId = 270760395)
 class KeyguardTransitionRepositoryTest : SysuiTestCase() {
 
     private lateinit var underTest: KeyguardTransitionRepository
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt
index 1365132..86246f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt
@@ -28,6 +28,7 @@
 import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
 import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepositoryImpl
 import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.mockito.whenever
 import com.android.systemui.util.time.FakeSystemClock
@@ -39,8 +40,10 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
 import org.mockito.Mock
 import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
@@ -52,6 +55,7 @@
     private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
     private lateinit var deviceEntryFingerprintAuthRepository:
         FakeDeviceEntryFingerprintAuthRepository
+    @Mock private lateinit var statusBarStateController: StatusBarStateController
     @Mock private lateinit var keyguardStateController: KeyguardStateController
     @Mock private lateinit var systemClock: SystemClock
     @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
@@ -73,6 +77,7 @@
         featureFlags = FakeFeatureFlags().apply { this.set(Flags.MODERN_ALTERNATE_BOUNCER, true) }
         underTest =
             AlternateBouncerInteractor(
+                statusBarStateController,
                 keyguardStateController,
                 bouncerRepository,
                 biometricSettingsRepository,
@@ -130,6 +135,14 @@
     }
 
     @Test
+    fun canShowAlternateBouncerForFingerprint_isDozing() {
+        givenCanShowAlternateBouncer()
+        whenever(statusBarStateController.isDozing).thenReturn(true)
+
+        assertFalse(underTest.canShowAlternateBouncerForFingerprint())
+    }
+
+    @Test
     fun show_whenCanShow() {
         givenCanShowAlternateBouncer()
 
@@ -169,6 +182,42 @@
         assertFalse(bouncerRepository.alternateBouncerVisible.value)
     }
 
+    @Test
+    fun onUnlockedIsFalse_doesNotHide() {
+        // GIVEN alternate bouncer is showing
+        bouncerRepository.setAlternateVisible(true)
+
+        val keyguardStateControllerCallbackCaptor =
+            ArgumentCaptor.forClass(KeyguardStateController.Callback::class.java)
+        verify(keyguardStateController).addCallback(keyguardStateControllerCallbackCaptor.capture())
+
+        // WHEN isUnlocked=false
+        givenCanShowAlternateBouncer()
+        whenever(keyguardStateController.isUnlocked).thenReturn(false)
+        keyguardStateControllerCallbackCaptor.value.onUnlockedChanged()
+
+        // THEN the alternate bouncer is still visible
+        assertTrue(bouncerRepository.alternateBouncerVisible.value)
+    }
+
+    @Test
+    fun onUnlockedChangedIsTrue_hide() {
+        // GIVEN alternate bouncer is showing
+        bouncerRepository.setAlternateVisible(true)
+
+        val keyguardStateControllerCallbackCaptor =
+            ArgumentCaptor.forClass(KeyguardStateController.Callback::class.java)
+        verify(keyguardStateController).addCallback(keyguardStateControllerCallbackCaptor.capture())
+
+        // WHEN isUnlocked=true
+        givenCanShowAlternateBouncer()
+        whenever(keyguardStateController.isUnlocked).thenReturn(true)
+        keyguardStateControllerCallbackCaptor.value.onUnlockedChanged()
+
+        // THEN the alternate bouncer is hidden
+        assertFalse(bouncerRepository.alternateBouncerVisible.value)
+    }
+
     private fun givenCanShowAlternateBouncer() {
         bouncerRepository.setAlternateBouncerUIAvailable(true)
         biometricSettingsRepository.setFingerprintEnrolled(true)
@@ -176,6 +225,7 @@
         biometricSettingsRepository.setFingerprintEnabledByDevicePolicy(true)
         deviceEntryFingerprintAuthRepository.setLockedOut(false)
         whenever(keyguardStateController.isUnlocked).thenReturn(false)
+        whenever(statusBarStateController.isDozing).thenReturn(false)
     }
 
     private fun givenCannotShowAlternateBouncer() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
index 153439e..7f30162 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
@@ -145,7 +145,7 @@
             repository.setKeyguardOccluded(true)
             assertThat(secureCameraActive()).isTrue()
 
-            bouncerRepository.setPrimaryVisible(true)
+            bouncerRepository.setPrimaryShow(true)
             assertThat(secureCameraActive()).isFalse()
         }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
index 62c9e5f..5528b94 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
@@ -281,6 +281,24 @@
         }
 
     @Test
+    fun `quickAffordance - hidden when quick settings is visible`() =
+        testScope.runTest {
+            repository.setQuickSettingsVisible(true)
+            quickAccessWallet.setState(
+                KeyguardQuickAffordanceConfig.LockScreenState.Visible(
+                    icon = ICON,
+                )
+            )
+
+            val collectedValue =
+                collectLastValue(
+                    underTest.quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_END)
+                )
+
+            assertThat(collectedValue()).isEqualTo(KeyguardQuickAffordanceModel.Hidden)
+        }
+
+    @Test
     fun `quickAffordance - bottom start affordance hidden while dozing`() =
         testScope.runTest {
             repository.setDozing(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index fe9098f..092fdca 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -259,7 +259,7 @@
             runCurrent()
 
             // WHEN the primary bouncer is set to show
-            bouncerRepository.setPrimaryVisible(true)
+            bouncerRepository.setPrimaryShow(true)
             runCurrent()
 
             val info =
@@ -358,6 +358,50 @@
         }
 
     @Test
+    fun `LOCKSCREEN to DREAMING`() =
+        testScope.runTest {
+            // GIVEN a device that is not dreaming or dozing
+            keyguardRepository.setDreamingWithOverlay(false)
+            keyguardRepository.setWakefulnessModel(startingToWake())
+            keyguardRepository.setDozeTransitionModel(
+                DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH)
+            )
+            runCurrent()
+
+            // GIVEN a prior transition has run to LOCKSCREEN
+            runner.startTransition(
+                testScope,
+                TransitionInfo(
+                    ownerName = "",
+                    from = KeyguardState.GONE,
+                    to = KeyguardState.LOCKSCREEN,
+                    animator =
+                        ValueAnimator().apply {
+                            duration = 10
+                            interpolator = Interpolators.LINEAR
+                        },
+                )
+            )
+            reset(mockTransitionRepository)
+
+            // WHEN the device begins to dream
+            keyguardRepository.setDreamingWithOverlay(true)
+            advanceUntilIdle()
+
+            val info =
+                withArgCaptor<TransitionInfo> {
+                    verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+                }
+            // THEN a transition to DREAMING should occur
+            assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
+            assertThat(info.from).isEqualTo(KeyguardState.LOCKSCREEN)
+            assertThat(info.to).isEqualTo(KeyguardState.DREAMING)
+            assertThat(info.animator).isNotNull()
+
+            coroutineContext.cancelChildren()
+        }
+
+    @Test
     fun `LOCKSCREEN to DOZING`() =
         testScope.runTest {
             // GIVEN a device with AOD not available
@@ -697,7 +741,7 @@
             reset(mockTransitionRepository)
 
             // WHEN the alternateBouncer stops showing and then the primary bouncer shows
-            bouncerRepository.setPrimaryVisible(true)
+            bouncerRepository.setPrimaryShow(true)
             runCurrent()
 
             val info =
@@ -735,7 +779,7 @@
             reset(mockTransitionRepository)
 
             // GIVEN the primary bouncer isn't showing, aod available and starting to sleep
-            bouncerRepository.setPrimaryVisible(false)
+            bouncerRepository.setPrimaryShow(false)
             keyguardRepository.setAodAvailable(true)
             keyguardRepository.setWakefulnessModel(startingToSleep())
 
@@ -779,7 +823,7 @@
 
             // GIVEN the primary bouncer isn't showing, aod not available and starting to sleep
             // to sleep
-            bouncerRepository.setPrimaryVisible(false)
+            bouncerRepository.setPrimaryShow(false)
             keyguardRepository.setAodAvailable(false)
             keyguardRepository.setWakefulnessModel(startingToSleep())
 
@@ -822,7 +866,7 @@
             reset(mockTransitionRepository)
 
             // GIVEN the primary bouncer isn't showing and device not sleeping
-            bouncerRepository.setPrimaryVisible(false)
+            bouncerRepository.setPrimaryShow(false)
             keyguardRepository.setWakefulnessModel(startingToWake())
 
             // WHEN the alternateBouncer stops showing
@@ -846,7 +890,7 @@
     fun `PRIMARY_BOUNCER to AOD`() =
         testScope.runTest {
             // GIVEN a prior transition has run to PRIMARY_BOUNCER
-            bouncerRepository.setPrimaryVisible(true)
+            bouncerRepository.setPrimaryShow(true)
             runner.startTransition(
                 testScope,
                 TransitionInfo(
@@ -868,7 +912,7 @@
             keyguardRepository.setWakefulnessModel(startingToSleep())
 
             // WHEN the primaryBouncer stops showing
-            bouncerRepository.setPrimaryVisible(false)
+            bouncerRepository.setPrimaryShow(false)
             runCurrent()
 
             val info =
@@ -888,7 +932,7 @@
     fun `PRIMARY_BOUNCER to DOZING`() =
         testScope.runTest {
             // GIVEN a prior transition has run to PRIMARY_BOUNCER
-            bouncerRepository.setPrimaryVisible(true)
+            bouncerRepository.setPrimaryShow(true)
             runner.startTransition(
                 testScope,
                 TransitionInfo(
@@ -910,7 +954,7 @@
             keyguardRepository.setWakefulnessModel(startingToSleep())
 
             // WHEN the primaryBouncer stops showing
-            bouncerRepository.setPrimaryVisible(false)
+            bouncerRepository.setPrimaryShow(false)
             runCurrent()
 
             val info =
@@ -930,7 +974,7 @@
     fun `PRIMARY_BOUNCER to LOCKSCREEN`() =
         testScope.runTest {
             // GIVEN a prior transition has run to PRIMARY_BOUNCER
-            bouncerRepository.setPrimaryVisible(true)
+            bouncerRepository.setPrimaryShow(true)
             runner.startTransition(
                 testScope,
                 TransitionInfo(
@@ -951,7 +995,7 @@
             keyguardRepository.setWakefulnessModel(startingToWake())
 
             // WHEN the alternateBouncer stops showing
-            bouncerRepository.setPrimaryVisible(false)
+            bouncerRepository.setPrimaryShow(false)
             runCurrent()
 
             val info =
@@ -967,6 +1011,92 @@
             coroutineContext.cancelChildren()
         }
 
+    @Test
+    fun `OCCLUDED to GONE`() =
+        testScope.runTest {
+            // GIVEN a device on lockscreen
+            keyguardRepository.setKeyguardShowing(true)
+            runCurrent()
+
+            // GIVEN a prior transition has run to OCCLUDED
+            runner.startTransition(
+                testScope,
+                TransitionInfo(
+                    ownerName = "",
+                    from = KeyguardState.LOCKSCREEN,
+                    to = KeyguardState.OCCLUDED,
+                    animator =
+                        ValueAnimator().apply {
+                            duration = 10
+                            interpolator = Interpolators.LINEAR
+                        },
+                )
+            )
+            keyguardRepository.setKeyguardOccluded(true)
+            runCurrent()
+            reset(mockTransitionRepository)
+
+            // WHEN keyguard goes away
+            keyguardRepository.setKeyguardShowing(false)
+            // AND occlusion ends
+            keyguardRepository.setKeyguardOccluded(false)
+            runCurrent()
+
+            val info =
+                withArgCaptor<TransitionInfo> {
+                    verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+                }
+            // THEN a transition to GONE should occur
+            assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor")
+            assertThat(info.from).isEqualTo(KeyguardState.OCCLUDED)
+            assertThat(info.to).isEqualTo(KeyguardState.GONE)
+            assertThat(info.animator).isNotNull()
+
+            coroutineContext.cancelChildren()
+        }
+
+    @Test
+    fun `OCCLUDED to LOCKSCREEN`() =
+        testScope.runTest {
+            // GIVEN a device on lockscreen
+            keyguardRepository.setKeyguardShowing(true)
+            runCurrent()
+
+            // GIVEN a prior transition has run to OCCLUDED
+            runner.startTransition(
+                testScope,
+                TransitionInfo(
+                    ownerName = "",
+                    from = KeyguardState.LOCKSCREEN,
+                    to = KeyguardState.OCCLUDED,
+                    animator =
+                        ValueAnimator().apply {
+                            duration = 10
+                            interpolator = Interpolators.LINEAR
+                        },
+                )
+            )
+            keyguardRepository.setKeyguardOccluded(true)
+            runCurrent()
+            reset(mockTransitionRepository)
+
+            // WHEN occlusion ends
+            keyguardRepository.setKeyguardOccluded(false)
+            runCurrent()
+
+            val info =
+                withArgCaptor<TransitionInfo> {
+                    verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+                }
+            // THEN a transition to LOCKSCREEN should occur
+            assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor")
+            assertThat(info.from).isEqualTo(KeyguardState.OCCLUDED)
+            assertThat(info.to).isEqualTo(KeyguardState.LOCKSCREEN)
+            assertThat(info.animator).isNotNull()
+
+            coroutineContext.cancelChildren()
+        }
+
     private fun startingToWake() =
         WakefulnessModel(
             WakefulnessState.STARTING_TO_WAKE,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt
index 6b7fd61..bdc33f4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt
@@ -35,11 +35,11 @@
 import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN
 import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE
 import com.android.systemui.keyguard.shared.model.BouncerShowMessageModel
-import com.android.systemui.keyguard.shared.model.KeyguardBouncerModel
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.whenever
 import com.android.systemui.utils.os.FakeHandler
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
@@ -51,7 +51,6 @@
 import org.mockito.Mockito.mock
 import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when`
 import org.mockito.MockitoAnnotations
 
 @SmallTest
@@ -91,9 +90,9 @@
                 keyguardUpdateMonitor,
                 keyguardBypassController,
             )
-        `when`(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(null)
-        `when`(repository.primaryBouncerShow.value).thenReturn(null)
-        `when`(bouncerView.delegate).thenReturn(bouncerViewDelegate)
+        whenever(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(null)
+        whenever(repository.primaryBouncerShow.value).thenReturn(false)
+        whenever(bouncerView.delegate).thenReturn(bouncerViewDelegate)
         resources = context.orCreateTestableResources
     }
 
@@ -101,15 +100,13 @@
     fun testShow_isScrimmed() {
         underTest.show(true)
         verify(repository).setKeyguardAuthenticated(null)
-        verify(repository).setPrimaryHide(false)
         verify(repository).setPrimaryStartingToHide(false)
         verify(repository).setPrimaryScrimmed(true)
         verify(repository).setPanelExpansion(EXPANSION_VISIBLE)
         verify(repository).setPrimaryShowingSoon(true)
         verify(keyguardStateController).notifyPrimaryBouncerShowing(true)
         verify(mPrimaryBouncerCallbackInteractor).dispatchStartingToShow()
-        verify(repository).setPrimaryVisible(true)
-        verify(repository).setPrimaryShow(any(KeyguardBouncerModel::class.java))
+        verify(repository).setPrimaryShow(true)
         verify(repository).setPrimaryShowingSoon(false)
         verify(mPrimaryBouncerCallbackInteractor).dispatchVisibilityChanged(View.VISIBLE)
     }
@@ -121,7 +118,7 @@
 
     @Test
     fun testShow_keyguardIsDone() {
-        `when`(bouncerView.delegate?.showNextSecurityScreenOrFinish()).thenReturn(true)
+        whenever(bouncerView.delegate?.showNextSecurityScreenOrFinish()).thenReturn(true)
         verify(keyguardStateController, never()).notifyPrimaryBouncerShowing(true)
         verify(mPrimaryBouncerCallbackInteractor, never()).dispatchStartingToShow()
     }
@@ -132,15 +129,13 @@
         verify(falsingCollector).onBouncerHidden()
         verify(keyguardStateController).notifyPrimaryBouncerShowing(false)
         verify(repository).setPrimaryShowingSoon(false)
-        verify(repository).setPrimaryVisible(false)
-        verify(repository).setPrimaryHide(true)
-        verify(repository).setPrimaryShow(null)
+        verify(repository).setPrimaryShow(false)
         verify(mPrimaryBouncerCallbackInteractor).dispatchVisibilityChanged(View.INVISIBLE)
     }
 
     @Test
     fun testExpansion() {
-        `when`(repository.panelExpansionAmount.value).thenReturn(0.5f)
+        whenever(repository.panelExpansionAmount.value).thenReturn(0.5f)
         underTest.setPanelExpansion(0.6f)
         verify(repository).setPanelExpansion(0.6f)
         verify(mPrimaryBouncerCallbackInteractor).dispatchExpansionChanged(0.6f)
@@ -148,8 +143,8 @@
 
     @Test
     fun testExpansion_fullyShown() {
-        `when`(repository.panelExpansionAmount.value).thenReturn(0.5f)
-        `when`(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(null)
+        whenever(repository.panelExpansionAmount.value).thenReturn(0.5f)
+        whenever(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(null)
         underTest.setPanelExpansion(EXPANSION_VISIBLE)
         verify(falsingCollector).onBouncerShown()
         verify(mPrimaryBouncerCallbackInteractor).dispatchFullyShown()
@@ -157,12 +152,10 @@
 
     @Test
     fun testExpansion_fullyHidden() {
-        `when`(repository.panelExpansionAmount.value).thenReturn(0.5f)
-        `when`(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(null)
+        whenever(repository.panelExpansionAmount.value).thenReturn(0.5f)
+        whenever(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(null)
         underTest.setPanelExpansion(EXPANSION_HIDDEN)
-        verify(repository).setPrimaryVisible(false)
-        verify(repository).setPrimaryShow(null)
-        verify(repository).setPrimaryHide(true)
+        verify(repository).setPrimaryShow(false)
         verify(falsingCollector).onBouncerHidden()
         verify(mPrimaryBouncerCallbackInteractor).dispatchReset()
         verify(mPrimaryBouncerCallbackInteractor).dispatchFullyHidden()
@@ -170,7 +163,7 @@
 
     @Test
     fun testExpansion_startingToHide() {
-        `when`(repository.panelExpansionAmount.value).thenReturn(EXPANSION_VISIBLE)
+        whenever(repository.panelExpansionAmount.value).thenReturn(EXPANSION_VISIBLE)
         underTest.setPanelExpansion(0.1f)
         verify(repository).setPrimaryStartingToHide(true)
         verify(mPrimaryBouncerCallbackInteractor).dispatchStartingToHide()
@@ -235,7 +228,21 @@
     }
 
     @Test
-    fun testStartDisappearAnimation() {
+    fun testStartDisappearAnimation_willRunDismissFromKeyguard() {
+        whenever(bouncerViewDelegate.willRunDismissFromKeyguard()).thenReturn(true)
+
+        val runnable = mock(Runnable::class.java)
+        underTest.startDisappearAnimation(runnable)
+        // End runnable should run immediately
+        verify(runnable).run()
+        // ... while the disappear animation should never be run
+        verify(repository, never()).setPrimaryStartDisappearAnimation(any(Runnable::class.java))
+    }
+
+    @Test
+    fun testStartDisappearAnimation_willNotRunDismissFromKeyguard_() {
+        whenever(bouncerViewDelegate.willRunDismissFromKeyguard()).thenReturn(false)
+
         val runnable = mock(Runnable::class.java)
         underTest.startDisappearAnimation(runnable)
         verify(repository).setPrimaryStartDisappearAnimation(any(Runnable::class.java))
@@ -243,45 +250,45 @@
 
     @Test
     fun testIsFullShowing() {
-        `when`(repository.primaryBouncerVisible.value).thenReturn(true)
-        `when`(repository.panelExpansionAmount.value).thenReturn(EXPANSION_VISIBLE)
-        `when`(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(null)
+        whenever(repository.primaryBouncerShow.value).thenReturn(true)
+        whenever(repository.panelExpansionAmount.value).thenReturn(EXPANSION_VISIBLE)
+        whenever(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(null)
         assertThat(underTest.isFullyShowing()).isTrue()
-        `when`(repository.primaryBouncerVisible.value).thenReturn(false)
+        whenever(repository.primaryBouncerShow.value).thenReturn(false)
         assertThat(underTest.isFullyShowing()).isFalse()
     }
 
     @Test
     fun testIsScrimmed() {
-        `when`(repository.primaryBouncerScrimmed.value).thenReturn(true)
+        whenever(repository.primaryBouncerScrimmed.value).thenReturn(true)
         assertThat(underTest.isScrimmed()).isTrue()
-        `when`(repository.primaryBouncerScrimmed.value).thenReturn(false)
+        whenever(repository.primaryBouncerScrimmed.value).thenReturn(false)
         assertThat(underTest.isScrimmed()).isFalse()
     }
 
     @Test
     fun testIsInTransit() {
-        `when`(repository.primaryBouncerShowingSoon.value).thenReturn(true)
+        whenever(repository.primaryBouncerShowingSoon.value).thenReturn(true)
         assertThat(underTest.isInTransit()).isTrue()
-        `when`(repository.primaryBouncerShowingSoon.value).thenReturn(false)
+        whenever(repository.primaryBouncerShowingSoon.value).thenReturn(false)
         assertThat(underTest.isInTransit()).isFalse()
-        `when`(repository.panelExpansionAmount.value).thenReturn(0.5f)
+        whenever(repository.panelExpansionAmount.value).thenReturn(0.5f)
         assertThat(underTest.isInTransit()).isTrue()
     }
 
     @Test
     fun testIsAnimatingAway() {
-        `when`(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(Runnable {})
+        whenever(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(Runnable {})
         assertThat(underTest.isAnimatingAway()).isTrue()
-        `when`(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(null)
+        whenever(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(null)
         assertThat(underTest.isAnimatingAway()).isFalse()
     }
 
     @Test
     fun testWillDismissWithAction() {
-        `when`(bouncerViewDelegate.willDismissWithActions()).thenReturn(true)
+        whenever(bouncerViewDelegate.willDismissWithActions()).thenReturn(true)
         assertThat(underTest.willDismissWithAction()).isTrue()
-        `when`(bouncerViewDelegate.willDismissWithActions()).thenReturn(false)
+        whenever(bouncerViewDelegate.willDismissWithActions()).thenReturn(false)
         assertThat(underTest.willDismissWithAction()).isFalse()
     }
 
@@ -370,12 +377,13 @@
         isUnlockingWithFpAllowed: Boolean,
         isAnimatingAway: Boolean
     ) {
-        `when`(repository.primaryBouncerVisible.value).thenReturn(isVisible)
+        whenever(repository.primaryBouncerShow.value).thenReturn(isVisible)
         resources.addOverride(R.bool.config_show_sidefps_hint_on_bouncer, sfpsEnabled)
-        `when`(keyguardUpdateMonitor.isFingerprintDetectionRunning).thenReturn(fpsDetectionRunning)
-        `when`(keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed)
+        whenever(keyguardUpdateMonitor.isFingerprintDetectionRunning)
+            .thenReturn(fpsDetectionRunning)
+        whenever(keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed)
             .thenReturn(isUnlockingWithFpAllowed)
-        `when`(repository.primaryBouncerStartingDisappearAnimation.value)
+        whenever(repository.primaryBouncerStartingDisappearAnimation.value)
             .thenReturn(if (isAnimatingAway) Runnable {} else null)
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt
index f675e79..edac468 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt
@@ -77,7 +77,7 @@
     fun notInteractableWhenExpansionIsBelow90Percent() = runTest {
         val isInteractable = collectLastValue(underTest.isInteractable)
 
-        repository.setPrimaryVisible(true)
+        repository.setPrimaryShow(true)
         repository.setPanelExpansion(0.15f)
 
         assertThat(isInteractable()).isFalse()
@@ -87,7 +87,7 @@
     fun notInteractableWhenExpansionAbove90PercentButNotVisible() = runTest {
         val isInteractable = collectLastValue(underTest.isInteractable)
 
-        repository.setPrimaryVisible(false)
+        repository.setPrimaryShow(false)
         repository.setPanelExpansion(0.05f)
 
         assertThat(isInteractable()).isFalse()
@@ -97,7 +97,7 @@
     fun isInteractableWhenExpansionAbove90PercentAndVisible() = runTest {
         var isInteractable = collectLastValue(underTest.isInteractable)
 
-        repository.setPrimaryVisible(true)
+        repository.setPrimaryShow(true)
         repository.setPanelExpansion(0.09f)
 
         assertThat(isInteractable()).isTrue()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModelTest.kt
index 65e4c10..2ab1b99 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModelTest.kt
@@ -93,10 +93,22 @@
     }
 
     @Test
-    fun shouldUpdateSideFps() = runTest {
+    fun shouldUpdateSideFps_show() = runTest {
         var count = 0
         val job = underTest.shouldUpdateSideFps.onEach { count++ }.launchIn(this)
-        repository.setPrimaryVisible(true)
+        repository.setPrimaryShow(true)
+        // Run the tasks that are pending at this point of virtual time.
+        runCurrent()
+        assertThat(count).isEqualTo(1)
+        job.cancel()
+    }
+
+    @Test
+    fun shouldUpdateSideFps_hide() = runTest {
+        repository.setPrimaryShow(true)
+        var count = 0
+        val job = underTest.shouldUpdateSideFps.onEach { count++ }.launchIn(this)
+        repository.setPrimaryShow(false)
         // Run the tasks that are pending at this point of virtual time.
         runCurrent()
         assertThat(count).isEqualTo(1)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
new file mode 100644
index 0000000..98794fd
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.ScrimAlpha
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.statusbar.SysuiStatusBarStateController
+import com.android.systemui.util.mockito.whenever
+import com.google.common.collect.Range
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class PrimaryBouncerToGoneTransitionViewModelTest : SysuiTestCase() {
+    private lateinit var underTest: PrimaryBouncerToGoneTransitionViewModel
+    private lateinit var repository: FakeKeyguardTransitionRepository
+    @Mock private lateinit var statusBarStateController: SysuiStatusBarStateController
+    @Mock private lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        repository = FakeKeyguardTransitionRepository()
+        val interactor = KeyguardTransitionInteractor(repository)
+        underTest =
+            PrimaryBouncerToGoneTransitionViewModel(
+                interactor,
+                statusBarStateController,
+                primaryBouncerInteractor
+            )
+
+        whenever(primaryBouncerInteractor.willRunDismissFromKeyguard()).thenReturn(false)
+        whenever(statusBarStateController.leaveOpenOnKeyguardHide()).thenReturn(false)
+    }
+
+    @Test
+    fun bouncerAlpha() =
+        runTest(UnconfinedTestDispatcher()) {
+            val values = mutableListOf<Float>()
+
+            val job = underTest.bouncerAlpha.onEach { values.add(it) }.launchIn(this)
+
+            repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+            repository.sendTransitionStep(step(0.3f))
+            repository.sendTransitionStep(step(0.6f))
+
+            assertThat(values.size).isEqualTo(3)
+            values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) }
+
+            job.cancel()
+        }
+
+    @Test
+    fun bouncerAlpha_runDimissFromKeyguard() =
+        runTest(UnconfinedTestDispatcher()) {
+            val values = mutableListOf<Float>()
+
+            val job = underTest.bouncerAlpha.onEach { values.add(it) }.launchIn(this)
+
+            whenever(primaryBouncerInteractor.willRunDismissFromKeyguard()).thenReturn(true)
+
+            repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+            repository.sendTransitionStep(step(0.3f))
+            repository.sendTransitionStep(step(0.6f))
+
+            assertThat(values.size).isEqualTo(3)
+            values.forEach { assertThat(it).isEqualTo(0f) }
+
+            job.cancel()
+        }
+
+    @Test
+    fun scrimAlpha_runDimissFromKeyguard() =
+        runTest(UnconfinedTestDispatcher()) {
+            val values = mutableListOf<ScrimAlpha>()
+
+            val job = underTest.scrimAlpha.onEach { values.add(it) }.launchIn(this)
+
+            whenever(primaryBouncerInteractor.willRunDismissFromKeyguard()).thenReturn(true)
+
+            repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+            repository.sendTransitionStep(step(0.3f))
+            repository.sendTransitionStep(step(0.6f))
+            repository.sendTransitionStep(step(1f))
+
+            assertThat(values.size).isEqualTo(4)
+            values.forEach { assertThat(it).isEqualTo(ScrimAlpha()) }
+
+            job.cancel()
+        }
+
+    @Test
+    fun scrimBehindAlpha_leaveShadeOpen() =
+        runTest(UnconfinedTestDispatcher()) {
+            val values = mutableListOf<ScrimAlpha>()
+
+            val job = underTest.scrimAlpha.onEach { values.add(it) }.launchIn(this)
+
+            whenever(statusBarStateController.leaveOpenOnKeyguardHide()).thenReturn(true)
+
+            repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+            repository.sendTransitionStep(step(0.3f))
+            repository.sendTransitionStep(step(0.6f))
+            repository.sendTransitionStep(step(1f))
+
+            assertThat(values.size).isEqualTo(4)
+            values.forEach {
+                assertThat(it).isEqualTo(ScrimAlpha(notificationsAlpha = 1f, behindAlpha = 1f))
+            }
+
+            job.cancel()
+        }
+
+    @Test
+    fun scrimBehindAlpha_doNotLeaveShadeOpen() =
+        runTest(UnconfinedTestDispatcher()) {
+            val values = mutableListOf<ScrimAlpha>()
+
+            val job = underTest.scrimAlpha.onEach { values.add(it) }.launchIn(this)
+
+            whenever(statusBarStateController.leaveOpenOnKeyguardHide()).thenReturn(false)
+
+            repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+            repository.sendTransitionStep(step(0.3f))
+            repository.sendTransitionStep(step(0.6f))
+            repository.sendTransitionStep(step(1f))
+
+            assertThat(values.size).isEqualTo(4)
+            values.forEach { assertThat(it.notificationsAlpha).isEqualTo(0f) }
+            values.forEach { assertThat(it.frontAlpha).isEqualTo(0f) }
+            values.forEach { assertThat(it.behindAlpha).isIn(Range.closed(0f, 1f)) }
+            assertThat(values[3].behindAlpha).isEqualTo(0f)
+
+            job.cancel()
+        }
+
+    private fun step(
+        value: Float,
+        state: TransitionState = TransitionState.RUNNING
+    ): TransitionStep {
+        return TransitionStep(
+            from = KeyguardState.PRIMARY_BOUNCER,
+            to = KeyguardState.GONE,
+            value = value,
+            transitionState = state,
+            ownerName = "PrimaryBouncerToGoneTransitionViewModelTest"
+        )
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableChangeTest.kt b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableChangeTest.kt
index c7f3fa0..fb20bac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableChangeTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableChangeTest.kt
@@ -121,4 +121,92 @@
         assertThat(underTest.getName()).doesNotContain("original")
         assertThat(underTest.getVal()).isEqualTo("8900")
     }
+
+    @Test
+    fun updateTo_emptyToString_isString() {
+        val underTest = TableChange(columnPrefix = "fakePrefix", columnName = "fakeName")
+
+        val new = TableChange(columnPrefix = "newPrefix", columnName = "newName")
+        new.set("newString")
+        underTest.updateTo(new)
+
+        assertThat(underTest.hasData()).isTrue()
+        assertThat(underTest.getName()).contains("newPrefix")
+        assertThat(underTest.getName()).contains("newName")
+        assertThat(underTest.getVal()).isEqualTo("newString")
+    }
+
+    @Test
+    fun updateTo_intToEmpty_isEmpty() {
+        val underTest = TableChange(columnPrefix = "fakePrefix", columnName = "fakeName")
+        underTest.set(42)
+
+        val new = TableChange(columnPrefix = "newPrefix", columnName = "newName")
+        underTest.updateTo(new)
+
+        assertThat(underTest.hasData()).isFalse()
+        assertThat(underTest.getName()).contains("newPrefix")
+        assertThat(underTest.getName()).contains("newName")
+        assertThat(underTest.getVal()).isEqualTo("null")
+    }
+
+    @Test
+    fun updateTo_stringToBool_isBool() {
+        val underTest = TableChange(columnPrefix = "fakePrefix", columnName = "fakeName")
+        underTest.set("oldString")
+
+        val new = TableChange(columnPrefix = "newPrefix", columnName = "newName")
+        new.set(true)
+        underTest.updateTo(new)
+
+        assertThat(underTest.hasData()).isTrue()
+        assertThat(underTest.getName()).contains("newPrefix")
+        assertThat(underTest.getName()).contains("newName")
+        assertThat(underTest.getVal()).isEqualTo("true")
+    }
+
+    @Test
+    fun updateTo_intToString_isString() {
+        val underTest = TableChange(columnPrefix = "fakePrefix", columnName = "fakeName")
+        underTest.set(43)
+
+        val new = TableChange(columnPrefix = "newPrefix", columnName = "newName")
+        new.set("newString")
+        underTest.updateTo(new)
+
+        assertThat(underTest.hasData()).isTrue()
+        assertThat(underTest.getName()).contains("newPrefix")
+        assertThat(underTest.getName()).contains("newName")
+        assertThat(underTest.getVal()).isEqualTo("newString")
+    }
+
+    @Test
+    fun updateTo_boolToInt_isInt() {
+        val underTest = TableChange(columnPrefix = "fakePrefix", columnName = "fakeName")
+        underTest.set(false)
+
+        val new = TableChange(columnPrefix = "newPrefix", columnName = "newName")
+        new.set(44)
+        underTest.updateTo(new)
+
+        assertThat(underTest.hasData()).isTrue()
+        assertThat(underTest.getName()).contains("newPrefix")
+        assertThat(underTest.getName()).contains("newName")
+        assertThat(underTest.getVal()).isEqualTo("44")
+    }
+
+    @Test
+    fun updateTo_boolToNewBool_isNewBool() {
+        val underTest = TableChange(columnPrefix = "fakePrefix", columnName = "fakeName")
+        underTest.set(false)
+
+        val new = TableChange(columnPrefix = "newPrefix", columnName = "newName")
+        new.set(true)
+        underTest.updateTo(new)
+
+        assertThat(underTest.hasData()).isTrue()
+        assertThat(underTest.getName()).contains("newPrefix")
+        assertThat(underTest.getName()).contains("newName")
+        assertThat(underTest.getVal()).isEqualTo("true")
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt
index 2c8d7ab..949fa1c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt
@@ -435,11 +435,236 @@
 
         assertThat(dumpedString).doesNotContain("testString[0]")
         assertThat(dumpedString).doesNotContain("testString[1]")
-        assertThat(dumpedString).doesNotContain("testString[2]")
+        // The buffer should contain [MAX_SIZE + 1] entries since we also save the most recently
+        // evicted value.
+        assertThat(dumpedString).contains("testString[2]")
         assertThat(dumpedString).contains("testString[3]")
         assertThat(dumpedString).contains("testString[${MAX_SIZE + 2}]")
     }
 
+    @Test
+    fun columnEvicted_lastKnownColumnValueInDump() {
+        systemClock.setCurrentTimeMillis(100L)
+        underTest.logChange(prefix = "", columnName = "willBeEvicted", value = "evictedValue")
+
+        // Exactly fill the buffer so that "willBeEvicted" is evicted
+        for (i in 0 until MAX_SIZE) {
+            systemClock.advanceTime(100L)
+            val dumpString = "fillString[$i]"
+            underTest.logChange(prefix = "", columnName = "fillingColumn", value = dumpString)
+        }
+
+        val dumpedString = dumpChanges()
+
+        // Expect that we'll have both the evicted column entry...
+        val evictedColumnLog =
+            TABLE_LOG_DATE_FORMAT.format(100L) +
+                SEPARATOR +
+                "willBeEvicted" +
+                SEPARATOR +
+                "evictedValue"
+        assertThat(dumpedString).contains(evictedColumnLog)
+
+        // ... *and* all of the fillingColumn entries.
+        val firstFillingColumnLog =
+            TABLE_LOG_DATE_FORMAT.format(200L) +
+                SEPARATOR +
+                "fillingColumn" +
+                SEPARATOR +
+                "fillString[0]"
+        val lastFillingColumnLog =
+            TABLE_LOG_DATE_FORMAT.format(1100L) +
+                SEPARATOR +
+                "fillingColumn" +
+                SEPARATOR +
+                "fillString[9]"
+        assertThat(dumpedString).contains(firstFillingColumnLog)
+        assertThat(dumpedString).contains(lastFillingColumnLog)
+    }
+
+    @Test
+    fun multipleColumnsEvicted_allColumnsInDump() {
+        systemClock.setCurrentTimeMillis(100L)
+        underTest.logChange(prefix = "", columnName = "willBeEvictedString", value = "evictedValue")
+        systemClock.advanceTime(100L)
+        underTest.logChange(prefix = "", columnName = "willBeEvictedInt", value = 45)
+        systemClock.advanceTime(100L)
+        underTest.logChange(prefix = "", columnName = "willBeEvictedBool", value = true)
+
+        // Exactly fill the buffer so that all the above columns will be evicted
+        for (i in 0 until MAX_SIZE) {
+            systemClock.advanceTime(100L)
+            val dumpString = "fillString[$i]"
+            underTest.logChange(prefix = "", columnName = "fillingColumn", value = dumpString)
+        }
+
+        val dumpedString = dumpChanges()
+
+        // Expect that we'll have all the evicted column entries...
+        val evictedColumnLogString =
+            TABLE_LOG_DATE_FORMAT.format(100L) +
+                SEPARATOR +
+                "willBeEvictedString" +
+                SEPARATOR +
+                "evictedValue"
+        val evictedColumnLogInt =
+            TABLE_LOG_DATE_FORMAT.format(200L) + SEPARATOR + "willBeEvictedInt" + SEPARATOR + "45"
+        val evictedColumnLogBool =
+            TABLE_LOG_DATE_FORMAT.format(300L) +
+                SEPARATOR +
+                "willBeEvictedBool" +
+                SEPARATOR +
+                "true"
+        assertThat(dumpedString).contains(evictedColumnLogString)
+        assertThat(dumpedString).contains(evictedColumnLogInt)
+        assertThat(dumpedString).contains(evictedColumnLogBool)
+
+        // ... *and* all of the fillingColumn entries.
+        val firstFillingColumnLog =
+            TABLE_LOG_DATE_FORMAT.format(400) +
+                SEPARATOR +
+                "fillingColumn" +
+                SEPARATOR +
+                "fillString[0]"
+        val lastFillingColumnLog =
+            TABLE_LOG_DATE_FORMAT.format(1300) +
+                SEPARATOR +
+                "fillingColumn" +
+                SEPARATOR +
+                "fillString[9]"
+        assertThat(dumpedString).contains(firstFillingColumnLog)
+        assertThat(dumpedString).contains(lastFillingColumnLog)
+    }
+
+    @Test
+    fun multipleColumnsEvicted_differentPrefixSameName_allColumnsInDump() {
+        systemClock.setCurrentTimeMillis(100L)
+        underTest.logChange(prefix = "prefix1", columnName = "sameName", value = "value1")
+        systemClock.advanceTime(100L)
+        underTest.logChange(prefix = "prefix2", columnName = "sameName", value = "value2")
+        systemClock.advanceTime(100L)
+        underTest.logChange(prefix = "prefix3", columnName = "sameName", value = "value3")
+
+        // Exactly fill the buffer so that all the above columns will be evicted
+        for (i in 0 until MAX_SIZE) {
+            systemClock.advanceTime(100L)
+            val dumpString = "fillString[$i]"
+            underTest.logChange(prefix = "", columnName = "fillingColumn", value = dumpString)
+        }
+
+        val dumpedString = dumpChanges()
+
+        // Expect that we'll have all the evicted column entries
+        val evictedColumn1 =
+            TABLE_LOG_DATE_FORMAT.format(100L) +
+                SEPARATOR +
+                "prefix1.sameName" +
+                SEPARATOR +
+                "value1"
+        val evictedColumn2 =
+            TABLE_LOG_DATE_FORMAT.format(200L) +
+                SEPARATOR +
+                "prefix2.sameName" +
+                SEPARATOR +
+                "value2"
+        val evictedColumn3 =
+            TABLE_LOG_DATE_FORMAT.format(300L) +
+                SEPARATOR +
+                "prefix3.sameName" +
+                SEPARATOR +
+                "value3"
+        assertThat(dumpedString).contains(evictedColumn1)
+        assertThat(dumpedString).contains(evictedColumn2)
+        assertThat(dumpedString).contains(evictedColumn3)
+    }
+
+    @Test
+    fun multipleColumnsEvicted_dumpSortedByTimestamp() {
+        systemClock.setCurrentTimeMillis(100L)
+        underTest.logChange(prefix = "", columnName = "willBeEvictedFirst", value = "evictedValue")
+        systemClock.advanceTime(100L)
+        underTest.logChange(prefix = "", columnName = "willBeEvictedSecond", value = 45)
+        systemClock.advanceTime(100L)
+        underTest.logChange(prefix = "", columnName = "willBeEvictedThird", value = true)
+
+        // Exactly fill the buffer with so that all the above columns will be evicted
+        for (i in 0 until MAX_SIZE) {
+            systemClock.advanceTime(100L)
+            val dumpString = "fillString[$i]"
+            underTest.logChange(prefix = "", columnName = "fillingColumn", value = dumpString)
+        }
+
+        val dumpedString = dumpChanges()
+
+        // Expect that we'll have all the evicted column entries in timestamp order
+        val firstEvictedLog =
+            TABLE_LOG_DATE_FORMAT.format(100L) +
+                SEPARATOR +
+                "willBeEvictedFirst" +
+                SEPARATOR +
+                "evictedValue"
+        val secondEvictedLog =
+            TABLE_LOG_DATE_FORMAT.format(200L) +
+                SEPARATOR +
+                "willBeEvictedSecond" +
+                SEPARATOR +
+                "45"
+        val thirdEvictedLog =
+            TABLE_LOG_DATE_FORMAT.format(300L) +
+                SEPARATOR +
+                "willBeEvictedThird" +
+                SEPARATOR +
+                "true"
+        assertThat(dumpedString).contains(firstEvictedLog)
+        val stringAfterFirst = dumpedString.substringAfter(firstEvictedLog)
+        assertThat(stringAfterFirst).contains(secondEvictedLog)
+        val stringAfterSecond = stringAfterFirst.substringAfter(secondEvictedLog)
+        assertThat(stringAfterSecond).contains(thirdEvictedLog)
+    }
+
+    @Test
+    fun sameColumnEvictedMultipleTimes_onlyLastEvictionInDump() {
+        systemClock.setCurrentTimeMillis(0L)
+
+        for (i in 1 until 4) {
+            systemClock.advanceTime(100L)
+            val dumpString = "evicted[$i]"
+            underTest.logChange(prefix = "", columnName = "evictedColumn", value = dumpString)
+        }
+
+        // Exactly fill the buffer so that all the entries for "evictedColumn" will be evicted.
+        for (i in 0 until MAX_SIZE) {
+            systemClock.advanceTime(100L)
+            val dumpString = "fillString[$i]"
+            underTest.logChange(prefix = "", columnName = "fillingColumn", value = dumpString)
+        }
+
+        val dumpedString = dumpChanges()
+
+        // Expect that we only have the most recent evicted column entry
+        val evictedColumnLog1 =
+            TABLE_LOG_DATE_FORMAT.format(100L) +
+                SEPARATOR +
+                "evictedColumn" +
+                SEPARATOR +
+                "evicted[1]"
+        val evictedColumnLog2 =
+            TABLE_LOG_DATE_FORMAT.format(200L) +
+                SEPARATOR +
+                "evictedColumn" +
+                SEPARATOR +
+                "evicted[2]"
+        val evictedColumnLog3 =
+            TABLE_LOG_DATE_FORMAT.format(300L) +
+                SEPARATOR +
+                "evictedColumn" +
+                SEPARATOR +
+                "evicted[3]"
+        assertThat(dumpedString).doesNotContain(evictedColumnLog1)
+        assertThat(dumpedString).doesNotContain(evictedColumnLog2)
+        assertThat(dumpedString).contains(evictedColumnLog3)
+    }
+
     private fun dumpChanges(): String {
         underTest.dump(PrintWriter(outputWriter), arrayOf())
         return outputWriter.toString()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt
index ab0669a..d428db7b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt
@@ -2031,7 +2031,7 @@
     }
 
     @Test
-    fun testRetain_sessionPlayer_destroyedWhileActive_fullyRemoved() {
+    fun testRetain_sessionPlayer_destroyedWhileActive_noResume_fullyRemoved() {
         whenever(mediaFlags.isRetainingPlayersEnabled()).thenReturn(true)
         whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true)
         addPlaybackStateAction()
@@ -2051,6 +2051,40 @@
     }
 
     @Test
+    fun testRetain_sessionPlayer_canResume_destroyedWhileActive_setToResume() {
+        whenever(mediaFlags.isRetainingPlayersEnabled()).thenReturn(true)
+        whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true)
+        addPlaybackStateAction()
+
+        // When a media control using session actions and that does allow resumption is added,
+        addNotificationAndLoad()
+        val dataResumable = mediaDataCaptor.value.copy(resumeAction = Runnable {})
+        mediaDataManager.onMediaDataLoaded(KEY, null, dataResumable)
+
+        // And then the session is destroyed without timing out first
+        sessionCallbackCaptor.value.invoke(KEY)
+
+        // It is converted to a resume player
+        verify(listener)
+            .onMediaDataLoaded(
+                eq(PACKAGE_NAME),
+                eq(KEY),
+                capture(mediaDataCaptor),
+                eq(true),
+                eq(0),
+                eq(false)
+            )
+        assertThat(mediaDataCaptor.value.resumption).isTrue()
+        assertThat(mediaDataCaptor.value.active).isFalse()
+        verify(logger)
+            .logActiveConvertedToResume(
+                anyInt(),
+                eq(PACKAGE_NAME),
+                eq(mediaDataCaptor.value.instanceId)
+            )
+    }
+
+    @Test
     fun testSessionDestroyed_noNotificationKey_stillRemoved() {
         whenever(mediaFlags.isRetainingPlayersEnabled()).thenReturn(true)
         whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/resume/MediaResumeListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/resume/MediaResumeListenerTest.kt
index 4dfa626..9ab7289 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/resume/MediaResumeListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/resume/MediaResumeListenerTest.kt
@@ -313,6 +313,25 @@
     }
 
     @Test
+    fun testOnLoadTwice_onlyChecksOnce() {
+        // When data is first loaded,
+        setUpMbsWithValidResolveInfo()
+        resumeListener.onMediaDataLoaded(KEY, null, data)
+
+        // We notify the manager to set a null action
+        verify(mediaDataManager).setResumeAction(KEY, null)
+
+        // If we then get another update from the app before the first check completes
+        assertThat(executor.numPending()).isEqualTo(1)
+        var dataWithCheck = data.copy(hasCheckedForResume = true)
+        resumeListener.onMediaDataLoaded(KEY, null, dataWithCheck)
+
+        // We do not try to start another check
+        assertThat(executor.numPending()).isEqualTo(1)
+        verify(mediaDataManager).setResumeAction(KEY, null)
+    }
+
+    @Test
     fun testOnUserUnlock_loadsTracks() {
         // Set up mock service to successfully find valid media
         val description = MediaDescription.Builder().setTitle(TITLE).build()
@@ -392,7 +411,7 @@
                 assertThat(result.size).isEqualTo(3)
                 assertThat(result[2].toLong()).isEqualTo(currentTime)
             }
-        verify(sharedPrefsEditor, times(1)).apply()
+        verify(sharedPrefsEditor).apply()
     }
 
     @Test
@@ -432,8 +451,8 @@
         resumeListener.userUnlockReceiver.onReceive(mockContext, intent)
 
         // We add its resume controls
-        verify(resumeBrowser, times(1)).findRecentMedia()
-        verify(mediaDataManager, times(1))
+        verify(resumeBrowser).findRecentMedia()
+        verify(mediaDataManager)
             .addResumptionControls(anyInt(), any(), any(), any(), any(), any(), eq(PACKAGE_NAME))
     }
 
@@ -516,7 +535,7 @@
                 assertThat(result.size).isEqualTo(3)
                 assertThat(result[2].toLong()).isEqualTo(currentTime)
             }
-        verify(sharedPrefsEditor, times(1)).apply()
+        verify(sharedPrefsEditor).apply()
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
index 7f57077..a72634b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
@@ -17,7 +17,6 @@
 package com.android.systemui.media.controls.ui
 
 import android.app.PendingIntent
-import android.content.res.ColorStateList
 import android.content.res.Configuration
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
@@ -27,9 +26,9 @@
 import com.android.internal.logging.InstanceId
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.keyguard.KeyguardUpdateMonitorCallback
-import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
@@ -50,7 +49,7 @@
 import com.android.systemui.statusbar.notification.collection.provider.OnReorderingAllowedListener
 import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider
 import com.android.systemui.statusbar.policy.ConfigurationController
-import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.concurrency.DelayableExecutor
 import com.android.systemui.util.mockito.capture
 import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.time.FakeSystemClock
@@ -90,6 +89,7 @@
     @Mock lateinit var mediaHostStatesManager: MediaHostStatesManager
     @Mock lateinit var mediaHostState: MediaHostState
     @Mock lateinit var activityStarter: ActivityStarter
+    @Mock @Main private lateinit var executor: DelayableExecutor
     @Mock lateinit var mediaDataManager: MediaDataManager
     @Mock lateinit var configurationController: ConfigurationController
     @Mock lateinit var falsingCollector: FalsingCollector
@@ -113,15 +113,11 @@
 
     private val clock = FakeSystemClock()
     private lateinit var mediaCarouselController: MediaCarouselController
-    private lateinit var mainExecutor: FakeExecutor
-    private lateinit var backgroundExecutor: FakeExecutor
 
     @Before
     fun setup() {
         MockitoAnnotations.initMocks(this)
         transitionRepository = FakeKeyguardTransitionRepository()
-        mainExecutor = FakeExecutor(clock)
-        backgroundExecutor = FakeExecutor(clock)
         mediaCarouselController =
             MediaCarouselController(
                 context,
@@ -130,8 +126,7 @@
                 mediaHostStatesManager,
                 activityStarter,
                 clock,
-                mainExecutor,
-                backgroundExecutor,
+                executor,
                 mediaDataManager,
                 configurationController,
                 falsingCollector,
@@ -406,7 +401,6 @@
                 resumption = true
             )
         )
-        runAllReady()
 
         assertEquals(
             MediaPlayerData.getMediaPlayerIndex("paused local"),
@@ -516,8 +510,6 @@
             false
         )
         mediaCarouselController.shouldScrollToKey = true
-        runAllReady()
-
         // switching between media players.
         listener.value.onMediaDataLoaded(
             "playing local",
@@ -539,7 +531,6 @@
                 resumption = false
             )
         )
-        runAllReady()
 
         assertEquals(
             MediaPlayerData.getMediaPlayerIndex("paused local"),
@@ -564,7 +555,6 @@
                 resumption = false
             )
         )
-        runAllReady()
 
         var playerIndex = MediaPlayerData.getMediaPlayerIndex("playing local")
         assertEquals(
@@ -587,8 +577,6 @@
                 packageName = "PACKAGE_NAME"
             )
         )
-        runAllReady()
-
         playerIndex = MediaPlayerData.getMediaPlayerIndex("playing local")
         assertEquals(playerIndex, 0)
     }
@@ -686,8 +674,6 @@
 
     @Test
     fun testOnConfigChanged_playersAreAddedBack() {
-        mediaCarouselController.pageIndicator = pageIndicator
-
         listener.value.onMediaDataLoaded(
             "playing local",
             null,
@@ -708,15 +694,11 @@
                 resumption = false
             )
         )
-        runAllReady()
 
         val playersSize = MediaPlayerData.players().size
 
         configListener.value.onConfigChanged(Configuration())
-        runAllReady()
 
-        verify(pageIndicator).tintList =
-            ColorStateList.valueOf(context.getColor(R.color.media_paging_indicator))
         assertEquals(playersSize, MediaPlayerData.players().size)
         assertEquals(
             MediaPlayerData.getMediaPlayerIndex("playing local"),
@@ -725,93 +707,6 @@
     }
 
     @Test
-    fun testOnUiModeChanged_playersAreAddedBack() {
-        mediaCarouselController.pageIndicator = pageIndicator
-
-        listener.value.onMediaDataLoaded(
-            "paused local",
-            null,
-            DATA.copy(
-                active = true,
-                isPlaying = false,
-                playbackLocation = MediaData.PLAYBACK_LOCAL,
-                resumption = false
-            )
-        )
-        runAllReady()
-
-        val playersSize = MediaPlayerData.players().size
-        configListener.value.onUiModeChanged()
-        runAllReady()
-
-        verify(pageIndicator).tintList =
-            ColorStateList.valueOf(context.getColor(R.color.media_paging_indicator))
-        assertEquals(playersSize, MediaPlayerData.players().size)
-        assertEquals(
-            MediaPlayerData.getMediaPlayerIndex("paused local"),
-            mediaCarouselController.mediaCarouselScrollHandler.visibleMediaIndex
-        )
-    }
-
-    @Test
-    fun testOnDensityOrFontScaleChanged_playersAreAddedBack() {
-        mediaCarouselController.pageIndicator = pageIndicator
-
-        listener.value.onMediaDataLoaded(
-            "paused local",
-            null,
-            DATA.copy(
-                active = true,
-                isPlaying = false,
-                playbackLocation = MediaData.PLAYBACK_LOCAL,
-                resumption = false
-            )
-        )
-        runAllReady()
-
-        val playersSize = MediaPlayerData.players().size
-        configListener.value.onDensityOrFontScaleChanged()
-        runAllReady()
-
-        verify(pageIndicator).tintList =
-            ColorStateList.valueOf(context.getColor(R.color.media_paging_indicator))
-        assertEquals(playersSize, MediaPlayerData.players().size)
-        assertEquals(
-            MediaPlayerData.getMediaPlayerIndex("paused local"),
-            mediaCarouselController.mediaCarouselScrollHandler.visibleMediaIndex
-        )
-    }
-
-    @Test
-    fun testOnThemeChanged_playersAreAddedBack() {
-        mediaCarouselController.pageIndicator = pageIndicator
-
-        listener.value.onMediaDataLoaded(
-            "paused local",
-            null,
-            DATA.copy(
-                active = true,
-                isPlaying = false,
-                playbackLocation = MediaData.PLAYBACK_LOCAL,
-                resumption = false
-            )
-        )
-        runAllReady()
-
-        val playersSize = MediaPlayerData.players().size
-        configListener.value.onThemeChanged()
-        runAllReady()
-
-        verify(pageIndicator).tintList =
-            ColorStateList.valueOf(context.getColor(R.color.media_paging_indicator))
-        assertEquals(playersSize, MediaPlayerData.players().size)
-        assertEquals(
-            MediaPlayerData.getMediaPlayerIndex("paused local"),
-            mediaCarouselController.mediaCarouselScrollHandler.visibleMediaIndex
-        )
-    }
-
-    @Test
     fun testRecommendation_persistentEnabled_newSmartspaceLoaded_updatesSort() {
         testRecommendation_persistentEnabled_inactiveSmartspaceDataLoaded_isAdded()
 
@@ -937,9 +832,4 @@
         // Verify that seekbar listening attribute in media control panel is set to false.
         verify(panel, times(MediaPlayerData.players().size)).listening = false
     }
-
-    private fun runAllReady() {
-        backgroundExecutor.runAllReady()
-        mainExecutor.runAllReady()
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
index 55a33b6..eba0591 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
@@ -27,6 +27,7 @@
 import android.graphics.Bitmap
 import android.graphics.Canvas
 import android.graphics.Color
+import android.graphics.Matrix
 import android.graphics.drawable.Animatable2
 import android.graphics.drawable.AnimatedVectorDrawable
 import android.graphics.drawable.Drawable
@@ -78,6 +79,8 @@
 import com.android.systemui.media.controls.pipeline.MediaDataManager
 import com.android.systemui.media.controls.util.MediaUiEventLogger
 import com.android.systemui.media.dialog.MediaOutputDialogFactory
+import com.android.systemui.monet.ColorScheme
+import com.android.systemui.monet.Style
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.statusbar.NotificationLockscreenUserManager
@@ -91,7 +94,6 @@
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.argumentCaptor
 import com.android.systemui.util.mockito.eq
-import com.android.systemui.util.mockito.nullable
 import com.android.systemui.util.mockito.withArgCaptor
 import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
@@ -214,6 +216,7 @@
     @Mock private lateinit var recSubtitleMock2: TextView
     @Mock private lateinit var recSubtitleMock3: TextView
     @Mock private lateinit var coverItem: ImageView
+    @Mock private lateinit var matrix: Matrix
     private lateinit var coverItem1: ImageView
     private lateinit var coverItem2: ImageView
     private lateinit var coverItem3: ImageView
@@ -700,6 +703,46 @@
     }
 
     @Test
+    fun addTwoPlayerGradients_differentStates() {
+        // Setup redArtwork and its color scheme.
+        val redBmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)
+        val redCanvas = Canvas(redBmp)
+        redCanvas.drawColor(Color.RED)
+        val redArt = Icon.createWithBitmap(redBmp)
+        val redWallpaperColor = player.getWallpaperColor(redArt)
+        val redColorScheme = ColorScheme(redWallpaperColor, true, Style.CONTENT)
+
+        // Setup greenArt and its color scheme.
+        val greenBmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)
+        val greenCanvas = Canvas(greenBmp)
+        greenCanvas.drawColor(Color.GREEN)
+        val greenArt = Icon.createWithBitmap(greenBmp)
+        val greenWallpaperColor = player.getWallpaperColor(greenArt)
+        val greenColorScheme = ColorScheme(greenWallpaperColor, true, Style.CONTENT)
+
+        // Add gradient to both icons.
+        val redArtwork = player.addGradientToPlayerAlbum(redArt, redColorScheme, 10, 10)
+        val greenArtwork = player.addGradientToPlayerAlbum(greenArt, greenColorScheme, 10, 10)
+
+        // They should have different constant states as they have different gradient color.
+        assertThat(redArtwork.getDrawable(1).constantState)
+            .isNotEqualTo(greenArtwork.getDrawable(1).constantState)
+    }
+
+    @Test
+    fun getWallpaperColor_recycledBitmap_notCrashing() {
+        // Setup redArt icon.
+        val redBmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)
+        val redArt = Icon.createWithBitmap(redBmp)
+
+        // Recycle bitmap of redArt icon.
+        redArt.bitmap.recycle()
+
+        // get wallpaperColor without illegal exception.
+        player.getWallpaperColor(redArt)
+    }
+
+    @Test
     fun bind_seekBarDisabled_hasActions_seekBarVisibilityIsSetToInvisible() {
         useRealConstraintSets()
 
@@ -1719,7 +1762,7 @@
     fun tapContentView_showOverLockscreen_openActivity() {
         // WHEN we are on lockscreen and this activity can show over lockscreen
         whenever(keyguardStateController.isShowing).thenReturn(true)
-        whenever(activityIntentHelper.wouldShowOverLockscreen(any(), any())).thenReturn(true)
+        whenever(activityIntentHelper.wouldPendingShowOverLockscreen(any(), any())).thenReturn(true)
 
         val clickIntent = mock(Intent::class.java)
         val pendingIntent = mock(PendingIntent::class.java)
@@ -1730,16 +1773,20 @@
         player.bindPlayer(data, KEY)
         verify(viewHolder.player).setOnClickListener(captor.capture())
 
-        // THEN it shows without dismissing keyguard first
+        // THEN it sends the PendingIntent without dismissing keyguard first,
+        // and does not use the Intent directly (see b/271845008)
         captor.value.onClick(viewHolder.player)
-        verify(activityStarter).startActivity(eq(clickIntent), eq(true), nullable(), eq(true))
+        verify(pendingIntent).send()
+        verify(pendingIntent, never()).getIntent()
+        verify(activityStarter, never()).postStartActivityDismissingKeyguard(eq(clickIntent), any())
     }
 
     @Test
     fun tapContentView_noShowOverLockscreen_dismissKeyguard() {
         // WHEN we are on lockscreen and the activity cannot show over lockscreen
         whenever(keyguardStateController.isShowing).thenReturn(true)
-        whenever(activityIntentHelper.wouldShowOverLockscreen(any(), any())).thenReturn(false)
+        whenever(activityIntentHelper.wouldPendingShowOverLockscreen(any(), any()))
+            .thenReturn(false)
 
         val clickIntent = mock(Intent::class.java)
         val pendingIntent = mock(PendingIntent::class.java)
@@ -2092,6 +2139,7 @@
             .thenReturn(listOf(recProgressBar1, recProgressBar2, recProgressBar3))
         whenever(recommendationViewHolder.mediaSubtitles)
             .thenReturn(listOf(recSubtitleMock1, recSubtitleMock2, recSubtitleMock3))
+        whenever(coverItem.imageMatrix).thenReturn(matrix)
 
         val bmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)
         val canvas = Canvas(bmp)
@@ -2127,6 +2175,7 @@
         verify(recCardTitle).setTextColor(any<Int>())
         verify(recAppIconItem, times(3)).setImageDrawable(any(Drawable::class.java))
         verify(coverItem, times(3)).setImageDrawable(any(Drawable::class.java))
+        verify(coverItem, times(3)).imageMatrix = any()
     }
 
     @Test
@@ -2189,6 +2238,34 @@
     }
 
     @Test
+    fun addTwoRecommendationGradients_differentStates() {
+        // Setup redArtwork and its color scheme.
+        val redBmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)
+        val redCanvas = Canvas(redBmp)
+        redCanvas.drawColor(Color.RED)
+        val redArt = Icon.createWithBitmap(redBmp)
+        val redWallpaperColor = player.getWallpaperColor(redArt)
+        val redColorScheme = ColorScheme(redWallpaperColor, true, Style.CONTENT)
+
+        // Setup greenArt and its color scheme.
+        val greenBmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)
+        val greenCanvas = Canvas(greenBmp)
+        greenCanvas.drawColor(Color.GREEN)
+        val greenArt = Icon.createWithBitmap(greenBmp)
+        val greenWallpaperColor = player.getWallpaperColor(greenArt)
+        val greenColorScheme = ColorScheme(greenWallpaperColor, true, Style.CONTENT)
+
+        // Add gradient to both icons.
+        val redArtwork = player.addGradientToRecommendationAlbum(redArt, redColorScheme, 10, 10)
+        val greenArtwork =
+            player.addGradientToRecommendationAlbum(greenArt, greenColorScheme, 10, 10)
+
+        // They should have different constant states as they have different gradient color.
+        assertThat(redArtwork.getDrawable(1).constantState)
+            .isNotEqualTo(greenArtwork.getDrawable(1).constantState)
+    }
+
+    @Test
     fun onButtonClick_touchRippleFlagEnabled_playsTouchRipple() {
         fakeFeatureFlag.set(Flags.UMO_SURFACE_RIPPLE, true)
         val semanticActions =
@@ -2273,6 +2350,48 @@
         }
     }
 
+    @Test
+    fun outputSwitcher_hasCustomIntent_openOverLockscreen() {
+        // When the device for a media player has an intent that opens over lockscreen
+        val pendingIntent = mock(PendingIntent::class.java)
+        whenever(pendingIntent.isActivity).thenReturn(true)
+        whenever(keyguardStateController.isShowing).thenReturn(true)
+        whenever(activityIntentHelper.wouldPendingShowOverLockscreen(any(), any())).thenReturn(true)
+
+        val customDevice = device.copy(intent = pendingIntent)
+        val dataWithDevice = mediaData.copy(device = customDevice)
+        player.attachPlayer(viewHolder)
+        player.bindPlayer(dataWithDevice, KEY)
+
+        // When the user taps on the output switcher,
+        seamless.callOnClick()
+
+        // Then we send the pending intent as is, without modifying the original intent
+        verify(pendingIntent).send()
+        verify(pendingIntent, never()).getIntent()
+    }
+
+    @Test
+    fun outputSwitcher_hasCustomIntent_requiresUnlock() {
+        // When the device for a media player has an intent that cannot open over lockscreen
+        val pendingIntent = mock(PendingIntent::class.java)
+        whenever(pendingIntent.isActivity).thenReturn(true)
+        whenever(keyguardStateController.isShowing).thenReturn(true)
+        whenever(activityIntentHelper.wouldPendingShowOverLockscreen(any(), any()))
+            .thenReturn(false)
+
+        val customDevice = device.copy(intent = pendingIntent)
+        val dataWithDevice = mediaData.copy(device = customDevice)
+        player.attachPlayer(viewHolder)
+        player.bindPlayer(dataWithDevice, KEY)
+
+        // When the user taps on the output switcher,
+        seamless.callOnClick()
+
+        // Then we request keyguard dismissal
+        verify(activityStarter).postStartActivityDismissingKeyguard(eq(pendingIntent))
+    }
+
     private fun getScrubbingChangeListener(): SeekBarViewModel.ScrubbingChangeListener =
         withArgCaptor {
             verify(seekBarViewModel).setScrubbingChangeListener(capture())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt
index a579518..feb429d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt
@@ -180,6 +180,57 @@
     }
 
     @Test
+    fun testBlockedWhenConfigurationChangesAndScreenOff() {
+        // Let's set it onto QS:
+        mediaHierarchyManager.qsExpansion = 1.0f
+        verify(mediaCarouselController)
+            .onDesiredLocationChanged(
+                ArgumentMatchers.anyInt(),
+                any(MediaHostState::class.java),
+                anyBoolean(),
+                anyLong(),
+                anyLong()
+            )
+        val observer = wakefullnessObserver.value
+        assertNotNull("lifecycle observer wasn't registered", observer)
+        observer.onStartedGoingToSleep()
+        clearInvocations(mediaCarouselController)
+        configurationController.notifyConfigurationChanged()
+        verify(mediaCarouselController, times(0))
+            .onDesiredLocationChanged(
+                ArgumentMatchers.anyInt(),
+                any(MediaHostState::class.java),
+                anyBoolean(),
+                anyLong(),
+                anyLong()
+            )
+    }
+
+    @Test
+    fun testAllowedWhenConfigurationChanges() {
+        // Let's set it onto QS:
+        mediaHierarchyManager.qsExpansion = 1.0f
+        verify(mediaCarouselController)
+            .onDesiredLocationChanged(
+                ArgumentMatchers.anyInt(),
+                any(MediaHostState::class.java),
+                anyBoolean(),
+                anyLong(),
+                anyLong()
+            )
+        clearInvocations(mediaCarouselController)
+        configurationController.notifyConfigurationChanged()
+        verify(mediaCarouselController)
+            .onDesiredLocationChanged(
+                ArgumentMatchers.anyInt(),
+                any(MediaHostState::class.java),
+                anyBoolean(),
+                anyLong(),
+                anyLong()
+            )
+    }
+
+    @Test
     fun testAllowedWhenNotTurningOff() {
         // Let's set it onto QS:
         mediaHierarchyManager.qsExpansion = 1.0f
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaViewControllerTest.kt
index af91cdb..4565762 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaViewControllerTest.kt
@@ -16,6 +16,8 @@
 
 package com.android.systemui.media.controls.ui
 
+import android.content.res.Configuration
+import android.content.res.Configuration.ORIENTATION_LANDSCAPE
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.view.View
@@ -77,6 +79,50 @@
     }
 
     @Test
+    fun testOrientationChanged_heightOfPlayerIsUpdated() {
+        val newConfig = Configuration()
+
+        mediaViewController.attach(player, MediaViewController.TYPE.PLAYER)
+        // Change the height to see the effect of orientation change.
+        MediaViewController.backgroundIds.forEach { id ->
+            mediaViewController.expandedLayout.getConstraint(id).layout.mHeight = 10
+        }
+        newConfig.orientation = ORIENTATION_LANDSCAPE
+        configurationController.onConfigurationChanged(newConfig)
+
+        MediaViewController.backgroundIds.forEach { id ->
+            assertTrue(
+                mediaViewController.expandedLayout.getConstraint(id).layout.mHeight ==
+                    context.resources.getDimensionPixelSize(
+                        R.dimen.qs_media_session_height_expanded
+                    )
+            )
+        }
+    }
+
+    @Test
+    fun testOrientationChanged_heightOfRecCardIsUpdated() {
+        val newConfig = Configuration()
+
+        mediaViewController.attach(recommendation, MediaViewController.TYPE.RECOMMENDATION)
+        // Change the height to see the effect of orientation change.
+        mediaViewController.expandedLayout
+            .getConstraint(MediaViewController.recSizingViewId)
+            .layout
+            .mHeight = 10
+        newConfig.orientation = ORIENTATION_LANDSCAPE
+        configurationController.onConfigurationChanged(newConfig)
+
+        assertTrue(
+            mediaViewController.expandedLayout
+                .getConstraint(MediaViewController.recSizingViewId)
+                .layout
+                .mHeight ==
+                context.resources.getDimensionPixelSize(R.dimen.qs_media_session_height_expanded)
+        )
+    }
+
+    @Test
     fun testObtainViewState_applySquishFraction_toPlayerTransitionViewState_height() {
         mediaViewController.attach(player, MediaViewController.TYPE.PLAYER)
         player.measureState =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt
index 85e8d07..6c3d6f5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt
@@ -25,6 +25,7 @@
 import com.android.systemui.common.shared.model.ContentDescription
 import com.android.systemui.common.shared.model.ContentDescription.Companion.loadContentDescription
 import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.temporarydisplay.chipbar.ChipbarInfo.Companion.DEFAULT_ICON_TINT
 import com.android.systemui.util.mockito.any
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
@@ -140,6 +141,7 @@
                 context.getString(R.string.media_transfer_receiver_content_description_unknown_app)
             )
         assertThat(iconInfo.icon).isEqualTo(MediaTttIcon.Resource(R.drawable.ic_cast))
+        assertThat(iconInfo.tint).isEqualTo(DEFAULT_ICON_TINT)
     }
 
     @Test
@@ -232,40 +234,40 @@
     fun iconInfo_toTintedIcon_loaded() {
         val contentDescription = ContentDescription.Loaded("test")
         val drawable = context.getDrawable(R.drawable.ic_cake)!!
-        val tintAttr = android.R.attr.textColorTertiary
+        val tint = R.color.GM2_blue_500
 
         val iconInfo =
             IconInfo(
                 contentDescription,
                 MediaTttIcon.Loaded(drawable),
-                tintAttr,
+                tint,
                 isAppIcon = false,
             )
 
         val tinted = iconInfo.toTintedIcon()
 
         assertThat(tinted.icon).isEqualTo(Icon.Loaded(drawable, contentDescription))
-        assertThat(tinted.tintAttr).isEqualTo(tintAttr)
+        assertThat(tinted.tint).isEqualTo(tint)
     }
 
     @Test
     fun iconInfo_toTintedIcon_resource() {
         val contentDescription = ContentDescription.Loaded("test")
         val drawableRes = R.drawable.ic_cake
-        val tintAttr = android.R.attr.textColorTertiary
+        val tint = R.color.GM2_blue_500
 
         val iconInfo =
             IconInfo(
                 contentDescription,
                 MediaTttIcon.Resource(drawableRes),
-                tintAttr,
+                tint,
                 isAppIcon = false
             )
 
         val tinted = iconInfo.toTintedIcon()
 
         assertThat(tinted.icon).isEqualTo(Icon.Resource(drawableRes, contentDescription))
-        assertThat(tinted.tintAttr).isEqualTo(tintAttr)
+        assertThat(tinted.tint).isEqualTo(tint)
     }
 }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt
index db890f6..ca2b1da 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt
@@ -107,6 +107,7 @@
     private lateinit var fakeExecutor: FakeExecutor
     private lateinit var uiEventLoggerFake: UiEventLoggerFake
     private lateinit var uiEventLogger: MediaTttSenderUiEventLogger
+    private val defaultTimeout = context.resources.getInteger(R.integer.heads_up_notification_decay)
 
     @Before
     fun setUp() {
@@ -1356,6 +1357,92 @@
         assertThat(chipbarView.getLoadingIcon().visibility).isEqualTo(View.VISIBLE)
     }
 
+    @Test
+    fun almostClose_hasLongTimeout_eventuallyTimesOut() {
+        whenever(accessibilityManager.getRecommendedTimeoutMillis(any(), any())).thenAnswer {
+            it.arguments[0]
+        }
+
+        commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+            StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST,
+            routeInfo,
+            null,
+        )
+
+        // WHEN the default timeout has passed
+        fakeClock.advanceTime(defaultTimeout + 1L)
+
+        // THEN the view is still on-screen because it has a long timeout
+        verify(windowManager, never()).removeView(any())
+
+        // WHEN a very long amount of time has passed
+        fakeClock.advanceTime(5L * defaultTimeout)
+
+        // THEN the view does time out
+        verify(windowManager).removeView(any())
+    }
+
+    @Test
+    fun loading_hasLongTimeout_eventuallyTimesOut() {
+        whenever(accessibilityManager.getRecommendedTimeoutMillis(any(), any())).thenAnswer {
+            it.arguments[0]
+        }
+
+        commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+            StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED,
+            routeInfo,
+            null,
+        )
+
+        // WHEN the default timeout has passed
+        fakeClock.advanceTime(defaultTimeout + 1L)
+
+        // THEN the view is still on-screen because it has a long timeout
+        verify(windowManager, never()).removeView(any())
+
+        // WHEN a very long amount of time has passed
+        fakeClock.advanceTime(5L * defaultTimeout)
+
+        // THEN the view does time out
+        verify(windowManager).removeView(any())
+    }
+
+    @Test
+    fun succeeded_hasDefaultTimeout() {
+        whenever(accessibilityManager.getRecommendedTimeoutMillis(any(), any())).thenAnswer {
+            it.arguments[0]
+        }
+
+        displayReceiverTriggered()
+        commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+            StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED,
+            routeInfo,
+            null,
+        )
+
+        fakeClock.advanceTime(defaultTimeout + 1L)
+
+        verify(windowManager).removeView(any())
+    }
+
+    @Test
+    fun failed_hasDefaultTimeout() {
+        whenever(accessibilityManager.getRecommendedTimeoutMillis(any(), any())).thenAnswer {
+            it.arguments[0]
+        }
+
+        displayThisDeviceTriggered()
+        commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+            StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_FAILED,
+            routeInfo,
+            null,
+        )
+
+        fakeClock.advanceTime(defaultTimeout + 1L)
+
+        verify(windowManager).removeView(any())
+    }
+
     private fun getChipbarView(): ViewGroup {
         val viewCaptor = ArgumentCaptor.forClass(View::class.java)
         verify(windowManager).addView(viewCaptor.capture(), any())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProviderTest.kt
index 464acb6..01ffdcd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProviderTest.kt
@@ -19,12 +19,14 @@
 import android.content.Context
 import android.content.res.Configuration
 import android.content.res.Resources
+import android.graphics.Insets
 import android.graphics.Rect
 import android.util.DisplayMetrics.DENSITY_DEFAULT
+import android.view.WindowInsets
 import android.view.WindowManager
 import android.view.WindowMetrics
+import androidx.core.view.WindowInsetsCompat.Type
 import androidx.test.filters.SmallTest
-import com.android.internal.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.mediaprojection.appselector.view.TaskPreviewSizeProvider.TaskPreviewSizeListener
 import com.android.systemui.statusbar.policy.FakeConfigurationController
@@ -94,7 +96,13 @@
     }
 
     private fun givenTaskbarSize(size: Int) {
-        whenever(resources.getDimensionPixelSize(eq(R.dimen.taskbar_frame_height))).thenReturn(size)
+        val windowInsets =
+            WindowInsets.Builder()
+                .setInsets(Type.tappableElement(), Insets.of(Rect(0, 0, 0, size)))
+                .build()
+        val windowMetrics = WindowMetrics(windowManager.maximumWindowMetrics.bounds, windowInsets)
+        whenever(windowManager.maximumWindowMetrics).thenReturn(windowMetrics)
+        whenever(windowManager.currentWindowMetrics).thenReturn(windowMetrics)
     }
 
     private fun givenDisplay(width: Int, height: Int, isTablet: Boolean = false) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java
index ce6a98c..9b8605d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java
@@ -35,6 +35,7 @@
 import static org.mockito.Mockito.when;
 
 import android.content.ComponentName;
+import android.view.IWindowManager;
 import android.view.accessibility.AccessibilityManager;
 
 import androidx.test.filters.SmallTest;
@@ -46,7 +47,9 @@
 import com.android.systemui.accessibility.SystemActions;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler;
 import com.android.systemui.recents.OverviewProxyService;
+import com.android.systemui.settings.DisplayTracker;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
@@ -101,6 +104,14 @@
     NavBarHelper.NavbarTaskbarStateUpdater mNavbarTaskbarStateUpdater;
     @Mock
     CommandQueue mCommandQueue;
+    @Mock
+    IWindowManager mWm;
+    @Mock
+    DisplayTracker mDisplayTracker;
+    @Mock
+    EdgeBackGestureHandler mEdgeBackGestureHandler;
+    @Mock
+    EdgeBackGestureHandler.Factory mEdgeBackGestureHandlerFactory;
     private AccessibilityManager.AccessibilityServicesStateChangeListener
             mAccessibilityServicesStateChangeListener;
 
@@ -114,6 +125,8 @@
         when(mAssistManagerLazy.get()).thenReturn(mAssistManager);
         when(mAssistManager.getAssistInfoForUser(anyInt())).thenReturn(mAssistantComponent);
         when(mUserTracker.getUserId()).thenReturn(1);
+        when(mDisplayTracker.getDefaultDisplayId()).thenReturn(0);
+        when(mEdgeBackGestureHandlerFactory.create(any())).thenReturn(mEdgeBackGestureHandler);
 
         doAnswer((invocation) -> mAccessibilityServicesStateChangeListener =
                 invocation.getArgument(0)).when(
@@ -122,36 +135,70 @@
                 mAccessibilityButtonModeObserver, mAccessibilityButtonTargetObserver,
                 mSystemActions, mOverviewProxyService, mAssistManagerLazy,
                 () -> Optional.of(mock(CentralSurfaces.class)), mock(KeyguardStateController.class),
-                mNavigationModeController, mUserTracker, mDumpManager, mCommandQueue);
+                mNavigationModeController, mEdgeBackGestureHandlerFactory, mWm, mUserTracker,
+                mDisplayTracker, mDumpManager, mCommandQueue);
 
     }
 
     @Test
     public void registerListenersInCtor() {
-        verify(mAccessibilityButtonModeObserver, times(1)).addListener(mNavBarHelper);
         verify(mNavigationModeController, times(1)).addListener(mNavBarHelper);
         verify(mOverviewProxyService, times(1)).addCallback(mNavBarHelper);
+        verify(mCommandQueue, times(1)).addCallback(any());
     }
 
     @Test
-    public void registerAssistantContentObserver() {
-        mNavBarHelper.init();
+    public void testSetupBarsRegistersListeners() throws Exception {
+        mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
+        verify(mAccessibilityButtonModeObserver, times(1)).addListener(mNavBarHelper);
+        verify(mAccessibilityButtonTargetObserver, times(1)).addListener(mNavBarHelper);
+        verify(mAccessibilityManager, times(1)).addAccessibilityServicesStateChangeListener(
+                mNavBarHelper);
         verify(mAssistManager, times(1)).getAssistInfoForUser(anyInt());
+        verify(mWm, times(1)).watchRotation(any(), anyInt());
+        verify(mWm, times(1)).registerWallpaperVisibilityListener(any(), anyInt());
+        verify(mEdgeBackGestureHandler, times(1)).onNavBarAttached();
+    }
+
+    @Test
+    public void testCleanupBarsUnregistersListeners() throws Exception {
+        mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
+        mNavBarHelper.removeNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
+        verify(mAccessibilityButtonModeObserver, times(1)).removeListener(mNavBarHelper);
+        verify(mAccessibilityButtonTargetObserver, times(1)).removeListener(mNavBarHelper);
+        verify(mAccessibilityManager, times(1)).removeAccessibilityServicesStateChangeListener(
+                mNavBarHelper);
+        verify(mWm, times(1)).removeRotationWatcher(any());
+        verify(mWm, times(1)).unregisterWallpaperVisibilityListener(any(), anyInt());
+        verify(mEdgeBackGestureHandler, times(1)).onNavBarDetached();
+    }
+
+    @Test
+    public void replacingBarsHint() {
+        mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
+        mNavBarHelper.setTogglingNavbarTaskbar(true);
+        mNavBarHelper.removeNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
+        mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
+        mNavBarHelper.setTogglingNavbarTaskbar(false);
+        // Use any state in cleanup to verify it was not called
+        verify(mAccessibilityButtonModeObserver, times(0)).removeListener(mNavBarHelper);
     }
 
     @Test
     public void callbacksFiredWhenRegistering() {
-        mNavBarHelper.init();
         mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
         verify(mNavbarTaskbarStateUpdater, times(1))
                 .updateAccessibilityServicesState();
         verify(mNavbarTaskbarStateUpdater, times(1))
                 .updateAssistantAvailable(anyBoolean(), anyBoolean());
+        verify(mNavbarTaskbarStateUpdater, times(1))
+                .updateRotationWatcherState(anyInt());
+        verify(mNavbarTaskbarStateUpdater, times(1))
+                .updateWallpaperVisibility(anyBoolean(), anyInt());
     }
 
     @Test
     public void assistantCallbacksFiredAfterConnecting() {
-        mNavBarHelper.init();
         // 1st set of callbacks get called when registering
         mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
 
@@ -172,7 +219,6 @@
 
     @Test
     public void a11yCallbacksFiredAfterModeChange() {
-        mNavBarHelper.init();
         // 1st set of callbacks get called when registering
         mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
 
@@ -185,7 +231,6 @@
 
     @Test
     public void assistantCallbacksFiredAfterNavModeChange() {
-        mNavBarHelper.init();
         // 1st set of callbacks get called when registering
         mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
 
@@ -198,7 +243,6 @@
 
     @Test
     public void removeListenerNoCallbacksFired() {
-        mNavBarHelper.init();
         // 1st set of callbacks get called when registering
         mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
 
@@ -220,7 +264,7 @@
         when(mAccessibilityManager.getAccessibilityShortcutTargets(
                 AccessibilityManager.ACCESSIBILITY_BUTTON)).thenReturn(createFakeShortcutTargets());
 
-        mNavBarHelper.init();
+        mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
 
         assertThat(mNavBarHelper.getA11yButtonState()).isEqualTo(
                 ACCESSIBILITY_BUTTON_CLICKABLE_STATE);
@@ -230,13 +274,15 @@
     public void initAccessibilityStateWithFloatingMenuModeAndTargets_disableClickableState() {
         when(mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode()).thenReturn(
                 ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU);
-        mNavBarHelper.init();
+
+        mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
 
         assertThat(mNavBarHelper.getA11yButtonState()).isEqualTo(/* disable_clickable_state */ 0);
     }
 
     @Test
     public void onA11yServicesStateChangedWithMultipleServices_a11yButtonClickableState() {
+        mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
         when(mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode()).thenReturn(
                 ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR);
 
@@ -250,14 +296,7 @@
     }
 
     @Test
-    public void registerCommandQueueCallbacks() {
-        mNavBarHelper.init();
-        verify(mCommandQueue, times(1)).addCallback(any());
-    }
-
-    @Test
     public void saveMostRecentSysuiState() {
-        mNavBarHelper.init();
         mNavBarHelper.setWindowState(DISPLAY_ID, WINDOW, STATE_ID);
         NavBarHelper.CurrentSysuiState state1 = mNavBarHelper.getCurrentSysuiState();
 
@@ -274,7 +313,6 @@
 
     @Test
     public void ignoreNonNavbarSysuiState() {
-        mNavBarHelper.init();
         mNavBarHelper.setWindowState(DISPLAY_ID, WINDOW, STATE_ID);
         NavBarHelper.CurrentSysuiState state1 = mNavBarHelper.getCurrentSysuiState();
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
index 764ddc4..f062ec7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
@@ -58,6 +58,7 @@
 import android.testing.TestableLooper.RunWithLooper;
 import android.view.Display;
 import android.view.DisplayInfo;
+import android.view.IWindowManager;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewRootImpl;
@@ -87,6 +88,7 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.recents.Recents;
+import com.android.systemui.settings.DisplayTracker;
 import com.android.systemui.settings.FakeDisplayTracker;
 import com.android.systemui.settings.UserContextProvider;
 import com.android.systemui.settings.UserTracker;
@@ -172,8 +174,6 @@
     private UiEventLogger mUiEventLogger;
     @Mock
     private ViewTreeObserver mViewTreeObserver;
-    @Mock
-    EdgeBackGestureHandler mEdgeBackGestureHandler;
     NavBarHelper mNavBarHelper;
     @Mock
     private LightBarController mLightBarController;
@@ -205,6 +205,10 @@
     private Resources mResources;
     @Mock
     private ViewRootImpl mViewRootImpl;
+    @Mock
+    private EdgeBackGestureHandler.Factory mEdgeBackGestureHandlerFactory;
+    @Mock
+    private EdgeBackGestureHandler mEdgeBackGestureHandler;
     private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
     private DeviceConfigProxyFake mDeviceConfigProxyFake = new DeviceConfigProxyFake();
     private TaskStackChangeListeners mTaskStackChangeListeners =
@@ -234,6 +238,7 @@
                 .thenReturn(mContext);
         when(mNavigationBarView.getResources()).thenReturn(mResources);
         when(mNavigationBarView.getViewRootImpl()).thenReturn(mViewRootImpl);
+        when(mEdgeBackGestureHandlerFactory.create(any())).thenReturn(mEdgeBackGestureHandler);
         setupSysuiDependency();
         // This class inflates views that call Dependency.get, thus these injections are still
         // necessary.
@@ -250,7 +255,9 @@
                     mSystemActions, mOverviewProxyService,
                     () -> mock(AssistManager.class), () -> Optional.of(mCentralSurfaces),
                     mKeyguardStateController, mock(NavigationModeController.class),
-                    mock(UserTracker.class), mock(DumpManager.class), mock(CommandQueue.class)));
+                    mEdgeBackGestureHandlerFactory, mock(IWindowManager.class),
+                    mock(UserTracker.class), mock(DisplayTracker.class), mock(DumpManager.class),
+                    mock(CommandQueue.class)));
             mNavigationBar = createNavBar(mContext);
             mExternalDisplayNavigationBar = createNavBar(mSysuiTestableContextExternal);
         });
@@ -492,7 +499,6 @@
                 mDeadZone,
                 mDeviceConfigProxyFake,
                 mNavigationBarTransitions,
-                mEdgeBackGestureHandler,
                 Optional.of(mock(BackAnimation.class)),
                 mUserContextProvider,
                 mWakefulnessLifecycle,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTransitionsTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTransitionsTest.java
index 5270737..54aec30 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTransitionsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTransitionsTest.java
@@ -27,7 +27,6 @@
 import android.content.Context;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
-import android.view.IWindowManager;
 
 import androidx.test.filters.SmallTest;
 
@@ -60,8 +59,6 @@
     EdgeBackGestureHandler.Factory mEdgeBackGestureHandlerFactory;
     @Mock
     EdgeBackGestureHandler mEdgeBackGestureHandler;
-    @Mock
-    IWindowManager mIWindowManager;
 
     private NavigationBarTransitions mTransitions;
     private final FakeDisplayTracker mDisplayTracker = new FakeDisplayTracker(mContext);
@@ -88,7 +85,7 @@
         when(navBar.getCurrentView()).thenReturn(navBar);
         when(navBar.findViewById(anyInt())).thenReturn(navBar);
         mTransitions = new NavigationBarTransitions(
-                navBar, mIWindowManager, mLightBarTransitionsFactory, mDisplayTracker);
+                navBar, mLightBarTransitionsFactory, mDisplayTracker);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/TaskbarDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/TaskbarDelegateTest.kt
index 1c9336a..8d01e80d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/TaskbarDelegateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/TaskbarDelegateTest.kt
@@ -38,8 +38,6 @@
     private lateinit var mTaskStackChangeListeners: TaskStackChangeListeners
     private lateinit var mTaskbarDelegate: TaskbarDelegate
     @Mock
-    lateinit var mEdgeBackGestureHandlerFactory : EdgeBackGestureHandler.Factory
-    @Mock
     lateinit var mEdgeBackGestureHandler : EdgeBackGestureHandler
     @Mock
     lateinit var mLightBarControllerFactory : LightBarTransitionsController.Factory
@@ -73,13 +71,13 @@
     @Before
     fun setup() {
         MockitoAnnotations.initMocks(this)
-        `when`(mEdgeBackGestureHandlerFactory.create(context)).thenReturn(mEdgeBackGestureHandler)
+        `when`(mNavBarHelper.edgeBackGestureHandler).thenReturn(mEdgeBackGestureHandler)
         `when`(mLightBarControllerFactory.create(any())).thenReturn(mLightBarTransitionController)
         `when`(mNavBarHelper.currentSysuiState).thenReturn(mCurrentSysUiState)
         `when`(mSysUiState.setFlag(anyInt(), anyBoolean())).thenReturn(mSysUiState)
         mTaskStackChangeListeners = TaskStackChangeListeners.getTestInstance()
-        mTaskbarDelegate = TaskbarDelegate(context, mEdgeBackGestureHandlerFactory,
-                mLightBarControllerFactory, mStatusBarKeyguardViewManager)
+        mTaskbarDelegate = TaskbarDelegate(context, mLightBarControllerFactory,
+            mStatusBarKeyguardViewManager)
         mTaskbarDelegate.setDependencies(mCommandQueue, mOverviewProxyService, mNavBarHelper,
         mNavigationModeController, mSysUiState, mDumpManager, mAutoHideController,
                 mLightBarController, mOptionalPip, mBackAnimation, mTaskStackChangeListeners)
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 89606bf..0ab0e2b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -52,6 +52,8 @@
 import com.android.systemui.SysuiBaseFragmentTest;
 import com.android.systemui.animation.ShadeInterpolation;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.media.controls.ui.MediaHost;
 import com.android.systemui.qs.customize.QSCustomizerController;
 import com.android.systemui.qs.dagger.QSFragmentComponent;
@@ -60,6 +62,7 @@
 import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel;
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.settings.FakeDisplayTracker;
+import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
@@ -103,6 +106,8 @@
     @Mock private QSSquishinessController mSquishinessController;
     @Mock private FooterActionsViewModel mFooterActionsViewModel;
     @Mock private FooterActionsViewModel.Factory mFooterActionsViewModelFactory;
+    @Mock private LargeScreenShadeInterpolator mLargeScreenShadeInterpolator;
+    @Mock private FeatureFlags mFeatureFlags;
     private View mQsFragmentView;
 
     public QSFragmentTest() {
@@ -148,8 +153,9 @@
     }
 
     @Test
-    public void transitionToFullShade_setsAlphaUsingShadeInterpolator() {
+    public void transitionToFullShade_smallScreen_alphaAlways1() {
         QSFragment fragment = resumeAndGetFragment();
+        setIsSmallScreen();
         setStatusBarCurrentAndUpcomingState(StatusBarState.SHADE);
         boolean isTransitioningToFullShade = true;
         float transitionProgress = 0.5f;
@@ -158,6 +164,43 @@
         fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress,
                 squishinessFraction);
 
+        assertThat(mQsFragmentView.getAlpha()).isEqualTo(1f);
+    }
+
+    @Test
+    public void transitionToFullShade_largeScreen_flagEnabled_alphaLargeScreenShadeInterpolator() {
+        when(mFeatureFlags.isEnabled(Flags.LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION))
+                .thenReturn(true);
+        QSFragment fragment = resumeAndGetFragment();
+        setIsLargeScreen();
+        setStatusBarCurrentAndUpcomingState(StatusBarState.SHADE);
+        boolean isTransitioningToFullShade = true;
+        float transitionProgress = 0.5f;
+        float squishinessFraction = 0.5f;
+        when(mLargeScreenShadeInterpolator.getQsAlpha(transitionProgress)).thenReturn(123f);
+
+        fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress,
+                squishinessFraction);
+
+        assertThat(mQsFragmentView.getAlpha())
+                .isEqualTo(123f);
+    }
+
+    @Test
+    public void transitionToFullShade_largeScreen_flagDisabled_alphaStandardInterpolator() {
+        when(mFeatureFlags.isEnabled(Flags.LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION))
+                .thenReturn(false);
+        QSFragment fragment = resumeAndGetFragment();
+        setIsLargeScreen();
+        setStatusBarCurrentAndUpcomingState(StatusBarState.SHADE);
+        boolean isTransitioningToFullShade = true;
+        float transitionProgress = 0.5f;
+        float squishinessFraction = 0.5f;
+        when(mLargeScreenShadeInterpolator.getQsAlpha(transitionProgress)).thenReturn(123f);
+
+        fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress,
+                squishinessFraction);
+
         assertThat(mQsFragmentView.getAlpha())
                 .isEqualTo(ShadeInterpolation.getContentAlpha(transitionProgress));
     }
@@ -514,7 +557,9 @@
                 mock(DumpManager.class),
                 mock(QSLogger.class),
                 mock(FooterActionsController.class),
-                mFooterActionsViewModelFactory);
+                mFooterActionsViewModelFactory,
+                mLargeScreenShadeInterpolator,
+                mFeatureFlags);
     }
 
     private void setUpOther() {
@@ -622,4 +667,12 @@
             return null;
         }).when(view).getLocationOnScreen(any(int[].class));
     }
+
+    private void setIsLargeScreen() {
+        getFragment().setIsNotificationPanelFullWidth(false);
+    }
+
+    private void setIsSmallScreen() {
+        getFragment().setIsNotificationPanelFullWidth(true);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
index 8644b5e..5be95d6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
@@ -57,6 +57,7 @@
 import org.mockito.ArgumentMatchers.anyString
 import org.mockito.Mock
 import org.mockito.Mockito.`when`
+import org.mockito.Mockito.clearInvocations
 import org.mockito.Mockito.mock
 import org.mockito.Mockito.never
 import org.mockito.Mockito.reset
@@ -351,4 +352,44 @@
             .startPendingIntentDismissingKeyguard(
                 eq(pi), nullable(), nullable<ActivityLaunchAnimator.Controller>())
     }
+
+    @Test
+    fun testActiveTileListensOnceAfterCreated() {
+        `when`(tileServiceManager.isActiveTile).thenReturn(true)
+
+        val tile = CustomTile.create(customTileBuilder, TILE_SPEC, mContext)
+        tile.initialize()
+        tile.postStale()
+        testableLooper.processAllMessages()
+
+        verify(tileServiceManager).setBindRequested(true)
+        verify(tileService).onStartListening()
+    }
+
+    @Test
+    fun testActiveTileDoesntListenAfterFirstTime() {
+        `when`(tileServiceManager.isActiveTile).thenReturn(true)
+
+        val tile = CustomTile.create(customTileBuilder, TILE_SPEC, mContext)
+        tile.initialize()
+        // Make sure we have an icon in the tile because we don't have a default icon
+        // This should not be overridden by the retrieved tile that has null icon.
+        tile.qsTile.icon = mock(Icon::class.java)
+        `when`(tile.qsTile.icon.loadDrawable(any(Context::class.java)))
+                .thenReturn(mock(Drawable::class.java))
+
+        tile.postStale()
+        testableLooper.processAllMessages()
+
+        // postStale will set it to not listening after it's done
+        verify(tileService).onStopListening()
+
+        clearInvocations(tileServiceManager, tileService)
+
+        tile.setListening(Any(), true)
+        testableLooper.processAllMessages()
+
+        verify(tileServiceManager, never()).setBindRequested(true)
+        verify(tileService, never()).onStartListening()
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
new file mode 100644
index 0000000..eb7b481
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents
+
+import android.content.ComponentName
+import android.content.pm.PackageManager
+import android.content.pm.ResolveInfo
+import android.testing.AndroidTestingRunner
+import android.testing.TestableContext
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.internal.app.AssistUtils
+import com.android.internal.logging.UiEventLogger
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.keyguard.KeyguardUnlockAnimationController
+import com.android.systemui.keyguard.ScreenLifecycle
+import com.android.systemui.model.SysUiState
+import com.android.systemui.navigationbar.NavigationBarController
+import com.android.systemui.navigationbar.NavigationModeController
+import com.android.systemui.recents.OverviewProxyService.ACTION_QUICKSTEP
+import com.android.systemui.settings.FakeDisplayTracker
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.shared.recents.IOverviewProxy
+import com.android.systemui.shared.system.QuickStepContract.SCREEN_STATE_OFF
+import com.android.systemui.shared.system.QuickStepContract.SCREEN_STATE_ON
+import com.android.systemui.shared.system.QuickStepContract.SCREEN_STATE_TURNING_OFF
+import com.android.systemui.shared.system.QuickStepContract.SCREEN_STATE_TURNING_ON
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_STATE_MASK
+import com.android.systemui.statusbar.CommandQueue
+import com.android.systemui.statusbar.NotificationShadeWindowController
+import com.android.systemui.statusbar.phone.CentralSurfaces
+import com.android.systemui.unfold.progress.UnfoldTransitionProgressForwarder
+import com.android.systemui.util.mockito.whenever
+import com.android.wm.shell.sysui.ShellInterface
+import com.google.common.util.concurrent.MoreExecutors
+import dagger.Lazy
+import java.util.Optional
+import java.util.concurrent.Executor
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers
+import org.mockito.Mock
+import org.mockito.Mockito.any
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.intThat
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class OverviewProxyServiceTest : SysuiTestCase() {
+
+    @Main private val executor: Executor = MoreExecutors.directExecutor()
+
+    private lateinit var subject: OverviewProxyService
+    private val dumpManager = DumpManager()
+    private val displayTracker = FakeDisplayTracker(mContext)
+    private val sysUiState = SysUiState(displayTracker)
+    private val screenLifecycle = ScreenLifecycle(dumpManager)
+
+    @Mock private lateinit var overviewProxy: IOverviewProxy.Stub
+    @Mock private lateinit var packageManager: PackageManager
+
+    // The following mocks belong to not-yet-tested parts of OverviewProxyService.
+    @Mock private lateinit var commandQueue: CommandQueue
+    @Mock private lateinit var shellInterface: ShellInterface
+    @Mock private lateinit var navBarController: NavigationBarController
+    @Mock private lateinit var centralSurfaces: CentralSurfaces
+    @Mock private lateinit var navModeController: NavigationModeController
+    @Mock private lateinit var statusBarWinController: NotificationShadeWindowController
+    @Mock private lateinit var userTracker: UserTracker
+    @Mock private lateinit var uiEventLogger: UiEventLogger
+    @Mock private lateinit var sysuiUnlockAnimationController: KeyguardUnlockAnimationController
+    @Mock private lateinit var assistUtils: AssistUtils
+    @Mock
+    private lateinit var unfoldTransitionProgressForwarder:
+        Optional<UnfoldTransitionProgressForwarder>
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        val serviceComponent = ComponentName("test_package", "service_provider")
+        context.addMockService(serviceComponent, overviewProxy)
+        context.addMockServiceResolver(
+            TestableContext.MockServiceResolver {
+                if (it.action == ACTION_QUICKSTEP) serviceComponent else null
+            }
+        )
+        whenever(overviewProxy.queryLocalInterface(ArgumentMatchers.anyString()))
+            .thenReturn(overviewProxy)
+        whenever(overviewProxy.asBinder()).thenReturn(overviewProxy)
+
+        // packageManager.resolveServiceAsUser has to return non-null for
+        // OverviewProxyService#isEnabled to become true.
+        context.setMockPackageManager(packageManager)
+        whenever(packageManager.resolveServiceAsUser(any(), anyInt(), anyInt()))
+            .thenReturn(mock(ResolveInfo::class.java))
+
+        subject =
+            OverviewProxyService(
+                context,
+                executor,
+                commandQueue,
+                shellInterface,
+                Lazy { navBarController },
+                Lazy { Optional.of(centralSurfaces) },
+                navModeController,
+                statusBarWinController,
+                sysUiState,
+                userTracker,
+                screenLifecycle,
+                uiEventLogger,
+                displayTracker,
+                sysuiUnlockAnimationController,
+                assistUtils,
+                dumpManager,
+                unfoldTransitionProgressForwarder
+            )
+    }
+
+    @After
+    fun tearDown() {
+        subject.shutdownForTest()
+    }
+
+    @Test
+    fun `ScreenLifecycle - screenTurnedOn triggers SysUI state flag changes `() {
+        screenLifecycle.dispatchScreenTurnedOn()
+
+        verify(overviewProxy)
+            .onSystemUiStateChanged(
+                intThat { it and SYSUI_STATE_SCREEN_STATE_MASK == SCREEN_STATE_ON }
+            )
+    }
+
+    @Test
+    fun `ScreenLifecycle - screenTurningOn triggers SysUI state flag changes `() {
+        screenLifecycle.dispatchScreenTurningOn()
+
+        verify(overviewProxy)
+            .onSystemUiStateChanged(
+                intThat { it and SYSUI_STATE_SCREEN_STATE_MASK == SCREEN_STATE_TURNING_ON }
+            )
+    }
+
+    @Test
+    fun `ScreenLifecycle - screenTurnedOff triggers SysUI state flag changes `() {
+        screenLifecycle.dispatchScreenTurnedOff()
+
+        verify(overviewProxy)
+            .onSystemUiStateChanged(
+                intThat { it and SYSUI_STATE_SCREEN_STATE_MASK == SCREEN_STATE_OFF }
+            )
+    }
+
+    @Test
+    fun `ScreenLifecycle - screenTurningOff triggers SysUI state flag changes `() {
+        screenLifecycle.dispatchScreenTurningOff()
+
+        verify(overviewProxy)
+            .onSystemUiStateChanged(
+                intThat { it and SYSUI_STATE_SCREEN_STATE_MASK == SCREEN_STATE_TURNING_OFF }
+            )
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index 52b0b6a..7087c01 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -22,11 +22,11 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
-
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.doAnswer;
@@ -35,6 +35,8 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
+
 import android.annotation.IdRes;
 import android.content.ContentResolver;
 import android.content.res.Configuration;
@@ -184,6 +186,7 @@
     @Mock protected NotificationStackScrollLayout mNotificationStackScrollLayout;
     @Mock protected KeyguardBottomAreaView mKeyguardBottomArea;
     @Mock protected KeyguardBottomAreaViewController mKeyguardBottomAreaViewController;
+    @Mock protected ViewPropertyAnimator mViewPropertyAnimator;
     @Mock protected KeyguardBottomAreaView mQsFrame;
     @Mock protected HeadsUpManagerPhone mHeadsUpManager;
     @Mock protected NotificationShelfController mNotificationShelfController;
@@ -357,7 +360,14 @@
                 .thenReturn(mHeadsUpCallback);
         when(mKeyguardBottomAreaViewController.getView()).thenReturn(mKeyguardBottomArea);
         when(mView.findViewById(R.id.keyguard_bottom_area)).thenReturn(mKeyguardBottomArea);
-        when(mKeyguardBottomArea.animate()).thenReturn(mock(ViewPropertyAnimator.class));
+        when(mKeyguardBottomArea.animate()).thenReturn(mViewPropertyAnimator);
+        when(mView.animate()).thenReturn(mViewPropertyAnimator);
+        when(mViewPropertyAnimator.translationX(anyFloat())).thenReturn(mViewPropertyAnimator);
+        when(mViewPropertyAnimator.alpha(anyFloat())).thenReturn(mViewPropertyAnimator);
+        when(mViewPropertyAnimator.setDuration(anyLong())).thenReturn(mViewPropertyAnimator);
+        when(mViewPropertyAnimator.setInterpolator(any())).thenReturn(mViewPropertyAnimator);
+        when(mViewPropertyAnimator.setListener(any())).thenReturn(mViewPropertyAnimator);
+        when(mViewPropertyAnimator.setUpdateListener(any())).thenReturn(mViewPropertyAnimator);
         when(mView.findViewById(R.id.qs_frame)).thenReturn(mQsFrame);
         when(mView.findViewById(R.id.keyguard_status_view))
                 .thenReturn(mock(KeyguardStatusView.class));
@@ -536,12 +546,10 @@
                 mQsController,
                 mFragmentService,
                 mContentResolver,
-                mRecordingController,
                 mShadeHeaderController,
                 mScreenOffAnimationController,
                 mLockscreenGestureLogger,
                 mShadeExpansionStateManager,
-                mNotificationRemoteInputManager,
                 mSysUIUnfoldComponent,
                 mSysUiState,
                 () -> mKeyguardBottomAreaViewController,
@@ -551,6 +559,7 @@
                 mNotificationStackSizeCalculator,
                 mUnlockedScreenOffAnimationController,
                 mShadeTransitionController,
+                mInteractionJankMonitor,
                 systemClock,
                 mKeyguardBottomAreaViewModel,
                 mKeyguardBottomAreaInteractor,
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 abcde3d..b868018 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -37,10 +37,13 @@
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.animation.Animator;
+import android.animation.ValueAnimator;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.view.MotionEvent;
@@ -673,6 +676,24 @@
     }
 
     @Test
+    public void testFoldToAodAnimationCleansupInAnimationEnd() {
+        ArgumentCaptor<Animator.AnimatorListener> animCaptor =
+                ArgumentCaptor.forClass(Animator.AnimatorListener.class);
+        ArgumentCaptor<ValueAnimator.AnimatorUpdateListener> updateCaptor =
+                ArgumentCaptor.forClass(ValueAnimator.AnimatorUpdateListener.class);
+
+        // Start fold animation & Capture Listeners
+        mNotificationPanelViewController.startFoldToAodAnimation(() -> {}, () -> {}, () -> {});
+        verify(mViewPropertyAnimator).setListener(animCaptor.capture());
+        verify(mViewPropertyAnimator).setUpdateListener(updateCaptor.capture());
+
+        // End animation and validate listeners were unset
+        animCaptor.getValue().onAnimationEnd(null);
+        verify(mViewPropertyAnimator).setListener(null);
+        verify(mViewPropertyAnimator).setUpdateListener(null);
+    }
+
+    @Test
     public void testExpandWithQsMethodIsUsingLockscreenTransitionController() {
         enableSplitShade(/* enabled= */ true);
         mStatusBarStateController.setState(KEYGUARD);
@@ -921,6 +942,38 @@
 
     }
 
+    @Test
+    public void onSplitShadeChanged_duringShadeExpansion_resetsOverScrollState() {
+        // There was a bug where there was left-over overscroll state after going from split shade
+        // to single shade.
+        // Since on single shade we don't set overscroll values on QS nor Scrim, those values that
+        // were there from split shade were never reset.
+        // To prevent this, we will reset all overscroll state.
+        enableSplitShade(true);
+        reset(mQsController, mScrimController, mNotificationStackScrollLayoutController);
+
+        mNotificationPanelViewController.setOverExpansion(123);
+        verify(mQsController).setOverScrollAmount(123);
+        verify(mScrimController).setNotificationsOverScrollAmount(123);
+        verify(mNotificationStackScrollLayoutController).setOverExpansion(123);
+
+        enableSplitShade(false);
+        verify(mQsController).setOverScrollAmount(0);
+        verify(mScrimController).setNotificationsOverScrollAmount(0);
+        verify(mNotificationStackScrollLayoutController).setOverExpansion(0);
+    }
+
+    @Test
+    public void onSplitShadeChanged_alwaysResetsOverScrollState() {
+        enableSplitShade(true);
+        enableSplitShade(false);
+
+        verify(mQsController, times(2)).setOverScrollAmount(0);
+        verify(mScrimController, times(2)).setNotificationsOverScrollAmount(0);
+        verify(mNotificationStackScrollLayoutController, times(2)).setOverExpansion(0);
+        verify(mNotificationStackScrollLayoutController, times(2)).setOverScrollAmount(0);
+    }
+
     /**
      * When shade is flinging to close and this fling is not intercepted,
      * {@link AmbientState#setIsClosing(boolean)} should be called before
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
index 82a5743..315663c3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -276,6 +276,20 @@
         underTest.keyguardMessageArea
         verify(view).findViewById<ViewGroup>(R.id.keyguard_message_area)
     }
+
+    @Test
+    fun handleDispatchTouchEvent_statusBarViewControllerOnTouch_returnsTrue() {
+        underTest.setStatusBarViewController(phoneStatusBarViewController)
+
+        // GIVEN the statusBarKeyguardViewManager will handle any touches
+        whenever(statusBarKeyguardViewManager.onTouch(any())).thenReturn(true)
+
+        // WHEN a touch is dispatched
+        val returnVal = interactionEventHandler.handleDispatchTouchEvent(downEv)
+
+        // THEN handleDispatchTouchEvent returns true
+        assertThat(returnVal).isTrue()
+    }
 }
 
 private val downEv = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerTest.java
index e3a3678..d8ffe39 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerTest.java
@@ -32,6 +32,7 @@
 import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
@@ -77,7 +78,6 @@
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.stack.AmbientState;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.phone.KeyguardBottomAreaView;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
@@ -91,9 +91,12 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.List;
+
 import dagger.Lazy;
 
 @SmallTest
@@ -101,12 +104,14 @@
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
 public class QuickSettingsControllerTest extends SysuiTestCase {
 
-    private static final int SPLIT_SHADE_FULL_TRANSITION_DISTANCE = 400;
     private static final float QS_FRAME_START_X = 0f;
     private static final int QS_FRAME_WIDTH = 1000;
     private static final int QS_FRAME_TOP = 0;
     private static final int QS_FRAME_BOTTOM = 1000;
-
+    private static final int DEFAULT_HEIGHT = 1000;
+    // In split shade min = max
+    private static final int DEFAULT_MIN_HEIGHT_SPLIT_SHADE = DEFAULT_HEIGHT;
+    private static final int DEFAULT_MIN_HEIGHT = 300;
 
     private QuickSettingsController mQsController;
 
@@ -115,7 +120,6 @@
     @Mock private KeyguardStatusBarView mKeyguardStatusBar;
     @Mock private QS mQs;
     @Mock private QSFragment mQSFragment;
-
     @Mock private Lazy<NotificationPanelViewController> mPanelViewControllerLazy;
     @Mock private NotificationPanelViewController mNotificationPanelViewController;
     @Mock private NotificationPanelView mPanelView;
@@ -147,10 +151,7 @@
     @Mock private FeatureFlags mFeatureFlags;
     @Mock private InteractionJankMonitor mInteractionJankMonitor;
     @Mock private ShadeLogger mShadeLogger;
-
     @Mock private DumpManager mDumpManager;
-
-    @Mock private HeadsUpManagerPhone mHeadsUpManager;
     @Mock private UiEventLogger mUiEventLogger;
 
     private SysuiStatusBarStateController mStatusBarStateController;
@@ -173,6 +174,8 @@
         KeyguardStatusView keyguardStatusView = new KeyguardStatusView(mContext);
         keyguardStatusView.setId(R.id.keyguard_status_view);
 
+        when(mResources.getDimensionPixelSize(
+                R.dimen.lockscreen_shade_qs_transition_distance)).thenReturn(DEFAULT_HEIGHT);
         when(mPanelView.getResources()).thenReturn(mResources);
         when(mPanelView.getContext()).thenReturn(getContext());
         when(mPanelView.findViewById(R.id.keyguard_header)).thenReturn(mKeyguardStatusBar);
@@ -272,9 +275,7 @@
 
     @Test
     public void testPanelStaysOpenWhenClosingQs() {
-        mShadeExpansionStateManager.onPanelExpansionChanged(/* fraction= */ 1,
-                /* expanded= */ true, /* tracking= */ false, /* dragDownPxAmount= */ 0);
-        mQsController.setShadeExpandedHeight(1);
+        mQsController.setShadeExpansion(/* shadeExpandedHeight= */ 1, /* expandedFraction=*/ 1);
 
         float shadeExpandedHeight = mQsController.getShadeExpandedHeight();
         mQsController.animateCloseQs(false);
@@ -286,7 +287,7 @@
     public void interceptTouchEvent_withinQs_shadeExpanded_startsQsTracking() {
         mQsController.setQs(mQs);
 
-        mQsController.setShadeExpandedHeight(1f);
+        mQsController.setShadeExpansion(/* shadeExpandedHeight= */ 1, /* expandedFraction=*/ 1);
         mQsController.onIntercept(
                 createMotionEvent(0, 0, ACTION_DOWN));
         mQsController.onIntercept(
@@ -300,7 +301,7 @@
         enableSplitShade(true);
         mQsController.setQs(mQs);
 
-        mQsController.setShadeExpandedHeight(1f);
+        mQsController.setShadeExpansion(/* shadeExpandedHeight= */ 1, /* expandedFraction=*/ 1);
         mQsController.onIntercept(
                 createMotionEvent(0, 0, ACTION_DOWN));
         mQsController.onIntercept(
@@ -339,13 +340,8 @@
     public void handleTouch_downActionInQsArea() {
         mQsController.setQs(mQs);
         mQsController.setBarState(SHADE);
-        mQsController.onPanelExpansionChanged(
-                new ShadeExpansionChangeEvent(
-                        0.5f,
-                        true,
-                        true,
-                        0
-                ));
+        mQsController.setShadeExpansion(/* shadeExpandedHeight= */ 1, /* expandedFraction=*/ 0.5f);
+
         MotionEvent event =
                 createMotionEvent(QS_FRAME_WIDTH / 2, QS_FRAME_BOTTOM / 2, ACTION_DOWN);
         mQsController.handleTouch(event, false, false);
@@ -382,7 +378,7 @@
     @Test
     public void handleTouch_isConflictingExpansionGestureSet() {
         assertThat(mQsController.isConflictingExpansionGesture()).isFalse();
-        mShadeExpansionStateManager.onPanelExpansionChanged(1f, true, false, 0f);
+        mQsController.setShadeExpansion(/* shadeExpandedHeight= */ 1, /* expandedFraction=*/ 1);
         mQsController.handleTouch(MotionEvent.obtain(0L /* downTime */,
                 0L /* eventTime */, ACTION_DOWN, 0f /* x */, 0f /* y */,
                 0 /* metaState */), false, false);
@@ -391,7 +387,7 @@
 
     @Test
     public void handleTouch_isConflictingExpansionGestureSet_cancel() {
-        mShadeExpansionStateManager.onPanelExpansionChanged(1f, true, false, 0f);
+        mQsController.setShadeExpansion(/* shadeExpandedHeight= */ 1, /* expandedFraction=*/ 1);
         mQsController.handleTouch(createMotionEvent(0, 0, ACTION_DOWN), false, false);
         assertThat(mQsController.isConflictingExpansionGesture()).isTrue();
         mQsController.handleTouch(createMotionEvent(0, 0, ACTION_UP), true, true);
@@ -529,6 +525,88 @@
         assertThat(mQsController.isOpenQsEvent(event)).isTrue();
     }
 
+    @Test
+    public void shadeClosed_onLockscreen_inSplitShade_setsQsNotVisible() {
+        mQsController.setQs(mQs);
+        enableSplitShade(true);
+        lockScreen();
+
+        closeLockedQS();
+
+        assertQsVisible(false);
+    }
+
+    @Test
+    public void shadeOpened_onLockscreen_inSplitShade_setsQsVisible() {
+        mQsController.setQs(mQs);
+        enableSplitShade(true);
+        lockScreen();
+
+        openLockedQS();
+
+        assertQsVisible(true);
+    }
+
+    @Test
+    public void shadeClosed_onLockscreen_inSingleShade_setsQsNotVisible() {
+        mQsController.setQs(mQs);
+        enableSplitShade(false);
+        lockScreen();
+
+        closeLockedQS();
+
+        verify(mQs).setQsVisible(false);
+    }
+
+    @Test
+    public void shadeOpened_onLockscreen_inSingleShade_setsQsVisible() {
+        mQsController.setQs(mQs);
+        enableSplitShade(false);
+        lockScreen();
+
+        openLockedQS();
+
+        verify(mQs).setQsVisible(true);
+    }
+
+    private void lockScreen() {
+        mQsController.setBarState(KEYGUARD);
+    }
+
+    private void openLockedQS() {
+        when(mLockscreenShadeTransitionController.getQSDragProgress())
+                .thenReturn((float) DEFAULT_HEIGHT);
+        mLockscreenShadeTransitionCallback.setTransitionToFullShadeAmount(
+                /* pxAmount= */ DEFAULT_HEIGHT,
+                /* animate=*/ false,
+                /* delay= */ 0
+        );
+    }
+
+    private void closeLockedQS() {
+        when(mLockscreenShadeTransitionController.getQSDragProgress()).thenReturn(0f);
+        mLockscreenShadeTransitionCallback.setTransitionToFullShadeAmount(
+                /* pxAmount= */ 0,
+                /* animate=*/ false,
+                /* delay= */ 0
+        );
+    }
+
+    private void setSplitShadeHeightProperties() {
+        // In split shade, min = max
+        when(mQs.getQsMinExpansionHeight()).thenReturn(DEFAULT_MIN_HEIGHT_SPLIT_SHADE);
+        when(mQs.getDesiredHeight()).thenReturn(DEFAULT_HEIGHT);
+        mQsController.updateMinHeight();
+        mQsController.onHeightChanged();
+    }
+
+    private void setDefaultHeightProperties() {
+        when(mQs.getQsMinExpansionHeight()).thenReturn(DEFAULT_MIN_HEIGHT);
+        when(mQs.getDesiredHeight()).thenReturn(DEFAULT_HEIGHT);
+        mQsController.updateMinHeight();
+        mQsController.onHeightChanged();
+    }
+
     private static MotionEvent createMotionEvent(int x, int y, int action) {
         return MotionEvent.obtain(0, 0, action, x, y, 0);
     }
@@ -549,6 +627,11 @@
     private void enableSplitShade(boolean enabled) {
         when(mResources.getBoolean(R.bool.config_use_split_notification_shade)).thenReturn(enabled);
         mQsController.updateResources();
+        if (enabled) {
+            setSplitShadeHeightProperties();
+        } else {
+            setDefaultHeightProperties();
+        }
     }
 
     private void setIsFullWidth(boolean fullWidth) {
@@ -561,5 +644,11 @@
         mQsController.handleShadeLayoutChanged(oldMaxHeight);
     }
 
-
+    private void assertQsVisible(boolean visible) {
+        ArgumentCaptor<Boolean> visibilityCaptor = ArgumentCaptor.forClass(Boolean.class);
+        verify(mQs, atLeastOnce()).setQsVisible(visibilityCaptor.capture());
+        List<Boolean> allVisibilities = visibilityCaptor.getAllValues();
+        boolean lastVisibility = allVisibilities.get(allVisibilities.size() - 1);
+        assertThat(lastVisibility).isEqualTo(visible);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/SplitShadeTransitionAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/SplitShadeTransitionAdapterTest.kt
new file mode 100644
index 0000000..64fec5b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/SplitShadeTransitionAdapterTest.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.shade
+
+import android.animation.Animator
+import android.testing.AndroidTestingRunner
+import android.transition.TransitionValues
+import androidx.test.filters.SmallTest
+import com.android.keyguard.KeyguardStatusViewController
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.shade.NotificationPanelViewController.SplitShadeTransitionAdapter
+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.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class SplitShadeTransitionAdapterTest : SysuiTestCase() {
+
+    @Mock private lateinit var keyguardStatusViewController: KeyguardStatusViewController
+
+    private lateinit var adapter: SplitShadeTransitionAdapter
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        adapter = SplitShadeTransitionAdapter(keyguardStatusViewController)
+    }
+
+    @Test
+    fun createAnimator_nullStartValues_returnsNull() {
+        val animator = adapter.createAnimator(startValues = null, endValues = TransitionValues())
+
+        assertThat(animator).isNull()
+    }
+
+    @Test
+    fun createAnimator_nullEndValues_returnsNull() {
+        val animator = adapter.createAnimator(startValues = TransitionValues(), endValues = null)
+
+        assertThat(animator).isNull()
+    }
+
+    @Test
+    fun createAnimator_nonNullStartAndEndValues_returnsAnimator() {
+        val animator =
+            adapter.createAnimator(startValues = TransitionValues(), endValues = TransitionValues())
+
+        assertThat(animator).isNotNull()
+    }
+}
+
+private fun SplitShadeTransitionAdapter.createAnimator(
+    startValues: TransitionValues?,
+    endValues: TransitionValues?
+): Animator? {
+    return createAnimator(/* sceneRoot= */ null, startValues, endValues)
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/transition/LargeScreenShadeInterpolatorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/transition/LargeScreenShadeInterpolatorImplTest.kt
new file mode 100644
index 0000000..8309342
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/transition/LargeScreenShadeInterpolatorImplTest.kt
@@ -0,0 +1,144 @@
+package com.android.systemui.shade.transition
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.policy.FakeConfigurationController
+import com.google.common.truth.Expect
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class LargeScreenShadeInterpolatorImplTest : SysuiTestCase() {
+    @get:Rule val expect: Expect = Expect.create()
+
+    private val portraitShadeInterpolator = LargeScreenPortraitShadeInterpolator()
+    private val splitShadeInterpolator = SplitShadeInterpolator()
+    private val configurationController = FakeConfigurationController()
+    private val impl =
+        LargeScreenShadeInterpolatorImpl(
+            configurationController,
+            context,
+            splitShadeInterpolator,
+            portraitShadeInterpolator
+        )
+
+    @Test
+    fun getBehindScrimAlpha_inSplitShade_usesSplitShadeValue() {
+        setSplitShadeEnabled(true)
+
+        assertInterpolation(
+            actual = { fraction -> impl.getBehindScrimAlpha(fraction) },
+            expected = { fraction -> splitShadeInterpolator.getBehindScrimAlpha(fraction) }
+        )
+    }
+
+    @Test
+    fun getBehindScrimAlpha_inPortraitShade_usesPortraitShadeValue() {
+        setSplitShadeEnabled(false)
+
+        assertInterpolation(
+            actual = { fraction -> impl.getBehindScrimAlpha(fraction) },
+            expected = { fraction -> portraitShadeInterpolator.getBehindScrimAlpha(fraction) }
+        )
+    }
+
+    @Test
+    fun getNotificationScrimAlpha_inSplitShade_usesSplitShadeValue() {
+        setSplitShadeEnabled(true)
+
+        assertInterpolation(
+            actual = { fraction -> impl.getNotificationScrimAlpha(fraction) },
+            expected = { fraction -> splitShadeInterpolator.getNotificationScrimAlpha(fraction) }
+        )
+    }
+    @Test
+    fun getNotificationScrimAlpha_inPortraitShade_usesPortraitShadeValue() {
+        setSplitShadeEnabled(false)
+
+        assertInterpolation(
+            actual = { fraction -> impl.getNotificationScrimAlpha(fraction) },
+            expected = { fraction -> portraitShadeInterpolator.getNotificationScrimAlpha(fraction) }
+        )
+    }
+
+    @Test
+    fun getNotificationContentAlpha_inSplitShade_usesSplitShadeValue() {
+        setSplitShadeEnabled(true)
+
+        assertInterpolation(
+            actual = { fraction -> impl.getNotificationContentAlpha(fraction) },
+            expected = { fraction -> splitShadeInterpolator.getNotificationContentAlpha(fraction) }
+        )
+    }
+
+    @Test
+    fun getNotificationContentAlpha_inPortraitShade_usesPortraitShadeValue() {
+        setSplitShadeEnabled(false)
+
+        assertInterpolation(
+            actual = { fraction -> impl.getNotificationContentAlpha(fraction) },
+            expected = { fraction ->
+                portraitShadeInterpolator.getNotificationContentAlpha(fraction)
+            }
+        )
+    }
+
+    @Test
+    fun getNotificationFooterAlpha_inSplitShade_usesSplitShadeValue() {
+        setSplitShadeEnabled(true)
+
+        assertInterpolation(
+            actual = { fraction -> impl.getNotificationFooterAlpha(fraction) },
+            expected = { fraction -> splitShadeInterpolator.getNotificationFooterAlpha(fraction) }
+        )
+    }
+    @Test
+    fun getNotificationFooterAlpha_inPortraitShade_usesPortraitShadeValue() {
+        setSplitShadeEnabled(false)
+
+        assertInterpolation(
+            actual = { fraction -> impl.getNotificationFooterAlpha(fraction) },
+            expected = { fraction ->
+                portraitShadeInterpolator.getNotificationFooterAlpha(fraction)
+            }
+        )
+    }
+
+    @Test
+    fun getQsAlpha_inSplitShade_usesSplitShadeValue() {
+        setSplitShadeEnabled(true)
+
+        assertInterpolation(
+            actual = { fraction -> impl.getQsAlpha(fraction) },
+            expected = { fraction -> splitShadeInterpolator.getQsAlpha(fraction) }
+        )
+    }
+    @Test
+    fun getQsAlpha_inPortraitShade_usesPortraitShadeValue() {
+        setSplitShadeEnabled(false)
+
+        assertInterpolation(
+            actual = { fraction -> impl.getQsAlpha(fraction) },
+            expected = { fraction -> portraitShadeInterpolator.getQsAlpha(fraction) }
+        )
+    }
+
+    private fun setSplitShadeEnabled(enabled: Boolean) {
+        overrideResource(R.bool.config_use_split_notification_shade, enabled)
+        configurationController.notifyConfigurationChanged()
+    }
+
+    private fun assertInterpolation(
+        actual: (fraction: Float) -> Float,
+        expected: (fraction: Float) -> Float
+    ) {
+        for (i in 0..10) {
+            val fraction = i / 10f
+            expect.that(actual(fraction)).isEqualTo(expected(fraction))
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/transition/LinearLargeScreenShadeInterpolator.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/transition/LinearLargeScreenShadeInterpolator.kt
new file mode 100644
index 0000000..d24bcdc
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/transition/LinearLargeScreenShadeInterpolator.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shade.transition
+
+class LinearLargeScreenShadeInterpolator : LargeScreenShadeInterpolator {
+    override fun getBehindScrimAlpha(fraction: Float) = fraction
+    override fun getNotificationScrimAlpha(fraction: Float) = fraction
+    override fun getNotificationContentAlpha(fraction: Float) = fraction
+    override fun getNotificationFooterAlpha(fraction: Float) = fraction
+    override fun getQsAlpha(fraction: Float) = fraction
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt
index 84f8656..cbf5485 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt
@@ -5,6 +5,8 @@
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
 import com.android.systemui.shade.STATE_CLOSED
 import com.android.systemui.shade.STATE_OPEN
 import com.android.systemui.shade.STATE_OPENING
@@ -30,6 +32,7 @@
     @Mock private lateinit var dumpManager: DumpManager
     @Mock private lateinit var statusBarStateController: SysuiStatusBarStateController
     @Mock private lateinit var headsUpManager: HeadsUpManager
+    @Mock private lateinit var featureFlags: FeatureFlags
     private val configurationController = FakeConfigurationController()
 
     private lateinit var controller: ScrimShadeTransitionController
@@ -45,7 +48,8 @@
                 scrimController,
                 context.resources,
                 statusBarStateController,
-                headsUpManager)
+                headsUpManager,
+                featureFlags)
 
         controller.onPanelStateChanged(STATE_OPENING)
     }
@@ -107,6 +111,19 @@
     }
 
     @Test
+    fun onPanelExpansionChanged_inSplitShade_flagTrue_setsFractionEqualToEventFraction() {
+        whenever(featureFlags.isEnabled(Flags.LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION))
+                .thenReturn(true)
+        whenever(statusBarStateController.currentOrUpcomingState)
+            .thenReturn(StatusBarState.SHADE)
+        setSplitShadeEnabled(true)
+
+        controller.onPanelExpansionChanged(EXPANSION_EVENT)
+
+        verify(scrimController).setRawPanelExpansionFraction(EXPANSION_EVENT.fraction)
+    }
+
+    @Test
     fun onPanelExpansionChanged_inSplitShade_onKeyguard_setsFractionEqualToEventFraction() {
         whenever(statusBarStateController.currentOrUpcomingState)
             .thenReturn(StatusBarState.KEYGUARD)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimatorTest.kt
index 6a68b71..8841f48 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimatorTest.kt
@@ -65,8 +65,8 @@
         // Positive translationX -> translated to the right
         // 10x10 view center is 25px from the center,
         // When progress is 0.5 it should be translated at:
-        // 25 * 0.3 * (1 - 0.5) = 3.75px
-        assertThat(view.translationX).isWithin(0.01f).of(3.75f)
+        // 25 * 0.08 * (1 - 0.5) = 1px
+        assertThat(view.translationX).isWithin(0.01f).of(1.0f)
     }
 
     @Test
@@ -81,8 +81,8 @@
         // Positive translationX -> translated to the right
         // 10x10 view center is 25px from the center,
         // When progress is 0 it should be translated at:
-        // 25 * 0.3 * (1 - 0) = 7.5px
-        assertThat(view.translationX).isWithin(0.01f).of(7.5f)
+        // 25 * 0.08 * (1 - 0) = 7.5px
+        assertThat(view.translationX).isWithin(0.01f).of(2f)
     }
 
     @Test
@@ -97,7 +97,7 @@
         // Positive translationX -> translated to the right
         // 10x10 view center is 25px from the center,
         // When progress is 1 it should be translated at:
-        // 25 * 0.3 * 0 = 0px
+        // 25 * 0.08 * 0 = 0px
         assertThat(view.translationX).isEqualTo(0f)
     }
 
@@ -113,8 +113,8 @@
         // Positive translationX -> translated to the right, original translation is ignored
         // 10x10 view center is 25px from the center,
         // When progress is 0.5 it should be translated at:
-        // 25 * 0.3 * (1 - 0.5) = 3.75px
-        assertThat(view.translationX).isWithin(0.01f).of(3.75f)
+        // 25 * 0.08 * (1 - 0.5) = 1px
+        assertThat(view.translationX).isWithin(0.01f).of(1.0f)
     }
 
     @Test
@@ -154,7 +154,7 @@
         animator.onTransitionProgress(0.5f)
 
         // Positive translationY -> translated to the bottom
-        assertThat(view.translationY).isWithin(0.01f).of(3.75f)
+        assertThat(view.translationY).isWithin(0.01f).of(1f)
     }
 
     @Test
@@ -169,7 +169,7 @@
         animator.updateViewPositions()
 
         // Negative translationX -> translated to the left
-        assertThat(view.translationX).isWithin(0.1f).of(-5.25f)
+        assertThat(view.translationX).isWithin(0.1f).of(-1.4f)
     }
 
     private fun createView(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/AnimatableClockViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/AnimatableClockViewTest.kt
index cc45cf88..2eca78a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/AnimatableClockViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/AnimatableClockViewTest.kt
@@ -57,7 +57,18 @@
         clockView.measure(50, 50)
 
         verify(mockTextAnimator).glyphFilter = any()
-        verify(mockTextAnimator).setTextStyle(300, -1.0f, 200, false, 350L, null, 0L, null)
+        verify(mockTextAnimator)
+            .setTextStyle(
+                weight = 300,
+                textSize = -1.0f,
+                color = 200,
+                strokeWidth = -1F,
+                animate = false,
+                duration = 350L,
+                interpolator = null,
+                delay = 0L,
+                onAnimationEnd = null
+            )
         verifyNoMoreInteractions(mockTextAnimator)
     }
 
@@ -68,8 +79,30 @@
         clockView.animateAppearOnLockscreen()
 
         verify(mockTextAnimator, times(2)).glyphFilter = any()
-        verify(mockTextAnimator).setTextStyle(100, -1.0f, 200, false, 0L, null, 0L, null)
-        verify(mockTextAnimator).setTextStyle(300, -1.0f, 200, true, 350L, null, 0L, null)
+        verify(mockTextAnimator)
+            .setTextStyle(
+                weight = 100,
+                textSize = -1.0f,
+                color = 200,
+                strokeWidth = -1F,
+                animate = false,
+                duration = 0L,
+                interpolator = null,
+                delay = 0L,
+                onAnimationEnd = null
+            )
+        verify(mockTextAnimator)
+            .setTextStyle(
+                weight = 300,
+                textSize = -1.0f,
+                color = 200,
+                strokeWidth = -1F,
+                animate = true,
+                duration = 350L,
+                interpolator = null,
+                delay = 0L,
+                onAnimationEnd = null
+            )
         verifyNoMoreInteractions(mockTextAnimator)
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt
index a280510..58b44ae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt
@@ -24,6 +24,7 @@
 import android.testing.TestableLooper
 import android.view.View
 import android.view.ViewGroup
+import android.widget.FrameLayout
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dreams.smartspace.DreamSmartspaceController
@@ -46,6 +47,7 @@
 import org.mockito.Mockito
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when`
+import org.mockito.Mockito.anyInt
 import org.mockito.MockitoAnnotations
 import org.mockito.Spy
 
@@ -69,12 +71,21 @@
     private lateinit var viewComponent: SmartspaceViewComponent
 
     @Mock
+    private lateinit var weatherViewComponent: SmartspaceViewComponent
+
+    @Spy
+    private var weatherSmartspaceView: SmartspaceView = TestView(context)
+
+    @Mock
     private lateinit var targetFilter: SmartspaceTargetFilter
 
     @Mock
     private lateinit var plugin: BcSmartspaceDataPlugin
 
     @Mock
+    private lateinit var weatherPlugin: BcSmartspaceDataPlugin
+
+    @Mock
     private lateinit var precondition: SmartspacePrecondition
 
     @Spy
@@ -88,6 +99,9 @@
 
     private lateinit var controller: DreamSmartspaceController
 
+    // TODO(b/272811280): Remove usage of real view
+    private val fakeParent = FrameLayout(context)
+
     /**
      * A class which implements SmartspaceView and extends View. This is mocked to provide the right
      * object inheritance and interface implementation used in DreamSmartspaceController
@@ -121,13 +135,17 @@
     @Before
     fun setup() {
         MockitoAnnotations.initMocks(this)
-        `when`(viewComponentFactory.create(any(), eq(plugin), any()))
+        `when`(viewComponentFactory.create(any(), eq(plugin), any(), eq(null)))
                 .thenReturn(viewComponent)
         `when`(viewComponent.getView()).thenReturn(smartspaceView)
+        `when`(viewComponentFactory.create(any(), eq(weatherPlugin), any(), any()))
+            .thenReturn(weatherViewComponent)
+        `when`(weatherViewComponent.getView()).thenReturn(weatherSmartspaceView)
         `when`(smartspaceManager.createSmartspaceSession(any())).thenReturn(session)
 
         controller = DreamSmartspaceController(context, smartspaceManager, execution, uiExecutor,
-                viewComponentFactory, precondition, Optional.of(targetFilter), Optional.of(plugin))
+                viewComponentFactory, precondition, Optional.of(targetFilter), Optional.of(plugin),
+        Optional.of(weatherPlugin))
     }
 
     /**
@@ -168,11 +186,11 @@
         `when`(precondition.conditionsMet()).thenReturn(true)
         controller.buildAndConnectView(Mockito.mock(ViewGroup::class.java))
 
-        var stateChangeListener = withArgCaptor<View.OnAttachStateChangeListener> {
-            verify(viewComponentFactory).create(any(), eq(plugin), capture())
+        val stateChangeListener = withArgCaptor<View.OnAttachStateChangeListener> {
+            verify(viewComponentFactory).create(any(), eq(plugin), capture(), eq(null))
         }
 
-        var mockView = Mockito.mock(TestView::class.java)
+        val mockView = Mockito.mock(TestView::class.java)
         `when`(precondition.conditionsMet()).thenReturn(true)
         stateChangeListener.onViewAttachedToWindow(mockView)
 
@@ -183,4 +201,74 @@
 
         verify(session).close()
     }
+
+    /**
+     * Ensures session is created when weather smartspace view is created and attached.
+     */
+    @Test
+    fun testConnectOnWeatherViewCreate() {
+        `when`(precondition.conditionsMet()).thenReturn(true)
+
+        val customView = Mockito.mock(TestView::class.java)
+        val weatherView = controller.buildAndConnectWeatherView(fakeParent, customView)
+        val weatherSmartspaceView = weatherView as SmartspaceView
+        fakeParent.addView(weatherView)
+
+        // Then weather view is created with custom view and the default weatherPlugin.getView
+        // should not be called
+        verify(viewComponentFactory).create(eq(fakeParent), eq(weatherPlugin), any(),
+            eq(customView))
+        verify(weatherPlugin, Mockito.never()).getView(fakeParent)
+
+        // And then session is created
+        controller.stateChangeListener.onViewAttachedToWindow(weatherView)
+        verify(smartspaceManager).createSmartspaceSession(any())
+        verify(weatherSmartspaceView).setPrimaryTextColor(anyInt())
+        verify(weatherSmartspaceView).setDozeAmount(0f)
+    }
+
+    /**
+     * Ensures weather plugin registers target listener when it is added from the controller.
+     */
+    @Test
+    fun testAddListenerInController_registersListenerForWeatherPlugin() {
+        val customView = Mockito.mock(TestView::class.java)
+        `when`(precondition.conditionsMet()).thenReturn(true)
+
+        // Given a session is created
+        val weatherView = controller.buildAndConnectWeatherView(fakeParent, customView)
+        controller.stateChangeListener.onViewAttachedToWindow(weatherView)
+        verify(smartspaceManager).createSmartspaceSession(any())
+
+        // When a listener is added
+        controller.addListenerForWeatherPlugin(listener)
+
+        // Then the listener is registered to the weather plugin only
+        verify(weatherPlugin).registerListener(listener)
+        verify(plugin, Mockito.never()).registerListener(any())
+    }
+
+    /**
+     * Ensures session is closed and weather plugin unregisters the notifier when weather smartspace
+     * view is detached.
+     */
+    @Test
+    fun testDisconnect_emitsEmptyListAndRemovesNotifier() {
+        `when`(precondition.conditionsMet()).thenReturn(true)
+
+        // Given a session is created
+        val customView = Mockito.mock(TestView::class.java)
+        val weatherView = controller.buildAndConnectWeatherView(fakeParent, customView)
+        controller.stateChangeListener.onViewAttachedToWindow(weatherView)
+        verify(smartspaceManager).createSmartspaceSession(any())
+
+        // When view is detached
+        controller.stateChangeListener.onViewDetachedFromWindow(weatherView)
+        // Then the session is closed
+        verify(session).close()
+
+        // And the listener receives an empty list of targets and unregisters the notifier
+        verify(weatherPlugin).onTargetsAvailable(emptyList())
+        verify(weatherPlugin).registerSmartspaceEventNotifier(null)
+    }
 }
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 406826b..b7dfea7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -1031,24 +1031,6 @@
     }
 
     @Test
-    public void onRefreshBatteryInfo_pluggedWithOverheat_presentChargingLimited() {
-        createController();
-        BatteryStatus status = new BatteryStatus(BatteryManager.BATTERY_STATUS_DISCHARGING,
-                80 /* level */, BatteryManager.BATTERY_PLUGGED_AC,
-                BatteryManager.BATTERY_HEALTH_OVERHEAT, 0 /* maxChargingWattage */,
-                true /* present */);
-
-        mController.getKeyguardCallback().onRefreshBatteryInfo(status);
-        mController.setVisible(true);
-
-        verifyIndicationMessage(
-                INDICATION_TYPE_BATTERY,
-                mContext.getString(
-                        R.string.keyguard_plugged_in_charging_limited,
-                        NumberFormat.getPercentInstance().format(80 / 100f)));
-    }
-
-    @Test
     public void onRefreshBatteryInfo_fullChargedWithOverheat_presentChargingLimited() {
         createController();
         BatteryStatus status = new BatteryStatus(BatteryManager.BATTERY_STATUS_CHARGING,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
index e6f272b..3327e42 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
@@ -167,4 +167,13 @@
         controller.setIsDreaming(false)
         verify(listener).onDreamingChanged(false)
     }
+
+    @Test
+    fun testSetDreamState_getterReturnsCurrentState() {
+        controller.setIsDreaming(true)
+        assertTrue(controller.isDreaming())
+
+        controller.setIsDreaming(false)
+        assertFalse(controller.isDreaming())
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/FakeNodeController.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/FakeNodeController.kt
new file mode 100644
index 0000000..2de21ae
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/FakeNodeController.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.statusbar.notification.collection.render
+
+import android.view.View
+
+class FakeNodeController(
+    override val view: View,
+    override val nodeLabel: String = "fakeNodeController"
+) : NodeController {
+    override fun offerToKeepInParentForAnimation(): Boolean = false
+    override fun removeFromParentIfKeptForAnimation(): Boolean = false
+    override fun resetKeepInParentForAnimation() = Unit
+}
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 fbec95b..dcbe9843 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
@@ -51,7 +51,6 @@
 import android.os.Handler;
 import android.os.PowerManager;
 import android.os.RemoteException;
-import android.service.dreams.IDreamManager;
 import android.testing.AndroidTestingRunner;
 
 import androidx.test.filters.SmallTest;
@@ -87,8 +86,6 @@
     @Mock
     PowerManager mPowerManager;
     @Mock
-    IDreamManager mDreamManager;
-    @Mock
     AmbientDisplayConfiguration mAmbientDisplayConfiguration;
     @Mock
     StatusBarStateController mStatusBarStateController;
@@ -126,7 +123,6 @@
                 new NotificationInterruptStateProviderImpl(
                         mContext.getContentResolver(),
                         mPowerManager,
-                        mDreamManager,
                         mAmbientDisplayConfiguration,
                         mBatteryController,
                         mStatusBarStateController,
@@ -150,7 +146,7 @@
         when(mHeadsUpManager.isSnoozed(any())).thenReturn(false);
 
         when(mStatusBarStateController.isDozing()).thenReturn(false);
-        when(mDreamManager.isDreaming()).thenReturn(false);
+        when(mStatusBarStateController.isDreaming()).thenReturn(false);
         when(mPowerManager.isScreenOn()).thenReturn(true);
     }
 
@@ -352,7 +348,7 @@
 
         // Also not in use if screen is on but we're showing screen saver / "dreaming"
         when(mPowerManager.isDeviceIdleMode()).thenReturn(true);
-        when(mDreamManager.isDreaming()).thenReturn(true);
+        when(mStatusBarStateController.isDreaming()).thenReturn(true);
         assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
     }
 
@@ -532,7 +528,7 @@
     public void testShouldNotFullScreen_notPendingIntent() throws RemoteException {
         NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
         when(mPowerManager.isInteractive()).thenReturn(true);
-        when(mDreamManager.isDreaming()).thenReturn(false);
+        when(mStatusBarStateController.isDreaming()).thenReturn(false);
         when(mStatusBarStateController.getState()).thenReturn(SHADE);
 
         assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry))
@@ -551,7 +547,7 @@
                 .setSuppressedVisualEffects(SUPPRESSED_EFFECT_FULL_SCREEN_INTENT)
                 .build();
         when(mPowerManager.isInteractive()).thenReturn(false);
-        when(mDreamManager.isDreaming()).thenReturn(false);
+        when(mStatusBarStateController.isDreaming()).thenReturn(false);
         when(mStatusBarStateController.getState()).thenReturn(SHADE);
 
         assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry))
@@ -570,7 +566,7 @@
                 .setSuppressedVisualEffects(SUPPRESSED_EFFECT_FULL_SCREEN_INTENT)
                 .build();
         when(mPowerManager.isInteractive()).thenReturn(false);
-        when(mDreamManager.isDreaming()).thenReturn(false);
+        when(mStatusBarStateController.isDreaming()).thenReturn(false);
         when(mStatusBarStateController.getState()).thenReturn(SHADE);
 
         assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry))
@@ -592,7 +588,7 @@
     public void testShouldNotFullScreen_notHighImportance() throws RemoteException {
         NotificationEntry entry = createFsiNotification(IMPORTANCE_DEFAULT, /* silenced */ false);
         when(mPowerManager.isInteractive()).thenReturn(true);
-        when(mDreamManager.isDreaming()).thenReturn(false);
+        when(mStatusBarStateController.isDreaming()).thenReturn(false);
         when(mStatusBarStateController.getState()).thenReturn(SHADE);
 
         assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry))
@@ -614,7 +610,7 @@
     public void testShouldNotFullScreen_isGroupAlertSilenced() throws RemoteException {
         NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ true);
         when(mPowerManager.isInteractive()).thenReturn(false);
-        when(mDreamManager.isDreaming()).thenReturn(true);
+        when(mStatusBarStateController.isDreaming()).thenReturn(true);
         when(mStatusBarStateController.getState()).thenReturn(KEYGUARD);
 
         assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry))
@@ -643,7 +639,7 @@
     public void testShouldFullScreen_notInteractive() throws RemoteException {
         NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
         when(mPowerManager.isInteractive()).thenReturn(false);
-        when(mDreamManager.isDreaming()).thenReturn(false);
+        when(mStatusBarStateController.isDreaming()).thenReturn(false);
         when(mStatusBarStateController.getState()).thenReturn(SHADE);
 
         assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry))
@@ -665,7 +661,7 @@
     public void testShouldFullScreen_isDreaming() throws RemoteException {
         NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
         when(mPowerManager.isInteractive()).thenReturn(true);
-        when(mDreamManager.isDreaming()).thenReturn(true);
+        when(mStatusBarStateController.isDreaming()).thenReturn(true);
         when(mStatusBarStateController.getState()).thenReturn(SHADE);
 
         assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry))
@@ -687,7 +683,7 @@
     public void testShouldFullScreen_onKeyguard() throws RemoteException {
         NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
         when(mPowerManager.isInteractive()).thenReturn(true);
-        when(mDreamManager.isDreaming()).thenReturn(false);
+        when(mStatusBarStateController.isDreaming()).thenReturn(false);
         when(mStatusBarStateController.getState()).thenReturn(KEYGUARD);
 
         assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry))
@@ -710,7 +706,7 @@
         NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
         when(mPowerManager.isInteractive()).thenReturn(true);
         when(mPowerManager.isScreenOn()).thenReturn(true);
-        when(mDreamManager.isDreaming()).thenReturn(false);
+        when(mStatusBarStateController.isDreaming()).thenReturn(false);
         when(mStatusBarStateController.getState()).thenReturn(SHADE);
 
         assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry))
@@ -727,7 +723,7 @@
         NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
         when(mPowerManager.isInteractive()).thenReturn(true);
         when(mPowerManager.isScreenOn()).thenReturn(true);
-        when(mDreamManager.isDreaming()).thenReturn(false);
+        when(mStatusBarStateController.isDreaming()).thenReturn(false);
         when(mStatusBarStateController.getState()).thenReturn(SHADE);
         when(mHeadsUpManager.isSnoozed("a")).thenReturn(true);
 
@@ -746,7 +742,7 @@
         NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
         when(mPowerManager.isInteractive()).thenReturn(true);
         when(mPowerManager.isScreenOn()).thenReturn(true);
-        when(mDreamManager.isDreaming()).thenReturn(false);
+        when(mStatusBarStateController.isDreaming()).thenReturn(false);
         when(mStatusBarStateController.getState()).thenReturn(SHADE);
         when(mHeadsUpManager.isSnoozed("a")).thenReturn(true);
         when(mKeyguardStateController.isShowing()).thenReturn(true);
@@ -767,7 +763,7 @@
         NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
         when(mPowerManager.isInteractive()).thenReturn(true);
         when(mPowerManager.isScreenOn()).thenReturn(true);
-        when(mDreamManager.isDreaming()).thenReturn(false);
+        when(mStatusBarStateController.isDreaming()).thenReturn(false);
         when(mStatusBarStateController.getState()).thenReturn(SHADE);
         when(mHeadsUpManager.isSnoozed("a")).thenReturn(true);
         when(mKeyguardStateController.isShowing()).thenReturn(true);
@@ -792,7 +788,7 @@
         NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
         when(mPowerManager.isInteractive()).thenReturn(true);
         when(mPowerManager.isScreenOn()).thenReturn(true);
-        when(mDreamManager.isDreaming()).thenReturn(false);
+        when(mStatusBarStateController.isDreaming()).thenReturn(false);
         when(mStatusBarStateController.getState()).thenReturn(SHADE_LOCKED);
         when(mHeadsUpManager.isSnoozed("a")).thenReturn(true);
         when(mKeyguardStateController.isShowing()).thenReturn(true);
@@ -813,7 +809,7 @@
         NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
         when(mPowerManager.isInteractive()).thenReturn(true);
         when(mPowerManager.isScreenOn()).thenReturn(true);
-        when(mDreamManager.isDreaming()).thenReturn(false);
+        when(mStatusBarStateController.isDreaming()).thenReturn(false);
         when(mStatusBarStateController.getState()).thenReturn(SHADE_LOCKED);
         when(mHeadsUpManager.isSnoozed("a")).thenReturn(true);
         when(mKeyguardStateController.isShowing()).thenReturn(true);
@@ -838,7 +834,7 @@
         NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
         when(mPowerManager.isInteractive()).thenReturn(true);
         when(mPowerManager.isScreenOn()).thenReturn(true);
-        when(mDreamManager.isDreaming()).thenReturn(false);
+        when(mStatusBarStateController.isDreaming()).thenReturn(false);
         when(mStatusBarStateController.getState()).thenReturn(SHADE);
         when(mHeadsUpManager.isSnoozed("a")).thenReturn(true);
         when(mKeyguardStateController.isShowing()).thenReturn(false);
@@ -859,7 +855,7 @@
         NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
         when(mPowerManager.isInteractive()).thenReturn(true);
         when(mPowerManager.isScreenOn()).thenReturn(true);
-        when(mDreamManager.isDreaming()).thenReturn(false);
+        when(mStatusBarStateController.isDreaming()).thenReturn(false);
         when(mStatusBarStateController.getState()).thenReturn(SHADE);
         when(mHeadsUpManager.isSnoozed("a")).thenReturn(true);
         when(mKeyguardStateController.isShowing()).thenReturn(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
index 2d23f3c..d164555 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
@@ -21,6 +21,7 @@
 import android.testing.TestableLooper
 import androidx.test.filters.SmallTest
 import com.android.internal.logging.MetricsLogger
+import com.android.internal.statusbar.IStatusBarService
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.flags.FeatureFlags
@@ -30,15 +31,19 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.statusbar.NotificationMediaManager
 import com.android.systemui.statusbar.SmartReplyController
+import com.android.systemui.statusbar.notification.collection.render.FakeNodeController
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager
 import com.android.systemui.statusbar.notification.logging.NotificationLogger
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
+import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer
 import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.statusbar.policy.HeadsUpManager
 import com.android.systemui.statusbar.policy.SmartReplyConstants
 import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.time.SystemClock
 import com.android.systemui.wmshell.BubblesManager
@@ -67,6 +72,7 @@
     private val metricsLogger: MetricsLogger = mock()
     private val logBufferLogger: NotificationRowLogger = mock()
     private val listContainer: NotificationListContainer = mock()
+    private val childrenContainer: NotificationChildrenContainer = mock()
     private val mediaManager: NotificationMediaManager = mock()
     private val smartReplyConstants: SmartReplyConstants = mock()
     private val smartReplyController: SmartReplyController = mock()
@@ -88,6 +94,7 @@
     private val peopleNotificationIdentifier: PeopleNotificationIdentifier = mock()
     private val bubblesManager: BubblesManager = mock()
     private val dragController: ExpandableNotificationRowDragController = mock()
+    private val statusBarService: IStatusBarService = mock()
     private lateinit var controller: ExpandableNotificationRowController
 
     @Before
@@ -124,8 +131,10 @@
                 featureFlags,
                 peopleNotificationIdentifier,
                 Optional.of(bubblesManager),
-                dragController
+                dragController,
+                statusBarService
             )
+        whenever(view.childrenContainer).thenReturn(childrenContainer)
     }
 
     @After
@@ -170,4 +179,32 @@
         Assert.assertFalse(controller.removeFromParentIfKeptForAnimation())
         Mockito.verifyNoMoreInteractions(parentView)
     }
+
+    @Test
+    fun removeChild_whenTransfer() {
+        val childView: ExpandableNotificationRow = mock()
+        val childNodeController = FakeNodeController(childView)
+
+        // GIVEN a child is removed for transfer
+        controller.removeChild(childNodeController, /* isTransfer= */ true)
+
+        // VERIFY the listContainer is not notified
+        Mockito.verify(childView).isChangingPosition = eq(true)
+        Mockito.verify(view).removeChildNotification(eq(childView))
+        Mockito.verify(listContainer, never()).notifyGroupChildRemoved(any(), any())
+    }
+
+    @Test
+    fun removeChild_whenNotTransfer() {
+        val childView: ExpandableNotificationRow = mock()
+        val childNodeController = FakeNodeController(childView)
+
+        // GIVEN a child is removed for real
+        controller.removeChild(childNodeController, /* isTransfer= */ false)
+
+        // VERIFY the listContainer is passed the childrenContainer for transient animations
+        Mockito.verify(childView, never()).isChangingPosition = any()
+        Mockito.verify(view).removeChildNotification(eq(childView))
+        Mockito.verify(listContainer).notifyGroupChildRemoved(eq(childView), eq(childrenContainer))
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
index 9e23d54..957b0f1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
@@ -103,6 +103,7 @@
 
         FakeFeatureFlags fakeFeatureFlags = new FakeFeatureFlags();
         fakeFeatureFlags.set(Flags.NOTIFICATION_ANIMATE_BIG_PICTURE, true);
+        fakeFeatureFlags.set(Flags.SENSITIVE_REVEAL_ANIM, false);
         mNotificationTestHelper.setFeatureFlags(fakeFeatureFlags);
     }
 
@@ -402,17 +403,6 @@
     }
 
     @Test
-    public void testIsBlockingHelperShowing_isCorrectlyUpdated() throws Exception {
-        ExpandableNotificationRow group = mNotificationTestHelper.createGroup();
-
-        group.setBlockingHelperShowing(true);
-        assertTrue(group.isBlockingHelperShowing());
-
-        group.setBlockingHelperShowing(false);
-        assertFalse(group.isBlockingHelperShowing());
-    }
-
-    @Test
     public void testGetNumUniqueChildren_defaultChannel() throws Exception {
         ExpandableNotificationRow groupRow = mNotificationTestHelper.createGroup();
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt
index 7b2051d..0b90ebe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt
@@ -74,7 +74,7 @@
         doReturn(10).whenever(spyRow).intrinsicHeight
 
         with(view) {
-            initialize(mPeopleNotificationIdentifier, mock(), mock(), mock())
+            initialize(mPeopleNotificationIdentifier, mock(), mock(), mock(), mock())
             setContainingNotification(spyRow)
             setHeights(/* smallHeight= */ 10, /* headsUpMaxHeight= */ 20, /* maxHeight= */ 30)
             contractedChild = createViewWithHeight(10)
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 d7ac6b4..3d8a744 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
@@ -117,7 +117,6 @@
     @Mock private NotificationPresenter mPresenter;
     @Mock private NotificationActivityStarter mNotificationActivityStarter;
     @Mock private NotificationListContainer mNotificationListContainer;
-    @Mock private NotificationInfo.CheckSaveListener mCheckSaveListener;
     @Mock private OnSettingsClickListener mOnSettingsClickListener;
     @Mock private DeviceProvisionedController mDeviceProvisionedController;
     @Mock private CentralSurfaces mCentralSurfaces;
@@ -173,7 +172,6 @@
 
         // Test doesn't support animation since the guts view is not attached.
         doNothing().when(guts).openControls(
-                eq(true) /* shouldDoCircularReveal */,
                 anyInt(),
                 anyInt(),
                 anyBoolean(),
@@ -190,7 +188,6 @@
         assertEquals(View.INVISIBLE, guts.getVisibility());
         mTestableLooper.processAllMessages();
         verify(guts).openControls(
-                eq(true),
                 anyInt(),
                 anyInt(),
                 anyBoolean(),
@@ -213,7 +210,6 @@
 
         // Test doesn't support animation since the guts view is not attached.
         doNothing().when(guts).openControls(
-                eq(true) /* shouldDoCircularReveal */,
                 anyInt(),
                 anyInt(),
                 anyBoolean(),
@@ -237,7 +233,6 @@
         assertTrue(mGutsManager.openGutsInternal(row, 0, 0, menuItem));
         mTestableLooper.processAllMessages();
         verify(guts).openControls(
-                eq(true),
                 anyInt(),
                 anyInt(),
                 anyBoolean(),
@@ -379,7 +374,6 @@
     public void testInitializeNotificationInfoView_PassesAlongProvisionedState() throws Exception {
         NotificationInfo notificationInfoView = mock(NotificationInfo.class);
         ExpandableNotificationRow row = spy(mHelper.createRow());
-        row.setBlockingHelperShowing(false);
         modifyRanking(row.getEntry())
                 .setUserSentiment(USER_SENTIMENT_NEGATIVE)
                 .build();
@@ -414,7 +408,6 @@
     public void testInitializeNotificationInfoView_withInitialAction() throws Exception {
         NotificationInfo notificationInfoView = mock(NotificationInfo.class);
         ExpandableNotificationRow row = spy(mHelper.createRow());
-        row.setBlockingHelperShowing(true);
         modifyRanking(row.getEntry())
                 .setUserSentiment(USER_SENTIMENT_NEGATIVE)
                 .build();
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
index e696c87..fdfb4f4 100644
--- 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
@@ -76,7 +76,7 @@
     fun openControls() {
         guts.gutsContent = gutsContent
 
-        guts.openControls(true, 0, 0, false, null)
+        guts.openControls(0, 0, false, null)
     }
 
     @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 aca9c56..318497a 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
@@ -48,6 +48,7 @@
 import android.widget.RemoteViews;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.statusbar.IStatusBarService;
 import com.android.systemui.TestableDependency;
 import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.classifier.FalsingManagerFake;
@@ -548,7 +549,8 @@
                 mock(MetricsLogger.class),
                 mock(SmartReplyConstants.class),
                 mock(SmartReplyController.class),
-                mFeatureFlags);
+                mFeatureFlags,
+                mock(IStatusBarService.class));
 
         row.setAboveShelfChangedListener(aboveShelf -> { });
         mBindStage.getStageParams(entry).requireContentViews(extraInflationFlags);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt
index 87f4c32..09382ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt
@@ -20,6 +20,8 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.shade.transition.LargeScreenShadeInterpolator
 import com.android.systemui.statusbar.StatusBarState
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
 import com.android.systemui.util.mockito.mock
@@ -39,6 +41,8 @@
     private val sectionProvider = StackScrollAlgorithm.SectionProvider { _, _ -> false }
     private val bypassController = StackScrollAlgorithm.BypassController { false }
     private val statusBarKeyguardViewManager = mock<StatusBarKeyguardViewManager>()
+    private val largeScreenShadeInterpolator = mock<LargeScreenShadeInterpolator>()
+    private val featureFlags = mock<FeatureFlags>()
 
     private lateinit var sut: AmbientState
 
@@ -51,6 +55,8 @@
                 sectionProvider,
                 bypassController,
                 statusBarKeyguardViewManager,
+                largeScreenShadeInterpolator,
+                featureFlags
             )
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
index 9d759c4..b1d3daa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
@@ -7,6 +7,9 @@
 import com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerProgress
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.ShadeInterpolation
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.shade.transition.LargeScreenShadeInterpolator
 import com.android.systemui.statusbar.NotificationShelf
 import com.android.systemui.statusbar.StatusBarIconView
 import com.android.systemui.statusbar.notification.LegacySourceType
@@ -21,7 +24,9 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.Mock
 import org.mockito.Mockito.mock
+import org.mockito.MockitoAnnotations
 import org.mockito.Mockito.`when` as whenever
 
 /**
@@ -32,6 +37,9 @@
 @RunWithLooper
 class NotificationShelfTest : SysuiTestCase() {
 
+    @Mock private lateinit var largeScreenShadeInterpolator: LargeScreenShadeInterpolator
+    @Mock private lateinit var flags: FeatureFlags
+
     private val shelf = NotificationShelf(
             context,
             /* attrs */ null,
@@ -50,8 +58,12 @@
 
     @Before
     fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        whenever(ambientState.largeScreenShadeInterpolator).thenReturn(largeScreenShadeInterpolator)
+        whenever(ambientState.featureFlags).thenReturn(flags)
         shelf.bind(ambientState, /* hostLayoutController */ hostLayoutController)
         shelf.layout(/* left */ 0, /* top */ 0, /* right */ 30, /* bottom */5)
+        whenever(ambientState.isSmallScreen).thenReturn(true)
     }
 
     @Test
@@ -295,7 +307,35 @@
     fun updateState_expansionChanging_shelfAlphaUpdated() {
         updateState_expansionChanging_shelfAlphaUpdated(
                 expansionFraction = 0.6f,
-                expectedAlpha = ShadeInterpolation.getContentAlpha(0.6f)
+                expectedAlpha = ShadeInterpolation.getContentAlpha(0.6f),
+        )
+    }
+
+    @Test
+    fun updateState_flagTrue_largeScreen_expansionChanging_shelfAlphaUpdated_largeScreenValue() {
+        val expansionFraction = 0.6f
+        whenever(flags.isEnabled(Flags.LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION)).thenReturn(true)
+        whenever(ambientState.isSmallScreen).thenReturn(false)
+        whenever(largeScreenShadeInterpolator.getNotificationContentAlpha(expansionFraction))
+            .thenReturn(0.123f)
+
+        updateState_expansionChanging_shelfAlphaUpdated(
+            expansionFraction = expansionFraction,
+            expectedAlpha = 0.123f
+        )
+    }
+
+    @Test
+    fun updateState_flagFalse_largeScreen_expansionChanging_shelfAlphaUpdated_standardValue() {
+        val expansionFraction = 0.6f
+        whenever(flags.isEnabled(Flags.LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION)).thenReturn(false)
+        whenever(ambientState.isSmallScreen).thenReturn(false)
+        whenever(largeScreenShadeInterpolator.getNotificationContentAlpha(expansionFraction))
+            .thenReturn(0.123f)
+
+        updateState_expansionChanging_shelfAlphaUpdated(
+            expansionFraction = expansionFraction,
+            expectedAlpha = ShadeInterpolation.getContentAlpha(expansionFraction)
         )
     }
 
@@ -305,7 +345,17 @@
 
         updateState_expansionChanging_shelfAlphaUpdated(
                 expansionFraction = 0.95f,
-                expectedAlpha = aboutToShowBouncerProgress(0.95f)
+                expectedAlpha = aboutToShowBouncerProgress(0.95f),
+        )
+    }
+
+    @Test
+    fun updateState_largeScreen_expansionChangingWhileBouncerInTransit_bouncerInterpolatorUsed() {
+        whenever(ambientState.isBouncerInTransit).thenReturn(true)
+
+        updateState_expansionChanging_shelfAlphaUpdated(
+                expansionFraction = 0.95f,
+                expectedAlpha = aboutToShowBouncerProgress(0.95f),
         )
     }
 
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 ff26a43..45ae96c 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
@@ -52,7 +52,6 @@
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.shade.ShadeController;
-import com.android.systemui.shade.transition.ShadeTransitionController;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
@@ -135,7 +134,6 @@
     @Mock private StackStateLogger mStackLogger;
     @Mock private NotificationStackScrollLogger mLogger;
     @Mock private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
-    @Mock private ShadeTransitionController mShadeTransitionController;
     @Mock private FeatureFlags mFeatureFlags;
     @Mock private NotificationTargetsHelper mNotificationTargetsHelper;
     @Mock private SecureSettings mSecureSettings;
@@ -183,7 +181,6 @@
                 mNotifPipelineFlags,
                 mNotifCollection,
                 mLockscreenShadeTransitionController,
-                mShadeTransitionController,
                 mUiEventLogger,
                 mRemoteInputManager,
                 mVisibilityLocationProviderDelegator,
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 dd7143a..7153e59 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
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.notification.stack;
 
 import static android.view.View.GONE;
+import static android.view.WindowInsets.Type.ime;
 
 import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;
 import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_GENTLE;
@@ -46,6 +47,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.graphics.Insets;
 import android.graphics.Rect;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -54,6 +56,8 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.WindowInsets;
+import android.view.WindowInsetsAnimation;
 import android.widget.TextView;
 
 import androidx.test.annotation.UiThreadTest;
@@ -64,7 +68,9 @@
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.shade.ShadeController;
+import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
 import com.android.systemui.statusbar.EmptyShadeView;
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.NotificationShelfController;
@@ -91,6 +97,8 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
+import java.util.ArrayList;
+
 /**
  * Tests for {@link NotificationStackScrollLayout}.
  */
@@ -123,6 +131,8 @@
     @Mock private NotificationShelf mNotificationShelf;
     @Mock private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
     @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+    @Mock private LargeScreenShadeInterpolator mLargeScreenShadeInterpolator;
+    @Mock private FeatureFlags mFeatureFlags;
 
     @Before
     @UiThreadTest
@@ -136,7 +146,10 @@
                 mDumpManager,
                 mNotificationSectionsManager,
                 mBypassController,
-                mStatusBarKeyguardViewManager));
+                mStatusBarKeyguardViewManager,
+                mLargeScreenShadeInterpolator,
+                mFeatureFlags
+        ));
 
         // Inject dependencies before initializing the layout
         mDependency.injectTestDependency(SysuiStatusBarStateController.class, mBarState);
@@ -843,6 +856,19 @@
         verify(mEmptyShadeView).setFooterText(not(0));
     }
 
+    @Test
+    public void testWindowInsetAnimationProgress_updatesBottomInset() {
+        int bottomImeInset = 100;
+        mStackScrollerInternal.setAnimatedInsetsEnabled(true);
+        WindowInsets windowInsets = new WindowInsets.Builder()
+                .setInsets(ime(), Insets.of(0, 0, 0, bottomImeInset)).build();
+        ArrayList<WindowInsetsAnimation> windowInsetsAnimations = new ArrayList<>();
+        mStackScrollerInternal
+                .dispatchWindowInsetsAnimationProgress(windowInsets, windowInsetsAnimations);
+
+        assertEquals(bottomImeInset, mStackScrollerInternal.mBottomInset);
+    }
+
     private void setBarStateForTest(int state) {
         // Can't inject this through the listener or we end up on the actual implementation
         // rather than the mock because the spy just coppied the anonymous inner /shruggie.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
index 4d9db8c..7f20f1e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
@@ -8,6 +8,9 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.ShadeInterpolation.getContentAlpha
 import com.android.systemui.dump.DumpManager
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.shade.transition.LargeScreenShadeInterpolator
 import com.android.systemui.statusbar.EmptyShadeView
 import com.android.systemui.statusbar.NotificationShelf
 import com.android.systemui.statusbar.StatusBarState
@@ -15,11 +18,13 @@
 import com.android.systemui.statusbar.notification.row.ExpandableView
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
 import com.android.systemui.util.mockito.mock
+import com.google.common.truth.Expect
 import com.google.common.truth.Truth.assertThat
 import junit.framework.Assert.assertEquals
 import junit.framework.Assert.assertFalse
 import junit.framework.Assert.assertTrue
 import org.junit.Before
+import org.junit.Rule
 import org.junit.Test
 import org.mockito.Mockito.any
 import org.mockito.Mockito.eq
@@ -30,12 +35,19 @@
 @SmallTest
 class StackScrollAlgorithmTest : SysuiTestCase() {
 
+
+    @JvmField @Rule
+    var expect: Expect = Expect.create()
+
+    private val largeScreenShadeInterpolator = mock<LargeScreenShadeInterpolator>()
+
     private val hostView = FrameLayout(context)
     private val stackScrollAlgorithm = StackScrollAlgorithm(context, hostView)
     private val notificationRow = mock<ExpandableNotificationRow>()
     private val dumpManager = mock<DumpManager>()
     private val mStatusBarKeyguardViewManager = mock<StatusBarKeyguardViewManager>()
     private val notificationShelf = mock<NotificationShelf>()
+    private val featureFlags = mock<FeatureFlags>()
     private val emptyShadeView = EmptyShadeView(context, /* attrs= */ null).apply {
         layout(/* l= */ 0, /* t= */ 0, /* r= */ 100, /* b= */ 100)
     }
@@ -44,8 +56,10 @@
             dumpManager,
             /* sectionProvider */ { _, _ -> false },
             /* bypassController */ { false },
-            mStatusBarKeyguardViewManager
-    )
+            mStatusBarKeyguardViewManager,
+            largeScreenShadeInterpolator,
+            featureFlags,
+        )
 
     private val testableResources = mContext.getOrCreateTestableResources()
 
@@ -59,6 +73,7 @@
     fun setUp() {
         whenever(notificationShelf.viewState).thenReturn(ExpandableViewState())
         whenever(notificationRow.viewState).thenReturn(ExpandableViewState())
+        ambientState.isSmallScreen = true
 
         hostView.addView(notificationRow)
     }
@@ -145,11 +160,46 @@
     }
 
     @Test
-    fun resetViewStates_expansionChangingWhileBouncerInTransit_notificationAlphaUpdated() {
+    fun resetViewStates_flagTrue_largeScreen_expansionChanging_alphaUpdated_largeScreenValue() {
+        val expansionFraction = 0.6f
+        val surfaceAlpha = 123f
+        ambientState.isSmallScreen = false
+        whenever(featureFlags.isEnabled(Flags.LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION))
+                .thenReturn(true)
+        whenever(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit).thenReturn(false)
+        whenever(largeScreenShadeInterpolator.getNotificationContentAlpha(expansionFraction))
+            .thenReturn(surfaceAlpha)
+
+        resetViewStates_expansionChanging_notificationAlphaUpdated(
+            expansionFraction = expansionFraction,
+            expectedAlpha = surfaceAlpha,
+        )
+    }
+
+    @Test
+    fun resetViewStates_flagFalse_largeScreen_expansionChanging_alphaUpdated_standardValue() {
+        val expansionFraction = 0.6f
+        val surfaceAlpha = 123f
+        ambientState.isSmallScreen = false
+        whenever(featureFlags.isEnabled(Flags.LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION))
+                .thenReturn(false)
+        whenever(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit).thenReturn(false)
+        whenever(largeScreenShadeInterpolator.getNotificationContentAlpha(expansionFraction))
+            .thenReturn(surfaceAlpha)
+
+        resetViewStates_expansionChanging_notificationAlphaUpdated(
+            expansionFraction = expansionFraction,
+            expectedAlpha = getContentAlpha(expansionFraction),
+        )
+    }
+
+    @Test
+    fun expansionChanging_largeScreen_bouncerInTransit_alphaUpdated_bouncerValues() {
+        ambientState.isSmallScreen = false
         whenever(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit).thenReturn(true)
         resetViewStates_expansionChanging_notificationAlphaUpdated(
                 expansionFraction = 0.95f,
-                expectedAlpha = aboutToShowBouncerProgress(0.95f)
+                expectedAlpha = aboutToShowBouncerProgress(0.95f),
         )
     }
 
@@ -696,7 +746,7 @@
 
     private fun resetViewStates_expansionChanging_notificationAlphaUpdated(
             expansionFraction: Float,
-            expectedAlpha: Float
+            expectedAlpha: Float,
     ) {
         ambientState.isExpansionChanging = true
         ambientState.expansionFraction = expansionFraction
@@ -704,7 +754,7 @@
 
         stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0)
 
-        assertThat(notificationRow.viewState.alpha).isEqualTo(expectedAlpha)
+        expect.that(notificationRow.viewState.alpha).isEqualTo(expectedAlpha)
     }
 }
 
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 5a5b142..33a813f 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
@@ -337,7 +337,6 @@
         mNotificationInterruptStateProvider =
                 new TestableNotificationInterruptStateProviderImpl(mContext.getContentResolver(),
                         mPowerManager,
-                        mDreamManager,
                         mAmbientDisplayConfiguration,
                         mStatusBarStateController,
                         mKeyguardStateController,
@@ -719,7 +718,7 @@
     public void testShouldHeadsUp_nonSuppressedGroupSummary() throws Exception {
         when(mPowerManager.isScreenOn()).thenReturn(true);
         when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
-        when(mDreamManager.isDreaming()).thenReturn(false);
+        when(mStatusBarStateController.isDreaming()).thenReturn(false);
 
         Notification n = new Notification.Builder(getContext(), "a")
                 .setGroup("a")
@@ -742,7 +741,7 @@
     public void testShouldHeadsUp_suppressedGroupSummary() throws Exception {
         when(mPowerManager.isScreenOn()).thenReturn(true);
         when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
-        when(mDreamManager.isDreaming()).thenReturn(false);
+        when(mStatusBarStateController.isDreaming()).thenReturn(false);
 
         Notification n = new Notification.Builder(getContext(), "a")
                 .setGroup("a")
@@ -765,7 +764,7 @@
     public void testShouldHeadsUp_suppressedHeadsUp() throws Exception {
         when(mPowerManager.isScreenOn()).thenReturn(true);
         when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
-        when(mDreamManager.isDreaming()).thenReturn(false);
+        when(mStatusBarStateController.isDreaming()).thenReturn(false);
 
         Notification n = new Notification.Builder(getContext(), "a").build();
 
@@ -786,7 +785,7 @@
     public void testShouldHeadsUp_noSuppressedHeadsUp() throws Exception {
         when(mPowerManager.isScreenOn()).thenReturn(true);
         when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
-        when(mDreamManager.isDreaming()).thenReturn(false);
+        when(mStatusBarStateController.isDreaming()).thenReturn(false);
 
         Notification n = new Notification.Builder(getContext(), "a").build();
 
@@ -1036,6 +1035,34 @@
     }
 
     @Test
+    public void testOccludingQSNotExpanded_transitionToAuthScrimmed() {
+        when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
+
+        // GIVEN device occluded and panel is NOT expanded
+        mCentralSurfaces.setBarStateForTest(SHADE); // occluding on LS has StatusBarState = SHADE
+        when(mKeyguardStateController.isOccluded()).thenReturn(true);
+        mCentralSurfaces.mPanelExpanded = false;
+
+        mCentralSurfaces.updateScrimController();
+
+        verify(mScrimController).transitionTo(eq(ScrimState.AUTH_SCRIMMED));
+    }
+
+    @Test
+    public void testOccludingQSExpanded_transitionToAuthScrimmedShade() {
+        when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
+
+        // GIVEN device occluded and qs IS expanded
+        mCentralSurfaces.setBarStateForTest(SHADE); // occluding on LS has StatusBarState = SHADE
+        when(mKeyguardStateController.isOccluded()).thenReturn(true);
+        mCentralSurfaces.mPanelExpanded = true;
+
+        mCentralSurfaces.updateScrimController();
+
+        verify(mScrimController).transitionTo(eq(ScrimState.AUTH_SCRIMMED_SHADE));
+    }
+
+    @Test
     public void testShowKeyguardImplementation_setsState() {
         when(mLockscreenUserManager.getCurrentProfiles()).thenReturn(new SparseArray<>());
 
@@ -1259,6 +1286,15 @@
         verify(mPowerManagerService, never()).wakeUp(anyLong(), anyInt(), anyString(), anyString());
     }
 
+    @Test
+    public void frpLockedDevice_shadeDisabled() {
+        when(mDeviceProvisionedController.isFrpActive()).thenReturn(true);
+        when(mDozeServiceHost.isPulsing()).thenReturn(true);
+        mCentralSurfaces.updateNotificationPanelTouchState();
+
+        verify(mNotificationPanelViewController).setTouchAndAnimationDisabled(true);
+    }
+
     /**
      * Configures the appropriate mocks and then calls {@link CentralSurfacesImpl#updateIsKeyguard}
      * to reconfigure the keyguard to reflect the requested showing/occluded states.
@@ -1308,7 +1344,6 @@
         TestableNotificationInterruptStateProviderImpl(
                 ContentResolver contentResolver,
                 PowerManager powerManager,
-                IDreamManager dreamManager,
                 AmbientDisplayConfiguration ambientDisplayConfiguration,
                 StatusBarStateController controller,
                 KeyguardStateController keyguardStateController,
@@ -1323,7 +1358,6 @@
             super(
                     contentResolver,
                     powerManager,
-                    dreamManager,
                     ambientDisplayConfiguration,
                     batteryController,
                     controller,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
index eb5edbc..f5b7ca8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
@@ -180,6 +180,7 @@
         when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(true);
         mDozeParameters.onTuningChanged(Settings.Secure.DOZE_ALWAYS_ON, "1");
 
+        verify(mScreenOffAnimationController).onAlwaysOnChanged(false);
         assertThat(mDozeParameters.getAlwaysOn()).isFalse();
     }
 
@@ -196,13 +197,16 @@
         mBatteryStateChangeCallback.getValue().onPowerSaveChanged(true);
 
         verify(callback, times(2)).onAlwaysOnChange();
+        verify(mScreenOffAnimationController, times(2)).onAlwaysOnChanged(false);
         assertThat(mDozeParameters.getAlwaysOn()).isFalse();
 
+        reset(mScreenOffAnimationController);
         reset(callback);
         when(mBatteryController.isAodPowerSave()).thenReturn(false);
         mBatteryStateChangeCallback.getValue().onPowerSaveChanged(true);
 
         verify(callback).onAlwaysOnChange();
+        verify(mScreenOffAnimationController).onAlwaysOnChanged(true);
         assertThat(mDozeParameters.getAlwaysOn()).isTrue();
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewTest.java
index 3108ed9..fe12051 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewTest.java
@@ -21,6 +21,7 @@
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.view.LayoutInflater;
+import android.view.View;
 
 import androidx.test.filters.SmallTest;
 
@@ -49,6 +50,13 @@
     }
 
     @Test
+    public void userSwitcherChip_defaultVisibilityIsGone() {
+        assertThat(mKeyguardStatusBarView.findViewById(
+                R.id.user_switcher_container).getVisibility()).isEqualTo(
+                View.GONE);
+    }
+
+    @Test
     public void setTopClipping_clippingUpdated() {
         int topClipping = 40;
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
index 14d239a..3edf33b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
@@ -18,7 +18,6 @@
 
 import android.view.LayoutInflater
 import android.view.MotionEvent
-import android.view.ViewGroup
 import android.view.ViewTreeObserver
 import android.view.ViewTreeObserver.OnPreDrawListener
 import android.widget.FrameLayout
@@ -26,6 +25,8 @@
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
 import com.android.systemui.shade.NotificationPanelViewController
 import com.android.systemui.shade.ShadeControllerImpl
 import com.android.systemui.shade.ShadeLogger
@@ -35,6 +36,7 @@
 import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider
 import com.android.systemui.user.ui.viewmodel.StatusBarUserChipViewModel
 import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.whenever
 import com.android.systemui.util.view.ViewUtil
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
@@ -55,7 +57,7 @@
     @Mock
     private lateinit var notificationPanelViewController: NotificationPanelViewController
     @Mock
-    private lateinit var panelView: ViewGroup
+    private lateinit var featureFlags: FeatureFlags
     @Mock
     private lateinit var moveFromCenterAnimation: StatusBarMoveFromCenterAnimationController
     @Mock
@@ -96,6 +98,8 @@
 
     @Test
     fun onViewAttachedAndDrawn_moveFromCenterAnimationEnabled_moveFromCenterAnimationInitialized() {
+        whenever(featureFlags.isEnabled(Flags.ENABLE_UNFOLD_STATUS_BAR_ANIMATIONS))
+                .thenReturn(true)
         val view = createViewMock()
         val argumentCaptor = ArgumentCaptor.forClass(OnPreDrawListener::class.java)
         unfoldConfig.isEnabled = true
@@ -111,12 +115,26 @@
     }
 
     @Test
+    fun onViewAttachedAndDrawn_statusBarAnimationDisabled_animationNotInitialized() {
+        whenever(featureFlags.isEnabled(Flags.ENABLE_UNFOLD_STATUS_BAR_ANIMATIONS))
+                .thenReturn(false)
+        val view = createViewMock()
+        unfoldConfig.isEnabled = true
+        // create the controller on main thread as it requires main looper
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            controller = createAndInitController(view)
+        }
+
+        verify(moveFromCenterAnimation, never()).onViewsReady(any())
+    }
+
+    @Test
     fun handleTouchEventFromStatusBar_panelsNotEnabled_returnsFalseAndNoViewEvent() {
         `when`(centralSurfacesImpl.commandQueuePanelsEnabled).thenReturn(false)
         val returnVal = view.onTouchEvent(
                         MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0))
         assertThat(returnVal).isFalse()
-        verify(notificationPanelViewController, never()).sendTouchEventToView(any())
+        verify(notificationPanelViewController, never()).handleExternalTouch(any())
     }
 
     @Test
@@ -128,7 +146,7 @@
         val returnVal = view.onTouchEvent(
                 MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0))
         assertThat(returnVal).isTrue()
-        verify(notificationPanelViewController, never()).sendTouchEventToView(any())
+        verify(notificationPanelViewController, never()).handleExternalTouch(any())
     }
 
     @Test
@@ -141,7 +159,7 @@
 
         view.onTouchEvent(event)
 
-        verify(notificationPanelViewController).sendTouchEventToView(event)
+        verify(notificationPanelViewController).handleExternalTouch(event)
     }
 
     @Test
@@ -154,7 +172,7 @@
 
         view.onTouchEvent(event)
 
-        verify(notificationPanelViewController).sendTouchEventToView(event)
+        verify(notificationPanelViewController).handleExternalTouch(event)
     }
 
     @Test
@@ -167,7 +185,7 @@
 
         view.onTouchEvent(event)
 
-        verify(notificationPanelViewController, never()).sendTouchEventToView(any())
+        verify(notificationPanelViewController, never()).handleExternalTouch(any())
     }
 
     private fun createViewMock(): PhoneStatusBarView {
@@ -182,6 +200,7 @@
         return PhoneStatusBarViewController.Factory(
             Optional.of(sysuiUnfoldComponent),
             Optional.of(progressProvider),
+            featureFlags,
             userChipViewModel,
             centralSurfacesImpl,
             shadeControllerImpl,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt
index 27b1da0..3ed454f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt
@@ -19,6 +19,7 @@
 import android.view.MotionEvent
 import android.view.ViewGroup
 import androidx.test.filters.SmallTest
+import com.android.systemui.Gefingerpoken
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.shade.NotificationPanelViewController
 import com.google.common.truth.Truth.assertThat
@@ -94,16 +95,17 @@
         // No assert needed, just testing no crash
     }
 
-    private class TestTouchEventHandler : PhoneStatusBarView.TouchEventHandler {
+    private class TestTouchEventHandler : Gefingerpoken {
         var lastInterceptEvent: MotionEvent? = null
         var lastEvent: MotionEvent? = null
         var handleTouchReturnValue: Boolean = false
 
-        override fun onInterceptTouchEvent(event: MotionEvent?) {
+        override fun onInterceptTouchEvent(event: MotionEvent?): Boolean {
             lastInterceptEvent = event
+            return handleTouchReturnValue
         }
 
-        override fun handleTouchEvent(event: MotionEvent?): Boolean {
+        override fun onTouchEvent(event: MotionEvent?): Boolean {
             lastEvent = event
             return handleTouchReturnValue
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 180d9f8..a9ed175 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -24,9 +24,8 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
-
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -41,6 +40,8 @@
 import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 
+import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
+
 import android.animation.Animator;
 import android.app.AlarmManager;
 import android.graphics.Color;
@@ -59,6 +60,8 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.animation.ShadeInterpolation;
 import com.android.systemui.dock.DockManager;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
 import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants;
@@ -67,6 +70,8 @@
 import com.android.systemui.keyguard.shared.model.TransitionStep;
 import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;
 import com.android.systemui.scrim.ScrimView;
+import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
+import com.android.systemui.shade.transition.LinearLargeScreenShadeInterpolator;
 import com.android.systemui.statusbar.policy.FakeConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.concurrency.FakeExecutor;
@@ -103,6 +108,8 @@
 
     private final FakeConfigurationController mConfigurationController =
             new FakeConfigurationController();
+    private final LargeScreenShadeInterpolator
+            mLinearLargeScreenShadeInterpolator = new LinearLargeScreenShadeInterpolator();
 
     private ScrimController mScrimController;
     private ScrimView mScrimBehind;
@@ -131,6 +138,7 @@
     // TODO(b/204991468): Use a real PanelExpansionStateManager object once this bug is fixed. (The
     //   event-dispatch-on-registration pattern caused some of these unit tests to fail.)
     @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+    @Mock private FeatureFlags mFeatureFlags;
 
     private static class AnimatorListener implements Animator.AnimatorListener {
         private int mNumStarts;
@@ -240,18 +248,28 @@
 
         when(mKeyguardTransitionInteractor.getPrimaryBouncerToGoneTransition())
                 .thenReturn(emptyFlow());
-        when(mPrimaryBouncerToGoneTransitionViewModel.getScrimAlpha()).thenReturn(emptyFlow());
+        when(mPrimaryBouncerToGoneTransitionViewModel.getScrimAlpha())
+                .thenReturn(emptyFlow());
 
-        mScrimController = new ScrimController(mLightBarController,
-                mDozeParameters, mAlarmManager, mKeyguardStateController, mDelayedWakeLockBuilder,
-                new FakeHandler(mLooper.getLooper()), mKeyguardUpdateMonitor,
-                mDockManager, mConfigurationController, new FakeExecutor(new FakeSystemClock()),
+        mScrimController = new ScrimController(
+                mLightBarController,
+                mDozeParameters,
+                mAlarmManager,
+                mKeyguardStateController,
+                mDelayedWakeLockBuilder,
+                new FakeHandler(mLooper.getLooper()),
+                mKeyguardUpdateMonitor,
+                mDockManager,
+                mConfigurationController,
+                new FakeExecutor(new FakeSystemClock()),
                 mScreenOffAnimationController,
                 mKeyguardUnlockAnimationController,
                 mStatusBarKeyguardViewManager,
                 mPrimaryBouncerToGoneTransitionViewModel,
                 mKeyguardTransitionInteractor,
-                mMainDispatcher);
+                mMainDispatcher,
+                mLinearLargeScreenShadeInterpolator,
+                mFeatureFlags);
         mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
         mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront);
         mScrimController.setAnimatorListener(mAnimatorListener);
@@ -649,7 +667,81 @@
     }
 
     @Test
-    public void transitionToUnlocked() {
+    public void transitionToUnlocked_clippedQs() {
+        mScrimController.setClipsQsScrim(true);
+        mScrimController.setRawPanelExpansionFraction(0f);
+        mScrimController.transitionTo(ScrimState.UNLOCKED);
+        finishAnimationsImmediately();
+
+        assertScrimTinted(Map.of(
+                mNotificationsScrim, false,
+                mScrimInFront, false,
+                mScrimBehind, true
+        ));
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mNotificationsScrim, TRANSPARENT,
+                mScrimBehind, OPAQUE));
+
+        mScrimController.setRawPanelExpansionFraction(0.25f);
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mNotificationsScrim, SEMI_TRANSPARENT,
+                mScrimBehind, OPAQUE));
+
+        mScrimController.setRawPanelExpansionFraction(0.5f);
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mNotificationsScrim, OPAQUE,
+                mScrimBehind, OPAQUE));
+    }
+
+    @Test
+    public void transitionToUnlocked_nonClippedQs_flagTrue_followsLargeScreensInterpolator() {
+        when(mFeatureFlags.isEnabled(Flags.LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION))
+                .thenReturn(true);
+        mScrimController.setClipsQsScrim(false);
+        mScrimController.setRawPanelExpansionFraction(0f);
+        mScrimController.transitionTo(ScrimState.UNLOCKED);
+        finishAnimationsImmediately();
+
+        assertScrimTinted(Map.of(
+                mNotificationsScrim, false,
+                mScrimInFront, false,
+                mScrimBehind, true
+        ));
+        // The large screens interpolator used in this test is a linear one, just for tests.
+        // Assertions below are based on this assumption, and that the code uses that interpolator
+        // when on a large screen (QS not clipped).
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mNotificationsScrim, TRANSPARENT,
+                mScrimBehind, TRANSPARENT));
+
+        mScrimController.setRawPanelExpansionFraction(0.5f);
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mNotificationsScrim, SEMI_TRANSPARENT,
+                mScrimBehind, SEMI_TRANSPARENT));
+
+        mScrimController.setRawPanelExpansionFraction(0.99f);
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mNotificationsScrim, SEMI_TRANSPARENT,
+                mScrimBehind, SEMI_TRANSPARENT));
+
+        mScrimController.setRawPanelExpansionFraction(1f);
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mNotificationsScrim, OPAQUE,
+                mScrimBehind, OPAQUE));
+    }
+
+
+    @Test
+    public void transitionToUnlocked_nonClippedQs_flagFalse() {
+        when(mFeatureFlags.isEnabled(Flags.LARGE_SHADE_GRANULAR_ALPHA_INTERPOLATION))
+                .thenReturn(false);
         mScrimController.setClipsQsScrim(false);
         mScrimController.setRawPanelExpansionFraction(0f);
         mScrimController.transitionTo(ScrimState.UNLOCKED);
@@ -687,7 +779,6 @@
                 mScrimBehind, OPAQUE));
     }
 
-
     @Test
     public void scrimStateCallback() {
         mScrimController.transitionTo(ScrimState.UNLOCKED);
@@ -875,16 +966,25 @@
         // GIVEN display does NOT need blanking
         when(mDozeParameters.getDisplayNeedsBlanking()).thenReturn(false);
 
-        mScrimController = new ScrimController(mLightBarController,
-                mDozeParameters, mAlarmManager, mKeyguardStateController, mDelayedWakeLockBuilder,
-                new FakeHandler(mLooper.getLooper()), mKeyguardUpdateMonitor,
-                mDockManager, mConfigurationController, new FakeExecutor(new FakeSystemClock()),
+        mScrimController = new ScrimController(
+                mLightBarController,
+                mDozeParameters,
+                mAlarmManager,
+                mKeyguardStateController,
+                mDelayedWakeLockBuilder,
+                new FakeHandler(mLooper.getLooper()),
+                mKeyguardUpdateMonitor,
+                mDockManager,
+                mConfigurationController,
+                new FakeExecutor(new FakeSystemClock()),
                 mScreenOffAnimationController,
                 mKeyguardUnlockAnimationController,
                 mStatusBarKeyguardViewManager,
                 mPrimaryBouncerToGoneTransitionViewModel,
                 mKeyguardTransitionInteractor,
-                mMainDispatcher);
+                mMainDispatcher,
+                mLinearLargeScreenShadeInterpolator,
+                mFeatureFlags);
         mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
         mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront);
         mScrimController.setAnimatorListener(mAnimatorListener);
@@ -1064,8 +1164,8 @@
     @Test
     public void testScrimFocus() {
         mScrimController.transitionTo(ScrimState.AOD);
-        Assert.assertFalse("Should not be focusable on AOD", mScrimBehind.isFocusable());
-        Assert.assertFalse("Should not be focusable on AOD", mScrimInFront.isFocusable());
+        assertFalse("Should not be focusable on AOD", mScrimBehind.isFocusable());
+        assertFalse("Should not be focusable on AOD", mScrimInFront.isFocusable());
 
         mScrimController.transitionTo(ScrimState.KEYGUARD);
         Assert.assertTrue("Should be focusable on keyguard", mScrimBehind.isFocusable());
@@ -1125,7 +1225,7 @@
     public void testAnimatesTransitionToAod() {
         when(mDozeParameters.shouldControlScreenOff()).thenReturn(false);
         ScrimState.AOD.prepare(ScrimState.KEYGUARD);
-        Assert.assertFalse("No animation when ColorFade kicks in",
+        assertFalse("No animation when ColorFade kicks in",
                 ScrimState.AOD.getAnimateChange());
 
         reset(mDozeParameters);
@@ -1137,9 +1237,9 @@
 
     @Test
     public void testViewsDontHaveFocusHighlight() {
-        Assert.assertFalse("Scrim shouldn't have focus highlight",
+        assertFalse("Scrim shouldn't have focus highlight",
                 mScrimInFront.getDefaultFocusHighlightEnabled());
-        Assert.assertFalse("Scrim shouldn't have focus highlight",
+        assertFalse("Scrim shouldn't have focus highlight",
                 mScrimBehind.getDefaultFocusHighlightEnabled());
     }
 
@@ -1639,7 +1739,7 @@
     @Test
     public void aodStateSetsFrontScrimToNotBlend() {
         mScrimController.transitionTo(ScrimState.AOD);
-        Assert.assertFalse("Front scrim should not blend with main color",
+        assertFalse("Front scrim should not blend with main color",
                 mScrimInFront.shouldBlendWithMainColor());
     }
 
@@ -1664,6 +1764,24 @@
         assertThat(mScrimController.getState()).isEqualTo(ScrimState.UNLOCKED);
     }
 
+    @Test
+    public void primaryBouncerToGoneOnFinishCallsKeyguardFadedAway() {
+        when(mKeyguardStateController.isKeyguardFadingAway()).thenReturn(true);
+        mScrimController.mPrimaryBouncerToGoneTransition.accept(
+                new TransitionStep(KeyguardState.PRIMARY_BOUNCER, KeyguardState.GONE, 0f,
+                        TransitionState.FINISHED, "ScrimControllerTest"));
+
+        verify(mStatusBarKeyguardViewManager).onKeyguardFadedAway();
+    }
+
+    @Test
+    public void testDoNotAnimateChangeIfOccludeAnimationPlaying() {
+        mScrimController.setOccludeAnimationPlaying(true);
+        mScrimController.transitionTo(ScrimState.UNLOCKED);
+
+        assertFalse(ScrimState.UNLOCKED.mAnimateChange);
+    }
+
     private void assertAlphaAfterExpansion(ScrimView scrim, float expectedAlpha, float expansion) {
         mScrimController.setRawPanelExpansionFraction(expansion);
         finishAnimationsImmediately();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImplTest.kt
index 3bc288a2..08e89fb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImplTest.kt
@@ -20,13 +20,17 @@
 import androidx.test.filters.SmallTest
 import com.android.internal.statusbar.StatusBarIcon
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.CommandQueue
 import com.android.systemui.statusbar.phone.StatusBarIconController.TAG_PRIMARY
 import com.android.systemui.statusbar.phone.StatusBarIconControllerImpl.EXTERNAL_SLOT_SUFFIX
+import com.android.systemui.util.mockito.kotlinArgumentCaptor
 import com.android.systemui.util.mockito.mock
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
 import org.junit.Test
+import org.mockito.Mock
 import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
 
 @SmallTest
 class StatusBarIconControllerImplTest : SysuiTestCase() {
@@ -34,15 +38,19 @@
     private lateinit var underTest: StatusBarIconControllerImpl
 
     private lateinit var iconList: StatusBarIconList
+    private lateinit var commandQueueCallbacks: CommandQueue.Callbacks
     private val iconGroup: StatusBarIconController.IconManager = mock()
 
+    @Mock private lateinit var commandQueue: CommandQueue
+
     @Before
     fun setUp() {
+        MockitoAnnotations.initMocks(this)
         iconList = StatusBarIconList(arrayOf())
         underTest =
             StatusBarIconControllerImpl(
                 context,
-                mock(),
+                commandQueue,
                 mock(),
                 mock(),
                 mock(),
@@ -51,11 +59,14 @@
                 mock(),
             )
         underTest.addIconGroup(iconGroup)
+        val commandQueueCallbacksCaptor = kotlinArgumentCaptor<CommandQueue.Callbacks>()
+        verify(commandQueue).addCallback(commandQueueCallbacksCaptor.capture())
+        commandQueueCallbacks = commandQueueCallbacksCaptor.value
     }
 
     /** Regression test for b/255428281. */
     @Test
-    fun internalAndExternalIconWithSameName_bothDisplayed() {
+    fun internalAndExternalIconWithSameName_externalFromTile_bothDisplayed() {
         val slotName = "mute"
 
         // Internal
@@ -71,7 +82,7 @@
                 /* number= */ 0,
                 "contentDescription",
             )
-        underTest.setIcon(slotName, externalIcon)
+        underTest.setIconFromTile(slotName, externalIcon)
 
         assertThat(iconList.slots).hasSize(2)
         // Whichever was added last comes first
@@ -83,17 +94,45 @@
 
     /** Regression test for b/255428281. */
     @Test
-    fun internalAndExternalIconWithSameName_externalRemoved_viaRemoveIcon_internalStays() {
+    fun internalAndExternalIconWithSameName_externalFromCommandQueue_bothDisplayed() {
         val slotName = "mute"
 
         // Internal
         underTest.setIcon(slotName, /* resourceId= */ 10, "contentDescription")
 
         // External
-        underTest.setIcon(slotName, createExternalIcon())
+        val externalIcon =
+            StatusBarIcon(
+                "external.package",
+                UserHandle.ALL,
+                /* iconId= */ 2,
+                /* iconLevel= */ 0,
+                /* number= */ 0,
+                "contentDescription",
+            )
+        commandQueueCallbacks.setIcon(slotName, externalIcon)
 
-        // WHEN the external icon is removed via #removeIcon
-        underTest.removeIcon(slotName)
+        assertThat(iconList.slots).hasSize(2)
+        // Whichever was added last comes first
+        assertThat(iconList.slots[0].name).isEqualTo(slotName + EXTERNAL_SLOT_SUFFIX)
+        assertThat(iconList.slots[1].name).isEqualTo(slotName)
+        assertThat(iconList.slots[0].hasIconsInSlot()).isTrue()
+        assertThat(iconList.slots[1].hasIconsInSlot()).isTrue()
+    }
+
+    /** Regression test for b/255428281. */
+    @Test
+    fun internalAndExternalIconWithSameName_externalRemoved_fromCommandQueue_internalStays() {
+        val slotName = "mute"
+
+        // Internal
+        underTest.setIcon(slotName, /* resourceId= */ 10, "contentDescription")
+
+        // External
+        commandQueueCallbacks.setIcon(slotName, createExternalIcon())
+
+        // WHEN the external icon is removed via CommandQueue.Callbacks#removeIcon
+        commandQueueCallbacks.removeIcon(slotName)
 
         // THEN the external icon is removed but the internal icon remains
         // Note: [StatusBarIconList] never removes slots from its list, it just sets the holder for
@@ -109,17 +148,17 @@
 
     /** Regression test for b/255428281. */
     @Test
-    fun internalAndExternalIconWithSameName_externalRemoved_viaRemoveAll_internalStays() {
+    fun internalAndExternalIconWithSameName_externalRemoved_fromTileRemove_internalStays() {
         val slotName = "mute"
 
         // Internal
         underTest.setIcon(slotName, /* resourceId= */ 10, "contentDescription")
 
         // External
-        underTest.setIcon(slotName, createExternalIcon())
+        underTest.setIconFromTile(slotName, createExternalIcon())
 
-        // WHEN the external icon is removed via #removeAllIconsForExternalSlot
-        underTest.removeAllIconsForExternalSlot(slotName)
+        // WHEN the external icon is removed via #removeIconForTile
+        underTest.removeIconForTile(slotName)
 
         // THEN the external icon is removed but the internal icon remains
         assertThat(iconList.slots).hasSize(2)
@@ -133,17 +172,17 @@
 
     /** Regression test for b/255428281. */
     @Test
-    fun internalAndExternalIconWithSameName_externalRemoved_viaSetNull_internalStays() {
+    fun internalAndExternalIconWithSameName_externalRemoved_fromTileSetNull_internalStays() {
         val slotName = "mute"
 
         // Internal
         underTest.setIcon(slotName, /* resourceId= */ 10, "contentDescription")
 
         // External
-        underTest.setIcon(slotName, createExternalIcon())
+        underTest.setIconFromTile(slotName, createExternalIcon())
 
-        // WHEN the external icon is removed via a #setIcon(null)
-        underTest.setIcon(slotName, /* icon= */ null)
+        // WHEN the external icon is removed via a #setIconFromTile(null)
+        underTest.setIconFromTile(slotName, /* icon= */ null)
 
         // THEN the external icon is removed but the internal icon remains
         assertThat(iconList.slots).hasSize(2)
@@ -164,12 +203,12 @@
         underTest.setIcon(slotName, /* resourceId= */ 10, "contentDescription")
 
         // External
-        underTest.setIcon(slotName, createExternalIcon())
+        underTest.setIconFromTile(slotName, createExternalIcon())
 
         // WHEN the internal icon is removed via #removeIcon
         underTest.removeIcon(slotName, /* tag= */ 0)
 
-        // THEN the external icon is removed but the internal icon remains
+        // THEN the internal icon is removed but the external icon remains
         assertThat(iconList.slots).hasSize(2)
         assertThat(iconList.slots[0].name).isEqualTo(slotName + EXTERNAL_SLOT_SUFFIX)
         assertThat(iconList.slots[1].name).isEqualTo(slotName)
@@ -188,12 +227,12 @@
         underTest.setIcon(slotName, /* resourceId= */ 10, "contentDescription")
 
         // External
-        underTest.setIcon(slotName, createExternalIcon())
+        underTest.setIconFromTile(slotName, createExternalIcon())
 
         // WHEN the internal icon is removed via #removeAllIconsForSlot
         underTest.removeAllIconsForSlot(slotName)
 
-        // THEN the external icon is removed but the internal icon remains
+        // THEN the internal icon is removed but the external icon remains
         assertThat(iconList.slots).hasSize(2)
         assertThat(iconList.slots[0].name).isEqualTo(slotName + EXTERNAL_SLOT_SUFFIX)
         assertThat(iconList.slots[1].name).isEqualTo(slotName)
@@ -221,7 +260,7 @@
                 /* number= */ 0,
                 "externalDescription",
             )
-        underTest.setIcon(slotName, startingExternalIcon)
+        underTest.setIconFromTile(slotName, startingExternalIcon)
 
         // WHEN the internal icon is updated
         underTest.setIcon(slotName, /* resourceId= */ 11, "newContentDescription")
@@ -243,7 +282,7 @@
 
     /** Regression test for b/255428281. */
     @Test
-    fun internalAndExternalIconWithSameName_externalUpdatedIndependently() {
+    fun internalAndExternalIconWithSameName_fromTile_externalUpdatedIndependently() {
         val slotName = "mute"
 
         // Internal
@@ -259,7 +298,7 @@
                 /* number= */ 0,
                 "externalDescription",
             )
-        underTest.setIcon(slotName, startingExternalIcon)
+        underTest.setIconFromTile(slotName, startingExternalIcon)
 
         // WHEN the external icon is updated
         val newExternalIcon =
@@ -271,7 +310,54 @@
                 /* number= */ 0,
                 "newExternalDescription",
             )
-        underTest.setIcon(slotName, newExternalIcon)
+        underTest.setIconFromTile(slotName, newExternalIcon)
+
+        // THEN only the external slot gets the updates
+        val externalSlot = iconList.slots[0]
+        val externalHolder = externalSlot.getHolderForTag(TAG_PRIMARY)!!
+        assertThat(externalSlot.name).isEqualTo(slotName + EXTERNAL_SLOT_SUFFIX)
+        assertThat(externalHolder.icon!!.contentDescription).isEqualTo("newExternalDescription")
+        assertThat(externalHolder.icon!!.icon.resId).isEqualTo(21)
+
+        // And the internal slot has its own values
+        val internalSlot = iconList.slots[1]
+        val internalHolder = internalSlot.getHolderForTag(TAG_PRIMARY)!!
+        assertThat(internalSlot.name).isEqualTo(slotName)
+        assertThat(internalHolder.icon!!.contentDescription).isEqualTo("contentDescription")
+        assertThat(internalHolder.icon!!.icon.resId).isEqualTo(10)
+    }
+
+    /** Regression test for b/255428281. */
+    @Test
+    fun internalAndExternalIconWithSameName_fromCommandQueue_externalUpdatedIndependently() {
+        val slotName = "mute"
+
+        // Internal
+        underTest.setIcon(slotName, /* resourceId= */ 10, "contentDescription")
+
+        // External
+        val startingExternalIcon =
+            StatusBarIcon(
+                "external.package",
+                UserHandle.ALL,
+                /* iconId= */ 20,
+                /* iconLevel= */ 0,
+                /* number= */ 0,
+                "externalDescription",
+            )
+        commandQueueCallbacks.setIcon(slotName, startingExternalIcon)
+
+        // WHEN the external icon is updated
+        val newExternalIcon =
+            StatusBarIcon(
+                "external.package",
+                UserHandle.ALL,
+                /* iconId= */ 21,
+                /* iconLevel= */ 0,
+                /* number= */ 0,
+                "newExternalDescription",
+            )
+        commandQueueCallbacks.setIcon(slotName, newExternalIcon)
 
         // THEN only the external slot gets the updates
         val externalSlot = iconList.slots[0]
@@ -289,8 +375,16 @@
     }
 
     @Test
-    fun externalSlot_alreadyEndsWithSuffix_suffixNotAddedTwice() {
-        underTest.setIcon("myslot$EXTERNAL_SLOT_SUFFIX", createExternalIcon())
+    fun externalSlot_fromTile_alreadyEndsWithSuffix_suffixNotAddedTwice() {
+        underTest.setIconFromTile("myslot$EXTERNAL_SLOT_SUFFIX", createExternalIcon())
+
+        assertThat(iconList.slots).hasSize(1)
+        assertThat(iconList.slots[0].name).isEqualTo("myslot$EXTERNAL_SLOT_SUFFIX")
+    }
+
+    @Test
+    fun externalSlot_fromCommandQueue_alreadyEndsWithSuffix_suffixNotAddedTwice() {
+        commandQueueCallbacks.setIcon("myslot$EXTERNAL_SLOT_SUFFIX", createExternalIcon())
 
         assertThat(iconList.slots).hasSize(1)
         assertThat(iconList.slots[0].name).isEqualTo("myslot$EXTERNAL_SLOT_SUFFIX")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 158e9ad..346b90c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -35,6 +35,7 @@
 
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewRootImpl;
@@ -683,4 +684,122 @@
         // the following call before registering centralSurfaces should NOT throw a NPE:
         mStatusBarKeyguardViewManager.hideAlternateBouncer(true);
     }
+
+    @Test
+    public void testResetHideBouncerWhenShowing_alternateBouncerHides() {
+        // GIVEN the keyguard is showing
+        reset(mAlternateBouncerInteractor);
+        when(mKeyguardStateController.isShowing()).thenReturn(true);
+
+        // WHEN SBKV is reset with hideBouncerWhenShowing=true
+        mStatusBarKeyguardViewManager.reset(true);
+
+        // THEN alternate bouncer is hidden
+        verify(mAlternateBouncerInteractor).hide();
+    }
+
+    @Test
+    public void testResetHideBouncerWhenShowingIsFalse_alternateBouncerHides() {
+        // GIVEN the keyguard is showing
+        reset(mAlternateBouncerInteractor);
+        when(mKeyguardStateController.isShowing()).thenReturn(true);
+
+        // WHEN SBKV is reset with hideBouncerWhenShowing=false
+        mStatusBarKeyguardViewManager.reset(false);
+
+        // THEN alternate bouncer is NOT hidden
+        verify(mAlternateBouncerInteractor, never()).hide();
+    }
+
+    @Test
+    public void testAlternateBouncerToShowPrimaryBouncer_updatesScrimControllerOnce() {
+        // GIVEN the alternate bouncer has shown and calls to hide()  will result in successfully
+        // hiding it
+        when(mAlternateBouncerInteractor.hide()).thenReturn(true);
+        when(mKeyguardStateController.isShowing()).thenReturn(true);
+        when(mPrimaryBouncerInteractor.isFullyShowing()).thenReturn(false);
+        when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(false);
+
+        // WHEN request to show primary bouncer
+        mStatusBarKeyguardViewManager.showPrimaryBouncer(true);
+
+        // THEN the scrim isn't updated from StatusBarKeyguardViewManager
+        verify(mCentralSurfaces, never()).updateScrimController();
+    }
+
+    @Test
+    public void testAlternateBouncerOnTouch_actionDownThenUp_noMinTimeShown_noHideAltBouncer() {
+        reset(mAlternateBouncerInteractor);
+
+        // GIVEN the alternate bouncer has shown for a minimum amount of time
+        when(mAlternateBouncerInteractor.hasAlternateBouncerShownWithMinTime()).thenReturn(false);
+        when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
+
+        // WHEN ACTION_DOWN and ACTION_UP touch event comes
+        boolean touchHandledDown = mStatusBarKeyguardViewManager.onTouch(
+                MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0));
+        boolean touchHandledUp = mStatusBarKeyguardViewManager.onTouch(
+                MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 0f, 0f, 0));
+
+        // THEN the touches are handled (doesn't let touches through to underlying views)
+        assertTrue(touchHandledDown);
+        assertTrue(touchHandledUp);
+
+        // THEN alternate bouncer does NOT attempt to hide since min showing time wasn't met
+        verify(mAlternateBouncerInteractor, never()).hide();
+    }
+
+    @Test
+    public void testAlternateBouncerOnTouch_actionDownThenUp_handlesTouch_hidesAltBouncer() {
+        reset(mAlternateBouncerInteractor);
+
+        // GIVEN the alternate bouncer has shown for a minimum amount of time
+        when(mAlternateBouncerInteractor.hasAlternateBouncerShownWithMinTime()).thenReturn(true);
+        when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
+
+        // WHEN ACTION_DOWN and ACTION_UP touch event comes
+        boolean touchHandledDown = mStatusBarKeyguardViewManager.onTouch(
+                MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0));
+        boolean touchHandledUp = mStatusBarKeyguardViewManager.onTouch(
+                MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 0f, 0f, 0));
+
+        // THEN the touches are handled
+        assertTrue(touchHandledDown);
+        assertTrue(touchHandledUp);
+
+        // THEN alternate bouncer attempts to hide
+        verify(mAlternateBouncerInteractor).hide();
+    }
+
+    @Test
+    public void testAlternateBouncerOnTouch_actionUp_doesNotHideAlternateBouncer() {
+        reset(mAlternateBouncerInteractor);
+
+        // GIVEN the alternate bouncer has shown for a minimum amount of time
+        when(mAlternateBouncerInteractor.hasAlternateBouncerShownWithMinTime()).thenReturn(true);
+        when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
+
+        // WHEN only ACTION_UP touch event comes
+        mStatusBarKeyguardViewManager.onTouch(
+                MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 0f, 0f, 0));
+
+        // THEN the alternateBouncer doesn't hide
+        verify(mAlternateBouncerInteractor, never()).hide();
+    }
+
+    @Test
+    public void testAlternateBouncerOnTouch_actionOutside_hidesAlternateBouncer() {
+        reset(mAlternateBouncerInteractor);
+
+        // GIVEN the alternate bouncer has shown for a minimum amount of time
+        when(mAlternateBouncerInteractor.hasAlternateBouncerShownWithMinTime()).thenReturn(true);
+        when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
+
+        // WHEN only ACTION_OUTSIDE touch event comes
+        mStatusBarKeyguardViewManager.onTouch(
+                MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_OUTSIDE, 0f, 0f, 0));
+
+        // THEN the alternateBouncer hides
+        verify(mAlternateBouncerInteractor).hide();
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationControllerTest.kt
index 1779de7..7594c90 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationControllerTest.kt
@@ -8,13 +8,14 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.unfold.TestUnfoldTransitionProvider
+import com.android.systemui.unfold.util.CurrentActivityTypeProvider
 import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider
+import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
 import org.junit.Test
 import org.mockito.ArgumentMatchers.any
 import org.mockito.Mock
-import org.mockito.Mockito.`when`
 import org.mockito.MockitoAnnotations
 
 @SmallTest
@@ -26,6 +27,9 @@
     @Mock
     private lateinit var display: Display
 
+    @Mock
+    private lateinit var currentActivityTypeProvider: CurrentActivityTypeProvider
+
     private val view: View = View(context)
     private val progressProvider = TestUnfoldTransitionProvider()
     private val scopedProvider = ScopedUnfoldTransitionProgressProvider(progressProvider)
@@ -36,9 +40,9 @@
     fun setUp() {
         MockitoAnnotations.initMocks(this)
 
-        `when`(windowManager.defaultDisplay).thenReturn(display)
-        `when`(display.rotation).thenReturn(Surface.ROTATION_0)
-        `when`(display.getSize(any())).thenAnswer {
+        whenever(windowManager.defaultDisplay).thenReturn(display)
+        whenever(display.rotation).thenReturn(Surface.ROTATION_0)
+        whenever(display.getSize(any())).thenAnswer {
             val point = it.arguments[0] as Point
             point.x = 100
             point.y = 100
@@ -47,7 +51,12 @@
 
         scopedProvider.setReadyToHandleTransition(true)
 
-        controller = StatusBarMoveFromCenterAnimationController(scopedProvider, windowManager)
+        controller =
+            StatusBarMoveFromCenterAnimationController(
+                scopedProvider,
+                currentActivityTypeProvider,
+                windowManager
+            )
     }
 
     @Test
@@ -99,6 +108,31 @@
     }
 
     @Test
+    fun alpha_onLauncher_alphaDoesNotChange() {
+        whenever(currentActivityTypeProvider.isHomeActivity).thenReturn(true)
+        controller.onViewsReady(arrayOf(view))
+        progressProvider.onTransitionStarted()
+        progressProvider.onTransitionProgress(0.0f)
+        assertThat(view.alpha).isEqualTo(1.0f)
+
+        progressProvider.onTransitionProgress(1.0f)
+
+        assertThat(view.alpha).isEqualTo(1.0f)
+    }
+
+    @Test
+    fun alpha_NotOnLauncher_alphaChanges() {
+        whenever(currentActivityTypeProvider.isHomeActivity).thenReturn(false)
+        controller.onViewsReady(arrayOf(view))
+        progressProvider.onTransitionStarted()
+        assertThat(view.alpha).isEqualTo(1.0f)
+
+        progressProvider.onTransitionProgress(0.5f)
+
+        assertThat(view.alpha).isNotEqualTo(1.0f)
+    }
+
+    @Test
     fun transitionFinished_viewReAttached_noChangesToTranslation() {
         controller.onViewsReady(arrayOf(view))
         progressProvider.onTransitionProgress(0.5f)
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 ccc57ad..ee7e082 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
@@ -18,6 +18,9 @@
 
 import static android.service.notification.NotificationListenerService.REASON_CLICK;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+
 import static org.mockito.AdditionalAnswers.answerVoid;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -28,7 +31,6 @@
 import static org.mockito.Mockito.doAnswer;
 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.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
@@ -38,6 +40,8 @@
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ResolveInfo;
 import android.os.Handler;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -51,6 +55,7 @@
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.statusbar.NotificationVisibility;
+import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.systemui.ActivityIntentHelper;
 import com.android.systemui.SysuiTestCase;
@@ -90,9 +95,12 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
 import org.mockito.stubbing.Answer;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Optional;
 
@@ -398,4 +406,40 @@
         // THEN display should try wake up for the full screen intent
         verify(mCentralSurfaces).wakeUpForFullScreenIntent();
     }
+
+    @Test
+    public void testOnFullScreenIntentWhenDozing_logToStatsd() {
+        final int kTestUid = 12345;
+        final String kTestActivityName = "TestActivity";
+        // GIVEN entry that can has a full screen intent that can show
+        PendingIntent mockFullScreenIntent = mock(PendingIntent.class);
+        when(mockFullScreenIntent.getCreatorUid()).thenReturn(kTestUid);
+        ResolveInfo resolveInfo = new ResolveInfo();
+        resolveInfo.activityInfo = new ActivityInfo();
+        resolveInfo.activityInfo.name = kTestActivityName;
+        when(mockFullScreenIntent.queryIntentComponents(anyInt()))
+                .thenReturn(Arrays.asList(resolveInfo));
+        Notification.Builder nb = new Notification.Builder(mContext, "a")
+                .setContentTitle("foo")
+                .setSmallIcon(android.R.drawable.sym_def_app_icon)
+                .setFullScreenIntent(mockFullScreenIntent, true);
+        StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0,
+                "tag" + System.currentTimeMillis(), 0, 0,
+                nb.build(), new UserHandle(0), null, 0);
+        NotificationEntry entry = mock(NotificationEntry.class);
+        when(entry.getImportance()).thenReturn(NotificationManager.IMPORTANCE_HIGH);
+        when(entry.getSbn()).thenReturn(sbn);
+        MockitoSession mockingSession = mockitoSession()
+                .mockStatic(FrameworkStatsLog.class)
+                .strictness(Strictness.LENIENT)
+                .startMocking();
+
+        // WHEN
+        mNotificationActivityStarter.launchFullScreenIntent(entry);
+
+        // THEN the full screen intent should be logged to statsd.
+        verify(() -> FrameworkStatsLog.write(FrameworkStatsLog.FULL_SCREEN_INTENT_LAUNCHED,
+                kTestUid, kTestActivityName));
+        mockingSession.finishMocking();
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index 1e5782b..49c50d6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -294,6 +294,13 @@
     }
 
     @Test
+    public void userChip_defaultVisibilityIsGone() {
+        CollapsedStatusBarFragment fragment = resumeAndGetFragment();
+
+        assertEquals(View.GONE, getUserChipView().getVisibility());
+    }
+
+    @Test
     public void disable_noOngoingCall_chipHidden() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
@@ -333,6 +340,19 @@
     }
 
     @Test
+    public void disable_hasOngoingCallButAlsoHun_chipHidden() {
+        CollapsedStatusBarFragment fragment = resumeAndGetFragment();
+
+        when(mOngoingCallController.hasOngoingCall()).thenReturn(true);
+        when(mHeadsUpAppearanceController.shouldBeVisible()).thenReturn(true);
+
+        fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
+
+        assertEquals(View.GONE,
+                mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility());
+    }
+
+    @Test
     public void disable_ongoingCallEnded_chipHidden() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
@@ -558,6 +578,10 @@
         return (CollapsedStatusBarFragment) mFragment;
     }
 
+    private View getUserChipView() {
+        return mFragment.getView().findViewById(R.id.user_switcher_container);
+    }
+
     private View getClockView() {
         return mFragment.getView().findViewById(R.id.clock);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/shared/MobileInputLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLoggerTest.kt
similarity index 91%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/shared/MobileInputLoggerTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLoggerTest.kt
index 86529dc..7c9351c8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/shared/MobileInputLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLoggerTest.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.pipeline.mobile.shared
+package com.android.systemui.statusbar.pipeline.mobile.data
 
 import android.net.Network
 import android.net.NetworkCapabilities
@@ -47,14 +47,14 @@
         val expectedNetId = NET_1_ID.toString()
         val expectedCaps = NET_1_CAPS.toString()
 
-        assertThat(actualString).contains("true")
+        assertThat(actualString).contains("onDefaultCapabilitiesChanged")
         assertThat(actualString).contains(expectedNetId)
         assertThat(actualString).contains(expectedCaps)
     }
 
     @Test
     fun testLogOnLost_bufferHasNetIdOfLostNetwork() {
-        logger.logOnLost(NET_1)
+        logger.logOnLost(NET_1, isDefaultNetworkCallback = false)
 
         val stringWriter = StringWriter()
         buffer.dump(PrintWriter(stringWriter), tailLength = 0)
@@ -62,6 +62,7 @@
 
         val expectedNetId = NET_1_ID.toString()
 
+        assertThat(actualString).contains("onLost")
         assertThat(actualString).contains(expectedNetId)
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileConnectionModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileConnectionModelTest.kt
deleted file mode 100644
index 45189cf..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileConnectionModelTest.kt
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.pipeline.mobile.data.model
-
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.log.table.TableRowLogger
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_ACTIVITY_DIRECTION_IN
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_ACTIVITY_DIRECTION_OUT
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_CARRIER_NETWORK_CHANGE
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_CDMA_LEVEL
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_CONNECTION_STATE
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_EMERGENCY
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_IS_GSM
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_OPERATOR
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_PRIMARY_LEVEL
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_RESOLVED_NETWORK_TYPE
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_ROAMING
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-
-@SmallTest
-class MobileConnectionModelTest : SysuiTestCase() {
-
-    @Test
-    fun `log diff - initial log contains all columns`() {
-        val logger = TestLogger()
-        val connection = MobileConnectionModel()
-
-        connection.logFull(logger)
-
-        assertThat(logger.changes)
-            .contains(Pair(COL_EMERGENCY, connection.isEmergencyOnly.toString()))
-        assertThat(logger.changes).contains(Pair(COL_ROAMING, connection.isRoaming.toString()))
-        assertThat(logger.changes)
-            .contains(Pair(COL_OPERATOR, connection.operatorAlphaShort.toString()))
-        assertThat(logger.changes).contains(Pair(COL_IS_GSM, connection.isGsm.toString()))
-        assertThat(logger.changes).contains(Pair(COL_CDMA_LEVEL, connection.cdmaLevel.toString()))
-        assertThat(logger.changes)
-            .contains(Pair(COL_PRIMARY_LEVEL, connection.primaryLevel.toString()))
-        assertThat(logger.changes)
-            .contains(Pair(COL_CONNECTION_STATE, connection.dataConnectionState.toString()))
-        assertThat(logger.changes)
-            .contains(
-                Pair(
-                    COL_ACTIVITY_DIRECTION_IN,
-                    connection.dataActivityDirection.hasActivityIn.toString(),
-                )
-            )
-        assertThat(logger.changes)
-            .contains(
-                Pair(
-                    COL_ACTIVITY_DIRECTION_OUT,
-                    connection.dataActivityDirection.hasActivityOut.toString(),
-                )
-            )
-        assertThat(logger.changes)
-            .contains(
-                Pair(COL_CARRIER_NETWORK_CHANGE, connection.carrierNetworkChangeActive.toString())
-            )
-        assertThat(logger.changes)
-            .contains(Pair(COL_RESOLVED_NETWORK_TYPE, connection.resolvedNetworkType.toString()))
-    }
-
-    @Test
-    fun `log diff - primary level changes - only level is logged`() {
-        val logger = TestLogger()
-        val connectionOld = MobileConnectionModel(primaryLevel = 1)
-
-        val connectionNew = MobileConnectionModel(primaryLevel = 2)
-
-        connectionNew.logDiffs(connectionOld, logger)
-
-        assertThat(logger.changes).isEqualTo(listOf(Pair(COL_PRIMARY_LEVEL, "2")))
-    }
-
-    private class TestLogger : TableRowLogger {
-        val changes = mutableListOf<Pair<String, String>>()
-
-        override fun logChange(columnName: String, value: String?) {
-            changes.add(Pair(columnName, value.toString()))
-        }
-
-        override fun logChange(columnName: String, value: Int) {
-            changes.add(Pair(columnName, value.toString()))
-        }
-
-        override fun logChange(columnName: String, value: Boolean) {
-            changes.add(Pair(columnName, value.toString()))
-        }
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt
index 0145103..dfef62e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt
@@ -24,8 +24,8 @@
 import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfigTest.Companion.createTestConfig
-import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger
 import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt
index 53cd71f1..44fbd5b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt
@@ -17,9 +17,11 @@
 package com.android.systemui.statusbar.pipeline.mobile.data.repository
 
 import com.android.systemui.log.table.TableLogBuffer
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
 import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
+import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
 import kotlinx.coroutines.flow.MutableStateFlow
 
 // TODO(b/261632894): remove this in favor of the real impl or DemoMobileConnectionRepository
@@ -27,8 +29,19 @@
     override val subId: Int,
     override val tableLogBuffer: TableLogBuffer,
 ) : MobileConnectionRepository {
-    private val _connectionInfo = MutableStateFlow(MobileConnectionModel())
-    override val connectionInfo = _connectionInfo
+    override val isEmergencyOnly = MutableStateFlow(false)
+    override val isRoaming = MutableStateFlow(false)
+    override val operatorAlphaShort: MutableStateFlow<String?> = MutableStateFlow(null)
+    override val isInService = MutableStateFlow(false)
+    override val isGsm = MutableStateFlow(false)
+    override val cdmaLevel = MutableStateFlow(0)
+    override val primaryLevel = MutableStateFlow(0)
+    override val dataConnectionState = MutableStateFlow(DataConnectionState.Disconnected)
+    override val dataActivityDirection =
+        MutableStateFlow(DataActivityModel(hasActivityIn = false, hasActivityOut = false))
+    override val carrierNetworkChangeActive = MutableStateFlow(false)
+    override val resolvedNetworkType: MutableStateFlow<ResolvedNetworkType> =
+        MutableStateFlow(ResolvedNetworkType.UnknownNetworkType)
 
     override val numberOfLevels = MutableStateFlow(DEFAULT_NUM_LEVELS)
 
@@ -40,10 +53,6 @@
     override val networkName =
         MutableStateFlow<NetworkNameModel>(NetworkNameModel.Default("default"))
 
-    fun setConnectionInfo(model: MobileConnectionModel) {
-        _connectionInfo.value = model
-    }
-
     fun setDataEnabled(enabled: Boolean) {
         _dataEnabled.value = enabled
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
index 17502f2..07c8cee 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
@@ -27,13 +27,13 @@
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.log.table.TableLogBuffer
 import com.android.systemui.log.table.TableLogBufferFactory
+import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.DemoMobileConnectionsRepository
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.DemoModeMobileConnectionDataSource
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.validMobileEvent
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileConnectionsRepositoryImpl
-import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger
 import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoModeWifiDataSource
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt
index b072dee..37fac34 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt
@@ -25,7 +25,6 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.log.table.TableLogBufferFactory
 import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
 import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
 import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
@@ -36,8 +35,11 @@
 import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.Job
 import kotlinx.coroutines.cancel
 import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.launch
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import kotlinx.coroutines.test.runTest
@@ -123,34 +125,49 @@
             assertConnection(underTest, networkModel)
         }
 
-    private fun assertConnection(
+    private fun TestScope.startCollection(conn: DemoMobileConnectionRepository): Job {
+        val job = launch {
+            launch { conn.cdmaLevel.collect {} }
+            launch { conn.primaryLevel.collect {} }
+            launch { conn.dataActivityDirection.collect {} }
+            launch { conn.carrierNetworkChangeActive.collect {} }
+            launch { conn.isRoaming.collect {} }
+            launch { conn.networkName.collect {} }
+            launch { conn.isEmergencyOnly.collect {} }
+            launch { conn.dataConnectionState.collect {} }
+        }
+        return job
+    }
+
+    private fun TestScope.assertConnection(
         conn: DemoMobileConnectionRepository,
         model: FakeNetworkEventModel
     ) {
+        val job = startCollection(underTest)
         when (model) {
             is FakeNetworkEventModel.Mobile -> {
-                val connectionInfo: MobileConnectionModel = conn.connectionInfo.value
                 assertThat(conn.subId).isEqualTo(model.subId)
-                assertThat(connectionInfo.cdmaLevel).isEqualTo(model.level)
-                assertThat(connectionInfo.primaryLevel).isEqualTo(model.level)
-                assertThat(connectionInfo.dataActivityDirection)
+                assertThat(conn.cdmaLevel.value).isEqualTo(model.level)
+                assertThat(conn.primaryLevel.value).isEqualTo(model.level)
+                assertThat(conn.dataActivityDirection.value)
                     .isEqualTo((model.activity ?: DATA_ACTIVITY_NONE).toMobileDataActivityModel())
-                assertThat(connectionInfo.carrierNetworkChangeActive)
+                assertThat(conn.carrierNetworkChangeActive.value)
                     .isEqualTo(model.carrierNetworkChange)
-                assertThat(connectionInfo.isRoaming).isEqualTo(model.roaming)
+                assertThat(conn.isRoaming.value).isEqualTo(model.roaming)
                 assertThat(conn.networkName.value)
                     .isEqualTo(NetworkNameModel.IntentDerived(model.name))
 
                 // TODO(b/261029387): check these once we start handling them
-                assertThat(connectionInfo.isEmergencyOnly).isFalse()
-                assertThat(connectionInfo.isGsm).isFalse()
-                assertThat(connectionInfo.dataConnectionState)
-                    .isEqualTo(DataConnectionState.Connected)
+                assertThat(conn.isEmergencyOnly.value).isFalse()
+                assertThat(conn.isGsm.value).isFalse()
+                assertThat(conn.dataConnectionState.value).isEqualTo(DataConnectionState.Connected)
             }
             // MobileDisabled isn't combinatorial in nature, and is tested in
             // DemoMobileConnectionsRepositoryTest.kt
             else -> {}
         }
+
+        job.cancel()
     }
 
     /** Matches [FakeNetworkEventModel] */
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
index f60d92b..0e45d8e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
@@ -26,7 +26,6 @@
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.log.table.TableLogBufferFactory
 import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
 import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
@@ -40,9 +39,11 @@
 import com.google.common.truth.Truth.assertThat
 import junit.framework.Assert
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.Job
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.launch
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import kotlinx.coroutines.test.runTest
@@ -524,47 +525,65 @@
             job.cancel()
         }
 
-    private fun assertConnection(
+    private fun TestScope.startCollection(conn: DemoMobileConnectionRepository): Job {
+        val job = launch {
+            launch { conn.cdmaLevel.collect {} }
+            launch { conn.primaryLevel.collect {} }
+            launch { conn.dataActivityDirection.collect {} }
+            launch { conn.carrierNetworkChangeActive.collect {} }
+            launch { conn.isRoaming.collect {} }
+            launch { conn.networkName.collect {} }
+            launch { conn.isEmergencyOnly.collect {} }
+            launch { conn.dataConnectionState.collect {} }
+        }
+        return job
+    }
+
+    private fun TestScope.assertConnection(
         conn: DemoMobileConnectionRepository,
-        model: FakeNetworkEventModel
+        model: FakeNetworkEventModel,
     ) {
+        val job = startCollection(conn)
+        // Assert the fields using the `MutableStateFlow` so that we don't have to start up
+        // a collector for every field for every test
         when (model) {
             is FakeNetworkEventModel.Mobile -> {
-                val connectionInfo: MobileConnectionModel = conn.connectionInfo.value
                 assertThat(conn.subId).isEqualTo(model.subId)
-                assertThat(connectionInfo.cdmaLevel).isEqualTo(model.level)
-                assertThat(connectionInfo.primaryLevel).isEqualTo(model.level)
-                assertThat(connectionInfo.dataActivityDirection)
+                assertThat(conn.cdmaLevel.value).isEqualTo(model.level)
+                assertThat(conn.primaryLevel.value).isEqualTo(model.level)
+                assertThat(conn.dataActivityDirection.value)
                     .isEqualTo((model.activity ?: DATA_ACTIVITY_NONE).toMobileDataActivityModel())
-                assertThat(connectionInfo.carrierNetworkChangeActive)
+                assertThat(conn.carrierNetworkChangeActive.value)
                     .isEqualTo(model.carrierNetworkChange)
-                assertThat(connectionInfo.isRoaming).isEqualTo(model.roaming)
+                assertThat(conn.isRoaming.value).isEqualTo(model.roaming)
                 assertThat(conn.networkName.value)
                     .isEqualTo(NetworkNameModel.IntentDerived(model.name))
 
                 // TODO(b/261029387) check these once we start handling them
-                assertThat(connectionInfo.isEmergencyOnly).isFalse()
-                assertThat(connectionInfo.isGsm).isFalse()
-                assertThat(connectionInfo.dataConnectionState)
-                    .isEqualTo(DataConnectionState.Connected)
+                assertThat(conn.isEmergencyOnly.value).isFalse()
+                assertThat(conn.isGsm.value).isFalse()
+                assertThat(conn.dataConnectionState.value).isEqualTo(DataConnectionState.Connected)
             }
             else -> {}
         }
+
+        job.cancel()
     }
 
-    private fun assertCarrierMergedConnection(
+    private fun TestScope.assertCarrierMergedConnection(
         conn: DemoMobileConnectionRepository,
         model: FakeWifiEventModel.CarrierMerged,
     ) {
-        val connectionInfo: MobileConnectionModel = conn.connectionInfo.value
+        val job = startCollection(conn)
         assertThat(conn.subId).isEqualTo(model.subscriptionId)
-        assertThat(connectionInfo.cdmaLevel).isEqualTo(model.level)
-        assertThat(connectionInfo.primaryLevel).isEqualTo(model.level)
-        assertThat(connectionInfo.carrierNetworkChangeActive).isEqualTo(false)
-        assertThat(connectionInfo.isRoaming).isEqualTo(false)
-        assertThat(connectionInfo.isEmergencyOnly).isFalse()
-        assertThat(connectionInfo.isGsm).isFalse()
-        assertThat(connectionInfo.dataConnectionState).isEqualTo(DataConnectionState.Connected)
+        assertThat(conn.cdmaLevel.value).isEqualTo(model.level)
+        assertThat(conn.primaryLevel.value).isEqualTo(model.level)
+        assertThat(conn.carrierNetworkChangeActive.value).isEqualTo(false)
+        assertThat(conn.isRoaming.value).isEqualTo(false)
+        assertThat(conn.isEmergencyOnly.value).isFalse()
+        assertThat(conn.isGsm.value).isFalse()
+        assertThat(conn.dataConnectionState.value).isEqualTo(DataConnectionState.Connected)
+        job.cancel()
     }
 }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt
index f0f213b..441186a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt
@@ -22,7 +22,6 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.log.table.TableLogBuffer
 import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
 import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
 import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
@@ -75,36 +74,48 @@
     }
 
     @Test
-    fun connectionInfo_inactiveWifi_isDefault() =
+    fun inactiveWifi_isDefault() =
         testScope.runTest {
-            var latest: MobileConnectionModel? = null
-            val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+            var latestConnState: DataConnectionState? = null
+            var latestNetType: ResolvedNetworkType? = null
+
+            val dataJob =
+                underTest.dataConnectionState.onEach { latestConnState = it }.launchIn(this)
+            val netJob = underTest.resolvedNetworkType.onEach { latestNetType = it }.launchIn(this)
 
             wifiRepository.setWifiNetwork(WifiNetworkModel.Inactive)
 
-            assertThat(latest).isEqualTo(MobileConnectionModel())
+            assertThat(latestConnState).isEqualTo(DataConnectionState.Disconnected)
+            assertThat(latestNetType).isNotEqualTo(ResolvedNetworkType.CarrierMergedNetworkType)
 
-            job.cancel()
+            dataJob.cancel()
+            netJob.cancel()
         }
 
     @Test
-    fun connectionInfo_activeWifi_isDefault() =
+    fun activeWifi_isDefault() =
         testScope.runTest {
-            var latest: MobileConnectionModel? = null
-            val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+            var latestConnState: DataConnectionState? = null
+            var latestNetType: ResolvedNetworkType? = null
+
+            val dataJob =
+                underTest.dataConnectionState.onEach { latestConnState = it }.launchIn(this)
+            val netJob = underTest.resolvedNetworkType.onEach { latestNetType = it }.launchIn(this)
 
             wifiRepository.setWifiNetwork(WifiNetworkModel.Active(networkId = NET_ID, level = 1))
 
-            assertThat(latest).isEqualTo(MobileConnectionModel())
+            assertThat(latestConnState).isEqualTo(DataConnectionState.Disconnected)
+            assertThat(latestNetType).isNotEqualTo(ResolvedNetworkType.CarrierMergedNetworkType)
 
-            job.cancel()
+            dataJob.cancel()
+            netJob.cancel()
         }
 
     @Test
-    fun connectionInfo_carrierMergedWifi_isValidAndFieldsComeFromWifiNetwork() =
+    fun carrierMergedWifi_isValidAndFieldsComeFromWifiNetwork() =
         testScope.runTest {
-            var latest: MobileConnectionModel? = null
-            val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+            var latest: Int? = null
+            val job = underTest.primaryLevel.onEach { latest = it }.launchIn(this)
 
             wifiRepository.setIsWifiEnabled(true)
             wifiRepository.setIsWifiDefault(true)
@@ -117,34 +128,16 @@
                 )
             )
 
-            val expected =
-                MobileConnectionModel(
-                    primaryLevel = 3,
-                    cdmaLevel = 3,
-                    dataConnectionState = DataConnectionState.Connected,
-                    dataActivityDirection =
-                        DataActivityModel(
-                            hasActivityIn = false,
-                            hasActivityOut = false,
-                        ),
-                    resolvedNetworkType = ResolvedNetworkType.CarrierMergedNetworkType,
-                    isRoaming = false,
-                    isEmergencyOnly = false,
-                    operatorAlphaShort = null,
-                    isInService = true,
-                    isGsm = false,
-                    carrierNetworkChangeActive = false,
-                )
-            assertThat(latest).isEqualTo(expected)
+            assertThat(latest).isEqualTo(3)
 
             job.cancel()
         }
 
     @Test
-    fun connectionInfo_activity_comesFromWifiActivity() =
+    fun activity_comesFromWifiActivity() =
         testScope.runTest {
-            var latest: MobileConnectionModel? = null
-            val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+            var latest: DataActivityModel? = null
+            val job = underTest.dataActivityDirection.onEach { latest = it }.launchIn(this)
 
             wifiRepository.setIsWifiEnabled(true)
             wifiRepository.setIsWifiDefault(true)
@@ -162,8 +155,8 @@
                 )
             )
 
-            assertThat(latest!!.dataActivityDirection.hasActivityIn).isTrue()
-            assertThat(latest!!.dataActivityDirection.hasActivityOut).isFalse()
+            assertThat(latest!!.hasActivityIn).isTrue()
+            assertThat(latest!!.hasActivityOut).isFalse()
 
             wifiRepository.setWifiActivity(
                 DataActivityModel(
@@ -172,17 +165,19 @@
                 )
             )
 
-            assertThat(latest!!.dataActivityDirection.hasActivityIn).isFalse()
-            assertThat(latest!!.dataActivityDirection.hasActivityOut).isTrue()
+            assertThat(latest!!.hasActivityIn).isFalse()
+            assertThat(latest!!.hasActivityOut).isTrue()
 
             job.cancel()
         }
 
     @Test
-    fun connectionInfo_carrierMergedWifi_wrongSubId_isDefault() =
+    fun carrierMergedWifi_wrongSubId_isDefault() =
         testScope.runTest {
-            var latest: MobileConnectionModel? = null
-            val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+            var latestLevel: Int? = null
+            var latestType: ResolvedNetworkType? = null
+            val levelJob = underTest.primaryLevel.onEach { latestLevel = it }.launchIn(this)
+            val typeJob = underTest.resolvedNetworkType.onEach { latestType = it }.launchIn(this)
 
             wifiRepository.setWifiNetwork(
                 WifiNetworkModel.CarrierMerged(
@@ -192,20 +187,19 @@
                 )
             )
 
-            assertThat(latest).isEqualTo(MobileConnectionModel())
-            assertThat(latest!!.primaryLevel).isNotEqualTo(3)
-            assertThat(latest!!.resolvedNetworkType)
-                .isNotEqualTo(ResolvedNetworkType.CarrierMergedNetworkType)
+            assertThat(latestLevel).isNotEqualTo(3)
+            assertThat(latestType).isNotEqualTo(ResolvedNetworkType.CarrierMergedNetworkType)
 
-            job.cancel()
+            levelJob.cancel()
+            typeJob.cancel()
         }
 
     // This scenario likely isn't possible, but write a test for it anyway
     @Test
-    fun connectionInfo_carrierMergedButNotEnabled_isDefault() =
+    fun carrierMergedButNotEnabled_isDefault() =
         testScope.runTest {
-            var latest: MobileConnectionModel? = null
-            val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+            var latest: Int? = null
+            val job = underTest.primaryLevel.onEach { latest = it }.launchIn(this)
 
             wifiRepository.setWifiNetwork(
                 WifiNetworkModel.CarrierMerged(
@@ -216,17 +210,17 @@
             )
             wifiRepository.setIsWifiEnabled(false)
 
-            assertThat(latest).isEqualTo(MobileConnectionModel())
+            assertThat(latest).isNotEqualTo(3)
 
             job.cancel()
         }
 
     // This scenario likely isn't possible, but write a test for it anyway
     @Test
-    fun connectionInfo_carrierMergedButWifiNotDefault_isDefault() =
+    fun carrierMergedButWifiNotDefault_isDefault() =
         testScope.runTest {
-            var latest: MobileConnectionModel? = null
-            val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+            var latest: Int? = null
+            val job = underTest.primaryLevel.onEach { latest = it }.launchIn(this)
 
             wifiRepository.setWifiNetwork(
                 WifiNetworkModel.CarrierMerged(
@@ -237,7 +231,7 @@
             )
             wifiRepository.setIsWifiDefault(false)
 
-            assertThat(latest).isEqualTo(MobileConnectionModel())
+            assertThat(latest).isNotEqualTo(3)
 
             job.cancel()
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
index cd4d847..db5a7d1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
@@ -24,13 +24,12 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.log.table.TableLogBuffer
 import com.android.systemui.log.table.TableLogBufferFactory
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_EMERGENCY
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_OPERATOR
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel.Companion.COL_PRIMARY_LEVEL
 import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_EMERGENCY
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_OPERATOR
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_PRIMARY_LEVEL
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.getTelephonyCallbackForType
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
 import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
@@ -94,16 +93,16 @@
     @Test
     fun startingIsCarrierMerged_usesCarrierMergedInitially() =
         testScope.runTest {
-            val carrierMergedConnectionInfo =
-                MobileConnectionModel(
-                    operatorAlphaShort = "Carrier Merged Operator",
-                )
-            carrierMergedRepo.setConnectionInfo(carrierMergedConnectionInfo)
+            val carrierMergedOperatorName = "Carrier Merged Operator"
+            val nonCarrierMergedName = "Non-carrier-merged"
+
+            carrierMergedRepo.operatorAlphaShort.value = carrierMergedOperatorName
+            mobileRepo.operatorAlphaShort.value = nonCarrierMergedName
 
             initializeRepo(startingIsCarrierMerged = true)
 
             assertThat(underTest.activeRepo.value).isEqualTo(carrierMergedRepo)
-            assertThat(underTest.connectionInfo.value).isEqualTo(carrierMergedConnectionInfo)
+            assertThat(underTest.operatorAlphaShort.value).isEqualTo(carrierMergedOperatorName)
             verify(mobileFactory, never())
                 .build(
                     SUB_ID,
@@ -116,16 +115,16 @@
     @Test
     fun startingNotCarrierMerged_usesTypicalInitially() =
         testScope.runTest {
-            val mobileConnectionInfo =
-                MobileConnectionModel(
-                    operatorAlphaShort = "Typical Operator",
-                )
-            mobileRepo.setConnectionInfo(mobileConnectionInfo)
+            val carrierMergedOperatorName = "Carrier Merged Operator"
+            val nonCarrierMergedName = "Typical Operator"
+
+            carrierMergedRepo.operatorAlphaShort.value = carrierMergedOperatorName
+            mobileRepo.operatorAlphaShort.value = nonCarrierMergedName
 
             initializeRepo(startingIsCarrierMerged = false)
 
             assertThat(underTest.activeRepo.value).isEqualTo(mobileRepo)
-            assertThat(underTest.connectionInfo.value).isEqualTo(mobileConnectionInfo)
+            assertThat(underTest.operatorAlphaShort.value).isEqualTo(nonCarrierMergedName)
             verify(carrierMergedFactory, never()).build(SUB_ID, tableLogBuffer)
         }
 
@@ -156,39 +155,40 @@
         testScope.runTest {
             initializeRepo(startingIsCarrierMerged = false)
 
-            var latest: MobileConnectionModel? = null
-            val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+            var latestName: String? = null
+            var latestLevel: Int? = null
+
+            val nameJob = underTest.operatorAlphaShort.onEach { latestName = it }.launchIn(this)
+            val levelJob = underTest.primaryLevel.onEach { latestLevel = it }.launchIn(this)
 
             underTest.setIsCarrierMerged(true)
 
-            val info1 =
-                MobileConnectionModel(
-                    operatorAlphaShort = "Carrier Merged Operator",
-                    primaryLevel = 1,
-                )
-            carrierMergedRepo.setConnectionInfo(info1)
+            val operator1 = "Carrier Merged Operator"
+            val level1 = 1
+            carrierMergedRepo.operatorAlphaShort.value = operator1
+            carrierMergedRepo.primaryLevel.value = level1
 
-            assertThat(latest).isEqualTo(info1)
+            assertThat(latestName).isEqualTo(operator1)
+            assertThat(latestLevel).isEqualTo(level1)
 
-            val info2 =
-                MobileConnectionModel(
-                    operatorAlphaShort = "Carrier Merged Operator #2",
-                    primaryLevel = 2,
-                )
-            carrierMergedRepo.setConnectionInfo(info2)
+            val operator2 = "Carrier Merged Operator #2"
+            val level2 = 2
+            carrierMergedRepo.operatorAlphaShort.value = operator2
+            carrierMergedRepo.primaryLevel.value = level2
 
-            assertThat(latest).isEqualTo(info2)
+            assertThat(latestName).isEqualTo(operator2)
+            assertThat(latestLevel).isEqualTo(level2)
 
-            val info3 =
-                MobileConnectionModel(
-                    operatorAlphaShort = "Carrier Merged Operator #3",
-                    primaryLevel = 3,
-                )
-            carrierMergedRepo.setConnectionInfo(info3)
+            val operator3 = "Carrier Merged Operator #3"
+            val level3 = 3
+            carrierMergedRepo.operatorAlphaShort.value = operator3
+            carrierMergedRepo.primaryLevel.value = level3
 
-            assertThat(latest).isEqualTo(info3)
+            assertThat(latestName).isEqualTo(operator3)
+            assertThat(latestLevel).isEqualTo(level3)
 
-            job.cancel()
+            nameJob.cancel()
+            levelJob.cancel()
         }
 
     @Test
@@ -196,39 +196,40 @@
         testScope.runTest {
             initializeRepo(startingIsCarrierMerged = false)
 
-            var latest: MobileConnectionModel? = null
-            val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+            var latestName: String? = null
+            var latestLevel: Int? = null
+
+            val nameJob = underTest.operatorAlphaShort.onEach { latestName = it }.launchIn(this)
+            val levelJob = underTest.primaryLevel.onEach { latestLevel = it }.launchIn(this)
 
             underTest.setIsCarrierMerged(false)
 
-            val info1 =
-                MobileConnectionModel(
-                    operatorAlphaShort = "Typical Merged Operator",
-                    primaryLevel = 1,
-                )
-            mobileRepo.setConnectionInfo(info1)
+            val operator1 = "Typical Merged Operator"
+            val level1 = 1
+            mobileRepo.operatorAlphaShort.value = operator1
+            mobileRepo.primaryLevel.value = level1
 
-            assertThat(latest).isEqualTo(info1)
+            assertThat(latestName).isEqualTo(operator1)
+            assertThat(latestLevel).isEqualTo(level1)
 
-            val info2 =
-                MobileConnectionModel(
-                    operatorAlphaShort = "Typical Merged Operator #2",
-                    primaryLevel = 2,
-                )
-            mobileRepo.setConnectionInfo(info2)
+            val operator2 = "Typical Merged Operator #2"
+            val level2 = 2
+            mobileRepo.operatorAlphaShort.value = operator2
+            mobileRepo.primaryLevel.value = level2
 
-            assertThat(latest).isEqualTo(info2)
+            assertThat(latestName).isEqualTo(operator2)
+            assertThat(latestLevel).isEqualTo(level2)
 
-            val info3 =
-                MobileConnectionModel(
-                    operatorAlphaShort = "Typical Merged Operator #3",
-                    primaryLevel = 3,
-                )
-            mobileRepo.setConnectionInfo(info3)
+            val operator3 = "Typical Merged Operator #3"
+            val level3 = 3
+            mobileRepo.operatorAlphaShort.value = operator3
+            mobileRepo.primaryLevel.value = level3
 
-            assertThat(latest).isEqualTo(info3)
+            assertThat(latestName).isEqualTo(operator3)
+            assertThat(latestLevel).isEqualTo(level3)
 
-            job.cancel()
+            nameJob.cancel()
+            levelJob.cancel()
         }
 
     @Test
@@ -236,57 +237,58 @@
         testScope.runTest {
             initializeRepo(startingIsCarrierMerged = false)
 
-            var latest: MobileConnectionModel? = null
-            val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+            var latestName: String? = null
+            var latestLevel: Int? = null
 
-            val carrierMergedInfo =
-                MobileConnectionModel(
-                    operatorAlphaShort = "Carrier Merged Operator",
-                    primaryLevel = 4,
-                )
-            carrierMergedRepo.setConnectionInfo(carrierMergedInfo)
+            val nameJob = underTest.operatorAlphaShort.onEach { latestName = it }.launchIn(this)
+            val levelJob = underTest.primaryLevel.onEach { latestLevel = it }.launchIn(this)
 
-            val mobileInfo =
-                MobileConnectionModel(
-                    operatorAlphaShort = "Typical Operator",
-                    primaryLevel = 2,
-                )
-            mobileRepo.setConnectionInfo(mobileInfo)
+            val carrierMergedOperator = "Carrier Merged Operator"
+            val carrierMergedLevel = 4
+            carrierMergedRepo.operatorAlphaShort.value = carrierMergedOperator
+            carrierMergedRepo.primaryLevel.value = carrierMergedLevel
+
+            val mobileName = "Typical Operator"
+            val mobileLevel = 2
+            mobileRepo.operatorAlphaShort.value = mobileName
+            mobileRepo.primaryLevel.value = mobileLevel
 
             // Start with the mobile info
-            assertThat(latest).isEqualTo(mobileInfo)
+            assertThat(latestName).isEqualTo(mobileName)
+            assertThat(latestLevel).isEqualTo(mobileLevel)
 
             // WHEN isCarrierMerged is set to true
             underTest.setIsCarrierMerged(true)
 
             // THEN the carrier merged info is used
-            assertThat(latest).isEqualTo(carrierMergedInfo)
+            assertThat(latestName).isEqualTo(carrierMergedOperator)
+            assertThat(latestLevel).isEqualTo(carrierMergedLevel)
 
-            val newCarrierMergedInfo =
-                MobileConnectionModel(
-                    operatorAlphaShort = "New CM Operator",
-                    primaryLevel = 0,
-                )
-            carrierMergedRepo.setConnectionInfo(newCarrierMergedInfo)
+            val newCarrierMergedName = "New CM Operator"
+            val newCarrierMergedLevel = 0
+            carrierMergedRepo.operatorAlphaShort.value = newCarrierMergedName
+            carrierMergedRepo.primaryLevel.value = newCarrierMergedLevel
 
-            assertThat(latest).isEqualTo(newCarrierMergedInfo)
+            assertThat(latestName).isEqualTo(newCarrierMergedName)
+            assertThat(latestLevel).isEqualTo(newCarrierMergedLevel)
 
             // WHEN isCarrierMerged is set to false
             underTest.setIsCarrierMerged(false)
 
             // THEN the typical info is used
-            assertThat(latest).isEqualTo(mobileInfo)
+            assertThat(latestName).isEqualTo(mobileName)
+            assertThat(latestLevel).isEqualTo(mobileLevel)
 
-            val newMobileInfo =
-                MobileConnectionModel(
-                    operatorAlphaShort = "New Mobile Operator",
-                    primaryLevel = 3,
-                )
-            mobileRepo.setConnectionInfo(newMobileInfo)
+            val newMobileName = "New MobileOperator"
+            val newMobileLevel = 3
+            mobileRepo.operatorAlphaShort.value = newMobileName
+            mobileRepo.primaryLevel.value = newMobileLevel
 
-            assertThat(latest).isEqualTo(newMobileInfo)
+            assertThat(latestName).isEqualTo(newMobileName)
+            assertThat(latestLevel).isEqualTo(newMobileLevel)
 
-            job.cancel()
+            nameJob.cancel()
+            levelJob.cancel()
         }
 
     @Test
@@ -370,7 +372,8 @@
 
             initializeRepo(startingIsCarrierMerged = false)
 
-            val job = underTest.connectionInfo.launchIn(this)
+            val emergencyJob = underTest.isEmergencyOnly.launchIn(this)
+            val operatorJob = underTest.operatorAlphaShort.launchIn(this)
 
             // WHEN we set up some mobile connection info
             val serviceState = ServiceState()
@@ -394,7 +397,8 @@
             assertThat(dumpBuffer()).contains("$COL_OPERATOR${BUFFER_SEPARATOR}OpDiff")
             assertThat(dumpBuffer()).contains("$COL_EMERGENCY${BUFFER_SEPARATOR}true")
 
-            job.cancel()
+            emergencyJob.cancel()
+            operatorJob.cancel()
         }
 
     @Test
@@ -409,7 +413,7 @@
 
             initializeRepo(startingIsCarrierMerged = true)
 
-            val job = underTest.connectionInfo.launchIn(this)
+            val job = underTest.primaryLevel.launchIn(this)
 
             // WHEN we set up carrier merged info
             val networkId = 2
@@ -452,7 +456,7 @@
 
             initializeRepo(startingIsCarrierMerged = false)
 
-            val job = underTest.connectionInfo.launchIn(this)
+            val job = underTest.primaryLevel.launchIn(this)
 
             // WHEN we set up some mobile connection info
             val signalStrength = mock<SignalStrength>()
@@ -502,12 +506,7 @@
             assertThat(bufferAfterCarrierMerged).contains("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}1")
 
             // WHEN the normal network is updated
-            val newMobileInfo =
-                MobileConnectionModel(
-                    operatorAlphaShort = "Mobile Operator 2",
-                    primaryLevel = 0,
-                )
-            mobileRepo.setConnectionInfo(newMobileInfo)
+            mobileRepo.primaryLevel.value = 0
 
             // THEN the new level is logged
             assertThat(dumpBuffer()).contains("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}0")
@@ -529,7 +528,7 @@
             // WHEN isCarrierMerged = false
             initializeRepo(startingIsCarrierMerged = false)
 
-            val job = underTest.connectionInfo.launchIn(this)
+            val job = underTest.primaryLevel.launchIn(this)
 
             val signalStrength = mock<SignalStrength>()
             whenever(signalStrength.level).thenReturn(1)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
index b2577e3..934e1c6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
@@ -18,17 +18,15 @@
 
 import android.content.Intent
 import android.telephony.CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL
-import android.telephony.CellSignalStrengthCdma
 import android.telephony.NetworkRegistrationInfo
 import android.telephony.ServiceState
 import android.telephony.ServiceState.STATE_IN_SERVICE
 import android.telephony.ServiceState.STATE_OUT_OF_SERVICE
-import android.telephony.SignalStrength
 import android.telephony.TelephonyCallback
 import android.telephony.TelephonyCallback.DataActivityListener
 import android.telephony.TelephonyCallback.ServiceStateListener
-import android.telephony.TelephonyDisplayInfo
 import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA
+import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE
 import android.telephony.TelephonyManager
 import android.telephony.TelephonyManager.DATA_ACTIVITY_DORMANT
 import android.telephony.TelephonyManager.DATA_ACTIVITY_IN
@@ -50,12 +48,15 @@
 import android.telephony.TelephonyManager.EXTRA_SPN
 import android.telephony.TelephonyManager.EXTRA_SUBSCRIPTION_ID
 import android.telephony.TelephonyManager.NETWORK_TYPE_LTE
+import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
 import androidx.test.filters.SmallTest
+import com.android.settingslib.mobile.MobileMappings
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
 import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
 import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.OverrideNetworkType
 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.UnknownNetworkType
@@ -65,7 +66,8 @@
 import com.android.systemui.statusbar.pipeline.mobile.data.model.toNetworkNameModel
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
-import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.signalStrength
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.telephonyDisplayInfo
 import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
 import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
 import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
@@ -73,14 +75,12 @@
 import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.cancel
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.runBlocking
-import org.junit.After
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Test
 import org.mockito.Mock
@@ -97,7 +97,6 @@
     @Mock private lateinit var logger: MobileInputLogger
     @Mock private lateinit var tableLogger: TableLogBuffer
 
-    private val scope = CoroutineScope(IMMEDIATE)
     private val mobileMappings = FakeMobileMappingsProxy()
     private val systemUiCarrierConfig =
         SystemUiCarrierConfig(
@@ -105,6 +104,9 @@
             createTestConfig(),
         )
 
+    private val testDispatcher = UnconfinedTestDispatcher()
+    private val testScope = TestScope(testDispatcher)
+
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
@@ -122,292 +124,353 @@
                 systemUiCarrierConfig,
                 fakeBroadcastDispatcher,
                 mobileMappings,
-                IMMEDIATE,
+                testDispatcher,
                 logger,
                 tableLogger,
-                scope,
+                testScope.backgroundScope,
             )
     }
 
-    @After
-    fun tearDown() {
-        scope.cancel()
-    }
-
     @Test
-    fun testFlowForSubId_default() =
-        runBlocking(IMMEDIATE) {
-            var latest: MobileConnectionModel? = null
-            val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
-
-            assertThat(latest).isEqualTo(MobileConnectionModel())
-
-            job.cancel()
-        }
-
-    @Test
-    fun testFlowForSubId_emergencyOnly() =
-        runBlocking(IMMEDIATE) {
-            var latest: MobileConnectionModel? = null
-            val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+    fun emergencyOnly() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job = underTest.isEmergencyOnly.onEach { latest = it }.launchIn(this)
 
             val serviceState = ServiceState()
             serviceState.isEmergencyOnly = true
 
             getTelephonyCallbackForType<ServiceStateListener>().onServiceStateChanged(serviceState)
 
-            assertThat(latest?.isEmergencyOnly).isEqualTo(true)
+            assertThat(latest).isEqualTo(true)
 
             job.cancel()
         }
 
     @Test
-    fun testFlowForSubId_emergencyOnly_toggles() =
-        runBlocking(IMMEDIATE) {
-            var latest: MobileConnectionModel? = null
-            val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+    fun emergencyOnly_toggles() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job = underTest.isEmergencyOnly.onEach { latest = it }.launchIn(this)
 
             val callback = getTelephonyCallbackForType<ServiceStateListener>()
-            val serviceState = ServiceState()
-            serviceState.isEmergencyOnly = true
-            callback.onServiceStateChanged(serviceState)
-            serviceState.isEmergencyOnly = false
-            callback.onServiceStateChanged(serviceState)
+            callback.onServiceStateChanged(ServiceState().also { it.isEmergencyOnly = true })
+            assertThat(latest).isTrue()
 
-            assertThat(latest?.isEmergencyOnly).isEqualTo(false)
+            callback.onServiceStateChanged(ServiceState().also { it.isEmergencyOnly = false })
+
+            assertThat(latest).isFalse()
 
             job.cancel()
         }
 
     @Test
-    fun testFlowForSubId_signalStrengths_levelsUpdate() =
-        runBlocking(IMMEDIATE) {
-            var latest: MobileConnectionModel? = null
-            val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+    fun cdmaLevelUpdates() =
+        testScope.runTest {
+            var latest: Int? = null
+            val job = underTest.cdmaLevel.onEach { latest = it }.launchIn(this)
 
             val callback = getTelephonyCallbackForType<TelephonyCallback.SignalStrengthsListener>()
-            val strength = signalStrength(gsmLevel = 1, cdmaLevel = 2, isGsm = true)
+            var strength = signalStrength(gsmLevel = 1, cdmaLevel = 2, isGsm = true)
             callback.onSignalStrengthsChanged(strength)
 
-            assertThat(latest?.isGsm).isEqualTo(true)
-            assertThat(latest?.primaryLevel).isEqualTo(1)
-            assertThat(latest?.cdmaLevel).isEqualTo(2)
+            assertThat(latest).isEqualTo(2)
+
+            // gsmLevel updates, no change to cdmaLevel
+            strength = signalStrength(gsmLevel = 3, cdmaLevel = 2, isGsm = true)
+
+            assertThat(latest).isEqualTo(2)
 
             job.cancel()
         }
 
     @Test
-    fun testFlowForSubId_dataConnectionState_connected() =
-        runBlocking(IMMEDIATE) {
-            var latest: MobileConnectionModel? = null
-            val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+    fun gsmLevelUpdates() =
+        testScope.runTest {
+            var latest: Int? = null
+            val job = underTest.primaryLevel.onEach { latest = it }.launchIn(this)
+
+            val callback = getTelephonyCallbackForType<TelephonyCallback.SignalStrengthsListener>()
+            var strength = signalStrength(gsmLevel = 1, cdmaLevel = 2, isGsm = true)
+            callback.onSignalStrengthsChanged(strength)
+
+            assertThat(latest).isEqualTo(1)
+
+            strength = signalStrength(gsmLevel = 3, cdmaLevel = 2, isGsm = true)
+            callback.onSignalStrengthsChanged(strength)
+
+            assertThat(latest).isEqualTo(3)
+
+            job.cancel()
+        }
+
+    @Test
+    fun isGsm() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job = underTest.isGsm.onEach { latest = it }.launchIn(this)
+
+            val callback = getTelephonyCallbackForType<TelephonyCallback.SignalStrengthsListener>()
+            var strength = signalStrength(gsmLevel = 1, cdmaLevel = 2, isGsm = true)
+            callback.onSignalStrengthsChanged(strength)
+
+            assertThat(latest).isTrue()
+
+            strength = signalStrength(gsmLevel = 1, cdmaLevel = 2, isGsm = false)
+            callback.onSignalStrengthsChanged(strength)
+
+            assertThat(latest).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
+    fun dataConnectionState_connected() =
+        testScope.runTest {
+            var latest: DataConnectionState? = null
+            val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
 
             val callback =
                 getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>()
             callback.onDataConnectionStateChanged(DATA_CONNECTED, 200 /* unused */)
 
-            assertThat(latest?.dataConnectionState).isEqualTo(DataConnectionState.Connected)
+            assertThat(latest).isEqualTo(DataConnectionState.Connected)
 
             job.cancel()
         }
 
     @Test
-    fun testFlowForSubId_dataConnectionState_connecting() =
-        runBlocking(IMMEDIATE) {
-            var latest: MobileConnectionModel? = null
-            val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+    fun dataConnectionState_connecting() =
+        testScope.runTest {
+            var latest: DataConnectionState? = null
+            val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
 
             val callback =
                 getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>()
             callback.onDataConnectionStateChanged(DATA_CONNECTING, 200 /* unused */)
 
-            assertThat(latest?.dataConnectionState).isEqualTo(DataConnectionState.Connecting)
+            assertThat(latest).isEqualTo(DataConnectionState.Connecting)
 
             job.cancel()
         }
 
     @Test
-    fun testFlowForSubId_dataConnectionState_disconnected() =
-        runBlocking(IMMEDIATE) {
-            var latest: MobileConnectionModel? = null
-            val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+    fun dataConnectionState_disconnected() =
+        testScope.runTest {
+            var latest: DataConnectionState? = null
+            val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
 
             val callback =
                 getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>()
             callback.onDataConnectionStateChanged(DATA_DISCONNECTED, 200 /* unused */)
 
-            assertThat(latest?.dataConnectionState).isEqualTo(DataConnectionState.Disconnected)
+            assertThat(latest).isEqualTo(DataConnectionState.Disconnected)
 
             job.cancel()
         }
 
     @Test
-    fun testFlowForSubId_dataConnectionState_disconnecting() =
-        runBlocking(IMMEDIATE) {
-            var latest: MobileConnectionModel? = null
-            val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+    fun dataConnectionState_disconnecting() =
+        testScope.runTest {
+            var latest: DataConnectionState? = null
+            val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
 
             val callback =
                 getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>()
             callback.onDataConnectionStateChanged(DATA_DISCONNECTING, 200 /* unused */)
 
-            assertThat(latest?.dataConnectionState).isEqualTo(DataConnectionState.Disconnecting)
+            assertThat(latest).isEqualTo(DataConnectionState.Disconnecting)
 
             job.cancel()
         }
 
     @Test
-    fun testFlowForSubId_dataConnectionState_suspended() =
-        runBlocking(IMMEDIATE) {
-            var latest: MobileConnectionModel? = null
-            val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+    fun dataConnectionState_suspended() =
+        testScope.runTest {
+            var latest: DataConnectionState? = null
+            val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
 
             val callback =
                 getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>()
             callback.onDataConnectionStateChanged(DATA_SUSPENDED, 200 /* unused */)
 
-            assertThat(latest?.dataConnectionState).isEqualTo(DataConnectionState.Suspended)
+            assertThat(latest).isEqualTo(DataConnectionState.Suspended)
 
             job.cancel()
         }
 
     @Test
-    fun testFlowForSubId_dataConnectionState_handoverInProgress() =
-        runBlocking(IMMEDIATE) {
-            var latest: MobileConnectionModel? = null
-            val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+    fun dataConnectionState_handoverInProgress() =
+        testScope.runTest {
+            var latest: DataConnectionState? = null
+            val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
 
             val callback =
                 getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>()
             callback.onDataConnectionStateChanged(DATA_HANDOVER_IN_PROGRESS, 200 /* unused */)
 
-            assertThat(latest?.dataConnectionState)
-                .isEqualTo(DataConnectionState.HandoverInProgress)
+            assertThat(latest).isEqualTo(DataConnectionState.HandoverInProgress)
 
             job.cancel()
         }
 
     @Test
-    fun testFlowForSubId_dataConnectionState_unknown() =
-        runBlocking(IMMEDIATE) {
-            var latest: MobileConnectionModel? = null
-            val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+    fun dataConnectionState_unknown() =
+        testScope.runTest {
+            var latest: DataConnectionState? = null
+            val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
 
             val callback =
                 getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>()
             callback.onDataConnectionStateChanged(DATA_UNKNOWN, 200 /* unused */)
 
-            assertThat(latest?.dataConnectionState).isEqualTo(DataConnectionState.Unknown)
+            assertThat(latest).isEqualTo(DataConnectionState.Unknown)
 
             job.cancel()
         }
 
     @Test
-    fun testFlowForSubId_dataConnectionState_invalid() =
-        runBlocking(IMMEDIATE) {
-            var latest: MobileConnectionModel? = null
-            val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+    fun dataConnectionState_invalid() =
+        testScope.runTest {
+            var latest: DataConnectionState? = null
+            val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
 
             val callback =
                 getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>()
             callback.onDataConnectionStateChanged(45, 200 /* unused */)
 
-            assertThat(latest?.dataConnectionState).isEqualTo(DataConnectionState.Invalid)
+            assertThat(latest).isEqualTo(DataConnectionState.Invalid)
 
             job.cancel()
         }
 
     @Test
-    fun testFlowForSubId_dataActivity() =
-        runBlocking(IMMEDIATE) {
-            var latest: MobileConnectionModel? = null
-            val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+    fun dataActivity() =
+        testScope.runTest {
+            var latest: DataActivityModel? = null
+            val job = underTest.dataActivityDirection.onEach { latest = it }.launchIn(this)
 
             val callback = getTelephonyCallbackForType<DataActivityListener>()
             callback.onDataActivity(DATA_ACTIVITY_INOUT)
 
-            assertThat(latest?.dataActivityDirection)
-                .isEqualTo(DATA_ACTIVITY_INOUT.toMobileDataActivityModel())
+            assertThat(latest).isEqualTo(DATA_ACTIVITY_INOUT.toMobileDataActivityModel())
 
             job.cancel()
         }
 
     @Test
-    fun testFlowForSubId_carrierNetworkChange() =
-        runBlocking(IMMEDIATE) {
-            var latest: MobileConnectionModel? = null
-            val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+    fun carrierNetworkChange() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job = underTest.carrierNetworkChangeActive.onEach { latest = it }.launchIn(this)
 
             val callback = getTelephonyCallbackForType<TelephonyCallback.CarrierNetworkListener>()
             callback.onCarrierNetworkChange(true)
 
-            assertThat(latest?.carrierNetworkChangeActive).isEqualTo(true)
+            assertThat(latest).isEqualTo(true)
 
             job.cancel()
         }
 
     @Test
-    fun subscriptionFlow_networkType_default() =
-        runBlocking(IMMEDIATE) {
-            var latest: MobileConnectionModel? = null
-            val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+    fun networkType_default() =
+        testScope.runTest {
+            var latest: ResolvedNetworkType? = null
+            val job = underTest.resolvedNetworkType.onEach { latest = it }.launchIn(this)
 
             val expected = UnknownNetworkType
 
-            assertThat(latest?.resolvedNetworkType).isEqualTo(expected)
+            assertThat(latest).isEqualTo(expected)
 
             job.cancel()
         }
 
     @Test
-    fun subscriptionFlow_networkType_updatesUsingDefault() =
-        runBlocking(IMMEDIATE) {
-            var latest: MobileConnectionModel? = null
-            val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+    fun networkType_unknown_hasCorrectKey() =
+        testScope.runTest {
+            var latest: ResolvedNetworkType? = null
+            val job = underTest.resolvedNetworkType.onEach { latest = it }.launchIn(this)
 
             val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>()
-            val type = NETWORK_TYPE_LTE
-            val expected = DefaultNetworkType(mobileMappings.toIconKey(type))
-            val ti = mock<TelephonyDisplayInfo>().also { whenever(it.networkType).thenReturn(type) }
+            val ti =
+                telephonyDisplayInfo(
+                    networkType = NETWORK_TYPE_UNKNOWN,
+                    overrideNetworkType = NETWORK_TYPE_UNKNOWN,
+                )
+
             callback.onDisplayInfoChanged(ti)
 
-            assertThat(latest?.resolvedNetworkType).isEqualTo(expected)
+            val expected = UnknownNetworkType
+            assertThat(latest).isEqualTo(expected)
+            assertThat(latest!!.lookupKey).isEqualTo(MobileMappings.toIconKey(NETWORK_TYPE_UNKNOWN))
 
             job.cancel()
         }
 
     @Test
-    fun subscriptionFlow_networkType_updatesUsingOverride() =
-        runBlocking(IMMEDIATE) {
-            var latest: MobileConnectionModel? = null
-            val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+    fun networkType_updatesUsingDefault() =
+        testScope.runTest {
+            var latest: ResolvedNetworkType? = null
+            val job = underTest.resolvedNetworkType.onEach { latest = it }.launchIn(this)
+
+            val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>()
+            val overrideType = OVERRIDE_NETWORK_TYPE_NONE
+            val type = NETWORK_TYPE_LTE
+            val ti = telephonyDisplayInfo(networkType = type, overrideNetworkType = overrideType)
+            callback.onDisplayInfoChanged(ti)
+
+            val expected = DefaultNetworkType(mobileMappings.toIconKey(type))
+            assertThat(latest).isEqualTo(expected)
+
+            job.cancel()
+        }
+
+    @Test
+    fun networkType_updatesUsingOverride() =
+        testScope.runTest {
+            var latest: ResolvedNetworkType? = null
+            val job = underTest.resolvedNetworkType.onEach { latest = it }.launchIn(this)
 
             val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>()
             val type = OVERRIDE_NETWORK_TYPE_LTE_CA
-            val expected = OverrideNetworkType(mobileMappings.toIconKeyOverride(type))
-            val ti =
-                mock<TelephonyDisplayInfo>().also {
-                    whenever(it.networkType).thenReturn(type)
-                    whenever(it.overrideNetworkType).thenReturn(type)
-                }
+            val ti = telephonyDisplayInfo(networkType = type, overrideNetworkType = type)
             callback.onDisplayInfoChanged(ti)
 
-            assertThat(latest?.resolvedNetworkType).isEqualTo(expected)
+            val expected = OverrideNetworkType(mobileMappings.toIconKeyOverride(type))
+            assertThat(latest).isEqualTo(expected)
+
+            job.cancel()
+        }
+
+    @Test
+    fun networkType_unknownNetworkWithOverride_usesOverrideKey() =
+        testScope.runTest {
+            var latest: ResolvedNetworkType? = null
+            val job = underTest.resolvedNetworkType.onEach { latest = it }.launchIn(this)
+
+            val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>()
+            val unknown = NETWORK_TYPE_UNKNOWN
+            val type = OVERRIDE_NETWORK_TYPE_LTE_CA
+            val ti = telephonyDisplayInfo(unknown, type)
+            callback.onDisplayInfoChanged(ti)
+
+            val expected = OverrideNetworkType(mobileMappings.toIconKeyOverride(type))
+            assertThat(latest).isEqualTo(expected)
 
             job.cancel()
         }
 
     @Test
     fun dataEnabled_initial_false() =
-        runBlocking(IMMEDIATE) {
+        testScope.runTest {
             whenever(telephonyManager.isDataConnectionAllowed).thenReturn(false)
 
             assertThat(underTest.dataEnabled.value).isFalse()
         }
 
     @Test
-    fun `is data enabled - tracks telephony callback`() =
-        runBlocking(IMMEDIATE) {
+    fun isDataEnabled_tracksTelephonyCallback() =
+        testScope.runTest {
             var latest: Boolean? = null
             val job = underTest.dataEnabled.onEach { latest = it }.launchIn(this)
 
@@ -427,7 +490,7 @@
 
     @Test
     fun numberOfLevels_isDefault() =
-        runBlocking(IMMEDIATE) {
+        testScope.runTest {
             var latest: Int? = null
             val job = underTest.numberOfLevels.onEach { latest = it }.launchIn(this)
 
@@ -437,51 +500,68 @@
         }
 
     @Test
-    fun `roaming - cdma - queries telephony manager`() =
-        runBlocking(IMMEDIATE) {
+    fun roaming_cdma_queriesTelephonyManager() =
+        testScope.runTest {
             var latest: Boolean? = null
             val job = underTest.cdmaRoaming.onEach { latest = it }.launchIn(this)
 
             val cb = getTelephonyCallbackForType<ServiceStateListener>()
 
-            val serviceState = ServiceState()
-            serviceState.roaming = false
-
-            // CDMA roaming is off, GSM roaming is off
+            // CDMA roaming is off, GSM roaming is on
             whenever(telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber).thenReturn(ERI_OFF)
-            cb.onServiceStateChanged(serviceState)
+            cb.onServiceStateChanged(ServiceState().also { it.roaming = true })
 
             assertThat(latest).isFalse()
 
-            // CDMA roaming is off, GSM roaming is on
+            // CDMA roaming is on, GSM roaming is off
             whenever(telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber).thenReturn(ERI_ON)
-            cb.onServiceStateChanged(serviceState)
+            cb.onServiceStateChanged(ServiceState().also { it.roaming = false })
 
             assertThat(latest).isTrue()
 
             job.cancel()
         }
 
+    /**
+     * [TelephonyManager.getCdmaEnhancedRoamingIndicatorDisplayNumber] returns -1 if the service is
+     * not running or if there is an error while retrieving the cdma ERI
+     */
     @Test
-    fun `roaming - gsm - queries service state`() =
-        runBlocking(IMMEDIATE) {
+    fun cdmaRoaming_ignoresNegativeOne() =
+        testScope.runTest {
             var latest: Boolean? = null
-            val job = underTest.connectionInfo.onEach { latest = it.isRoaming }.launchIn(this)
+            val job = underTest.cdmaRoaming.onEach { latest = it }.launchIn(this)
 
             val serviceState = ServiceState()
             serviceState.roaming = false
 
             val cb = getTelephonyCallbackForType<ServiceStateListener>()
 
-            // CDMA roaming is off, GSM roaming is off
-            whenever(telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber).thenReturn(ERI_OFF)
+            // CDMA roaming is unavailable (-1), GSM roaming is off
+            whenever(telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber).thenReturn(-1)
             cb.onServiceStateChanged(serviceState)
 
             assertThat(latest).isFalse()
 
+            job.cancel()
+        }
+
+    @Test
+    fun roaming_gsm_queriesServiceState() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job = underTest.isRoaming.onEach { latest = it }.launchIn(this)
+
+            val cb = getTelephonyCallbackForType<ServiceStateListener>()
+
+            // CDMA roaming is off, GSM roaming is off
+            whenever(telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber).thenReturn(ERI_OFF)
+            cb.onServiceStateChanged(ServiceState().also { it.roaming = false })
+
+            assertThat(latest).isFalse()
+
             // CDMA roaming is off, GSM roaming is on
-            serviceState.roaming = true
-            cb.onServiceStateChanged(serviceState)
+            cb.onServiceStateChanged(ServiceState().also { it.roaming = true })
 
             assertThat(latest).isTrue()
 
@@ -489,11 +569,10 @@
         }
 
     @Test
-    fun `activity - updates from callback`() =
-        runBlocking(IMMEDIATE) {
+    fun activity_updatesFromCallback() =
+        testScope.runTest {
             var latest: DataActivityModel? = null
-            val job =
-                underTest.connectionInfo.onEach { latest = it.dataActivityDirection }.launchIn(this)
+            val job = underTest.dataActivityDirection.onEach { latest = it }.launchIn(this)
 
             assertThat(latest)
                 .isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = false))
@@ -527,8 +606,8 @@
         }
 
     @Test
-    fun `network name - default`() =
-        runBlocking(IMMEDIATE) {
+    fun networkName_default() =
+        testScope.runTest {
             var latest: NetworkNameModel? = null
             val job = underTest.networkName.onEach { latest = it }.launchIn(this)
 
@@ -538,8 +617,8 @@
         }
 
     @Test
-    fun `network name - uses broadcast info - returns derived`() =
-        runBlocking(IMMEDIATE) {
+    fun networkName_usesBroadcastInfo_returnsDerived() =
+        testScope.runTest {
             var latest: NetworkNameModel? = null
             val job = underTest.networkName.onEach { latest = it }.launchIn(this)
 
@@ -555,8 +634,8 @@
         }
 
     @Test
-    fun `network name - broadcast not for this sub id - keeps old value`() =
-        runBlocking(IMMEDIATE) {
+    fun networkName_broadcastNotForThisSubId_keepsOldValue() =
+        testScope.runTest {
             var latest: NetworkNameModel? = null
             val job = underTest.networkName.onEach { latest = it }.launchIn(this)
 
@@ -580,8 +659,8 @@
         }
 
     @Test
-    fun `network name - broadcast has no data - updates to default`() =
-        runBlocking(IMMEDIATE) {
+    fun networkName_broadcastHasNoData_updatesToDefault() =
+        testScope.runTest {
             var latest: NetworkNameModel? = null
             val job = underTest.networkName.onEach { latest = it }.launchIn(this)
 
@@ -607,12 +686,11 @@
         }
 
     @Test
-    fun `operatorAlphaShort - tracked`() =
-        runBlocking(IMMEDIATE) {
+    fun operatorAlphaShort_tracked() =
+        testScope.runTest {
             var latest: String? = null
 
-            val job =
-                underTest.connectionInfo.onEach { latest = it.operatorAlphaShort }.launchIn(this)
+            val job = underTest.operatorAlphaShort.onEach { latest = it }.launchIn(this)
 
             val shortName = "short name"
             val serviceState = ServiceState()
@@ -630,35 +708,47 @@
         }
 
     @Test
-    fun `connection model - isInService - not iwlan`() =
-        runBlocking(IMMEDIATE) {
+    fun isInService_notIwlan() =
+        testScope.runTest {
             var latest: Boolean? = null
-            val job = underTest.connectionInfo.onEach { latest = it.isInService }.launchIn(this)
+            val job = underTest.isInService.onEach { latest = it }.launchIn(this)
 
-            val serviceState = ServiceState()
-            serviceState.voiceRegState = STATE_IN_SERVICE
-            serviceState.dataRegState = STATE_IN_SERVICE
-
-            getTelephonyCallbackForType<ServiceStateListener>().onServiceStateChanged(serviceState)
+            getTelephonyCallbackForType<ServiceStateListener>()
+                .onServiceStateChanged(
+                    ServiceState().also {
+                        it.voiceRegState = STATE_IN_SERVICE
+                        it.dataRegState = STATE_IN_SERVICE
+                    }
+                )
 
             assertThat(latest).isTrue()
 
-            serviceState.voiceRegState = STATE_OUT_OF_SERVICE
-            getTelephonyCallbackForType<ServiceStateListener>().onServiceStateChanged(serviceState)
+            getTelephonyCallbackForType<ServiceStateListener>()
+                .onServiceStateChanged(
+                    ServiceState().also {
+                        it.dataRegState = STATE_IN_SERVICE
+                        it.voiceRegState = STATE_OUT_OF_SERVICE
+                    }
+                )
             assertThat(latest).isTrue()
 
-            serviceState.dataRegState = STATE_OUT_OF_SERVICE
-            getTelephonyCallbackForType<ServiceStateListener>().onServiceStateChanged(serviceState)
+            getTelephonyCallbackForType<ServiceStateListener>()
+                .onServiceStateChanged(
+                    ServiceState().also {
+                        it.voiceRegState = STATE_OUT_OF_SERVICE
+                        it.dataRegState = STATE_OUT_OF_SERVICE
+                    }
+                )
             assertThat(latest).isFalse()
 
             job.cancel()
         }
 
     @Test
-    fun `connection model - isInService - is iwlan - voice out of service - data in service`() =
-        runBlocking(IMMEDIATE) {
+    fun isInService_isIwlan_voiceOutOfService_dataInService() =
+        testScope.runTest {
             var latest: Boolean? = null
-            val job = underTest.connectionInfo.onEach { latest = it.isInService }.launchIn(this)
+            val job = underTest.isInService.onEach { latest = it }.launchIn(this)
 
             // Mock the service state here so we can make it specifically IWLAN
             val serviceState: ServiceState = mock()
@@ -680,8 +770,8 @@
         }
 
     @Test
-    fun `number of levels - uses carrier config`() =
-        runBlocking(IMMEDIATE) {
+    fun numberOfLevels_usesCarrierConfig() =
+        testScope.runTest {
             var latest: Int? = null
             val job = underTest.numberOfLevels.onEach { latest = it }.launchIn(this)
 
@@ -706,19 +796,6 @@
         return MobileTelephonyHelpers.getTelephonyCallbackForType(telephonyManager)
     }
 
-    /** Convenience constructor for SignalStrength */
-    private fun signalStrength(gsmLevel: Int, cdmaLevel: Int, isGsm: Boolean): SignalStrength {
-        val signalStrength = mock<SignalStrength>()
-        whenever(signalStrength.isGsm).thenReturn(isGsm)
-        whenever(signalStrength.level).thenReturn(gsmLevel)
-        val cdmaStrength =
-            mock<CellSignalStrengthCdma>().also { whenever(it.level).thenReturn(cdmaLevel) }
-        whenever(signalStrength.getCellSignalStrengths(CellSignalStrengthCdma::class.java))
-            .thenReturn(listOf(cdmaStrength))
-
-        return signalStrength
-    }
-
     private fun spnIntent(
         subId: Int = SUB_1_ID,
         showSpn: Boolean = true,
@@ -735,7 +812,6 @@
         }
 
     companion object {
-        private val IMMEDIATE = Dispatchers.Main.immediate
         private const val SUB_1_ID = 1
 
         private val DEFAULT_NAME = NetworkNameModel.Default("default name")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt
new file mode 100644
index 0000000..9da9ff7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt
@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
+
+import android.telephony.ServiceState
+import android.telephony.TelephonyCallback
+import android.telephony.TelephonyCallback.CarrierNetworkListener
+import android.telephony.TelephonyCallback.DataActivityListener
+import android.telephony.TelephonyCallback.DataConnectionStateListener
+import android.telephony.TelephonyCallback.DataEnabledListener
+import android.telephony.TelephonyCallback.DisplayInfoListener
+import android.telephony.TelephonyCallback.ServiceStateListener
+import android.telephony.TelephonyDisplayInfo
+import android.telephony.TelephonyManager
+import android.telephony.TelephonyManager.DATA_ACTIVITY_INOUT
+import android.telephony.TelephonyManager.NETWORK_TYPE_LTE
+import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfigTest
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.getTelephonyCallbackForType
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.signalStrength
+import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
+import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+/**
+ * Test class to stress test the TelephonyCallbacks that we listen to. In particular, the callbacks
+ * all come back in on a single listener (for reasons defined in the system). This test is built to
+ * ensure that we don't miss any important callbacks.
+ *
+ * Kind of like an interaction test case build just for [TelephonyCallback]
+ *
+ * The list of telephony callbacks we use is:
+ * - [TelephonyCallback.CarrierNetworkListener]
+ * - [TelephonyCallback.DataActivityListener]
+ * - [TelephonyCallback.DataConnectionStateListener]
+ * - [TelephonyCallback.DataEnabledListener]
+ * - [TelephonyCallback.DisplayInfoListener]
+ * - [TelephonyCallback.ServiceStateListener]
+ * - [TelephonyCallback.SignalStrengthsListener]
+ *
+ * Because each of these callbacks comes in on the same callbackFlow, collecting on a field backed
+ * by only a single callback can immediately create backpressure on the other fields related to a
+ * mobile connection.
+ *
+ * This test should be designed to test _at least_ each individual callback in a smoke-test fashion.
+ * The way we will achieve this is as follows:
+ * 1. Start up a listener (A) collecting on a field which is _not under test_
+ * 2. Send a single event to a telephony callback which supports the field under test (B)
+ * 3. Send many (may be as few as 2) events to the callback backing A to ensure we start seeing
+ *    backpressure on other fields NOTE: poor handling of backpressure here would normally cause B
+ *    to get dropped
+ * 4. Start up a new collector for B
+ * 5. Assert that B has the state sent in step #2
+ */
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+class MobileConnectionTelephonySmokeTests : SysuiTestCase() {
+    private lateinit var underTest: MobileConnectionRepositoryImpl
+    private lateinit var connectionsRepo: FakeMobileConnectionsRepository
+
+    @Mock private lateinit var telephonyManager: TelephonyManager
+    @Mock private lateinit var logger: MobileInputLogger
+    @Mock private lateinit var tableLogger: TableLogBuffer
+
+    private val mobileMappings = FakeMobileMappingsProxy()
+    private val systemUiCarrierConfig =
+        SystemUiCarrierConfig(
+            SUB_1_ID,
+            SystemUiCarrierConfigTest.createTestConfig(),
+        )
+
+    private val testDispatcher = UnconfinedTestDispatcher()
+    private val testScope = TestScope(testDispatcher)
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        whenever(telephonyManager.subscriptionId).thenReturn(SUB_1_ID)
+
+        connectionsRepo = FakeMobileConnectionsRepository(mobileMappings, tableLogger)
+
+        underTest =
+            MobileConnectionRepositoryImpl(
+                context,
+                SUB_1_ID,
+                DEFAULT_NAME,
+                SEP,
+                telephonyManager,
+                systemUiCarrierConfig,
+                fakeBroadcastDispatcher,
+                mobileMappings,
+                testDispatcher,
+                logger,
+                tableLogger,
+                testScope.backgroundScope,
+            )
+    }
+
+    @Test
+    fun carrierNetworkChangeListener_noisyActivity() =
+        testScope.runTest {
+            var latest: Boolean? = null
+
+            // Start collecting data activity; don't care about the result
+            val activityJob = underTest.dataActivityDirection.launchIn(this)
+            val activityCallback = getTelephonyCallbackForType<DataActivityListener>()
+
+            val callback = getTelephonyCallbackForType<CarrierNetworkListener>()
+            callback.onCarrierNetworkChange(true)
+
+            flipActivity(100, activityCallback)
+
+            val job = underTest.carrierNetworkChangeActive.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isTrue()
+
+            activityJob.cancel()
+            job.cancel()
+        }
+
+    @Test
+    fun dataActivityLate_noisyDisplayInfo() =
+        testScope.runTest {
+            var latest: DataActivityModel? = null
+
+            // start collecting displayInfo; don't care about the result
+            val displayInfoJob = underTest.resolvedNetworkType.launchIn(this)
+
+            val activityCallback = getTelephonyCallbackForType<DataActivityListener>()
+            activityCallback.onDataActivity(DATA_ACTIVITY_INOUT)
+
+            val displayInfoCallback = getTelephonyCallbackForType<DisplayInfoListener>()
+            val type1 = NETWORK_TYPE_UNKNOWN
+            val type2 = NETWORK_TYPE_LTE
+            val t1 =
+                mock<TelephonyDisplayInfo>().also { whenever(it.networkType).thenReturn(type1) }
+            val t2 =
+                mock<TelephonyDisplayInfo>().also { whenever(it.networkType).thenReturn(type2) }
+
+            flipDisplayInfo(100, listOf(t1, t2), displayInfoCallback)
+
+            val job = underTest.dataActivityDirection.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest)
+                .isEqualTo(
+                    DataActivityModel(
+                        hasActivityIn = true,
+                        hasActivityOut = true,
+                    )
+                )
+
+            displayInfoJob.cancel()
+            job.cancel()
+        }
+
+    @Test
+    fun dataConnectionStateListener_noisyActivity() =
+        testScope.runTest {
+            var latest: DataConnectionState? = null
+
+            // Start collecting data activity; don't care about the result
+            val activityJob = underTest.dataActivityDirection.launchIn(this)
+
+            val connectionCallback = getTelephonyCallbackForType<DataConnectionStateListener>()
+            val activityCallback = getTelephonyCallbackForType<DataActivityListener>()
+
+            connectionCallback.onDataConnectionStateChanged(
+                TelephonyManager.DATA_CONNECTED,
+                200 /* unused */
+            )
+
+            flipActivity(100, activityCallback)
+
+            val connectionJob = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isEqualTo(DataConnectionState.Connected)
+
+            activityJob.cancel()
+            connectionJob.cancel()
+        }
+
+    @Test
+    fun dataEnabledLate_noisyActivity() =
+        testScope.runTest {
+            var latest: Boolean? = null
+
+            // Start collecting data activity; don't care about the result
+            val activityJob = underTest.dataActivityDirection.launchIn(this)
+
+            val enabledCallback = getTelephonyCallbackForType<DataEnabledListener>()
+            val activityCallback = getTelephonyCallbackForType<DataActivityListener>()
+
+            enabledCallback.onDataEnabledChanged(true, 1 /* unused */)
+
+            flipActivity(100, activityCallback)
+
+            val job = underTest.dataEnabled.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isTrue()
+
+            activityJob.cancel()
+            job.cancel()
+        }
+
+    @Test
+    fun displayInfoLate_noisyActivity() =
+        testScope.runTest {
+            var latest: ResolvedNetworkType? = null
+
+            // Start collecting data activity; don't care about the result
+            val activityJob = underTest.dataActivityDirection.launchIn(this)
+
+            val displayInfoCallback = getTelephonyCallbackForType<DisplayInfoListener>()
+            val activityCallback = getTelephonyCallbackForType<DataActivityListener>()
+
+            val type = NETWORK_TYPE_LTE
+            val expected = ResolvedNetworkType.DefaultNetworkType(mobileMappings.toIconKey(type))
+            val ti = mock<TelephonyDisplayInfo>().also { whenever(it.networkType).thenReturn(type) }
+            displayInfoCallback.onDisplayInfoChanged(ti)
+
+            flipActivity(100, activityCallback)
+
+            val job = underTest.resolvedNetworkType.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isEqualTo(expected)
+
+            activityJob.cancel()
+            job.cancel()
+        }
+
+    @Test
+    fun serviceStateListener_noisyActivity() =
+        testScope.runTest {
+            var latest: Boolean? = null
+
+            // Start collecting data activity; don't care about the result
+            val activityJob = underTest.dataActivityDirection.launchIn(this)
+
+            val serviceStateCallback = getTelephonyCallbackForType<ServiceStateListener>()
+            val activityCallback = getTelephonyCallbackForType<DataActivityListener>()
+
+            // isEmergencyOnly comes in
+            val serviceState = ServiceState()
+            serviceState.isEmergencyOnly = true
+            serviceStateCallback.onServiceStateChanged(serviceState)
+
+            flipActivity(100, activityCallback)
+
+            val job = underTest.isEmergencyOnly.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isTrue()
+
+            activityJob.cancel()
+            job.cancel()
+        }
+
+    @Test
+    fun signalStrengthsListenerLate_noisyActivity() =
+        testScope.runTest {
+            var latest: Int? = null
+
+            // Start collecting data activity; don't care about the result
+            val activityJob = underTest.dataActivityDirection.launchIn(this)
+            val activityCallback = getTelephonyCallbackForType<DataActivityListener>()
+
+            val callback = getTelephonyCallbackForType<TelephonyCallback.SignalStrengthsListener>()
+            val strength = signalStrength(gsmLevel = 1, cdmaLevel = 2, isGsm = true)
+            callback.onSignalStrengthsChanged(strength)
+
+            flipActivity(100, activityCallback)
+
+            val job = underTest.cdmaLevel.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isEqualTo(2)
+
+            activityJob.cancel()
+            job.cancel()
+        }
+
+    private fun flipActivity(
+        times: Int,
+        callback: DataActivityListener,
+    ) {
+        repeat(times) { index -> callback.onDataActivity(index % 4) }
+    }
+
+    private fun flipDisplayInfo(
+        times: Int,
+        infos: List<TelephonyDisplayInfo>,
+        callback: DisplayInfoListener,
+    ) {
+        val len = infos.size
+        repeat(times) { index -> callback.onDisplayInfoChanged(infos[index % len]) }
+    }
+
+    private inline fun <reified T> getTelephonyCallbackForType(): T {
+        return getTelephonyCallbackForType(telephonyManager)
+    }
+
+    companion object {
+        private const val SUB_1_ID = 1
+
+        private val DEFAULT_NAME = NetworkNameModel.Default("default name")
+        private const val SEP = "-"
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
index 09b7a66..68b1cda 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
@@ -37,12 +37,12 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.log.table.TableLogBuffer
 import com.android.systemui.log.table.TableLogBufferFactory
+import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
 import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigRepository
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Factory.Companion.tableBufferLogName
-import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger
 import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
 import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileTelephonyHelpers.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileTelephonyHelpers.kt
index 621f793..cf815c2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileTelephonyHelpers.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileTelephonyHelpers.kt
@@ -16,10 +16,15 @@
 
 package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
 
+import android.telephony.CellSignalStrengthCdma
+import android.telephony.SignalStrength
 import android.telephony.TelephonyCallback
+import android.telephony.TelephonyDisplayInfo
 import android.telephony.TelephonyManager
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
 import org.mockito.Mockito.verify
 
@@ -31,6 +36,25 @@
         return callbackCaptor.allValues
     }
 
+    /** Convenience constructor for SignalStrength */
+    fun signalStrength(gsmLevel: Int, cdmaLevel: Int, isGsm: Boolean): SignalStrength {
+        val signalStrength = mock<SignalStrength>()
+        whenever(signalStrength.isGsm).thenReturn(isGsm)
+        whenever(signalStrength.level).thenReturn(gsmLevel)
+        val cdmaStrength =
+            mock<CellSignalStrengthCdma>().also { whenever(it.level).thenReturn(cdmaLevel) }
+        whenever(signalStrength.getCellSignalStrengths(CellSignalStrengthCdma::class.java))
+            .thenReturn(listOf(cdmaStrength))
+
+        return signalStrength
+    }
+
+    fun telephonyDisplayInfo(networkType: Int, overrideNetworkType: Int) =
+        mock<TelephonyDisplayInfo>().also {
+            whenever(it.networkType).thenReturn(networkType)
+            whenever(it.overrideNetworkType).thenReturn(overrideNetworkType)
+        }
+
     inline fun <reified T> getTelephonyCallbackForType(mockTelephonyManager: TelephonyManager): T {
         val cbs = getTelephonyCallbacks(mockTelephonyManager).filterIsInstance<T>()
         assertThat(cbs.size).isEqualTo(1)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
index fa072fc..1eb1056 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
@@ -23,7 +23,6 @@
 import com.android.settingslib.mobile.TelephonyIcons
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
-import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
 import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.CarrierMergedNetworkType
 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
@@ -74,9 +73,7 @@
     @Test
     fun gsm_level_default_unknown() =
         runBlocking(IMMEDIATE) {
-            connectionRepository.setConnectionInfo(
-                MobileConnectionModel(isGsm = true),
-            )
+            connectionRepository.isGsm.value = true
 
             var latest: Int? = null
             val job = underTest.level.onEach { latest = it }.launchIn(this)
@@ -89,13 +86,9 @@
     @Test
     fun gsm_usesGsmLevel() =
         runBlocking(IMMEDIATE) {
-            connectionRepository.setConnectionInfo(
-                MobileConnectionModel(
-                    isGsm = true,
-                    primaryLevel = GSM_LEVEL,
-                    cdmaLevel = CDMA_LEVEL
-                ),
-            )
+            connectionRepository.isGsm.value = true
+            connectionRepository.primaryLevel.value = GSM_LEVEL
+            connectionRepository.cdmaLevel.value = CDMA_LEVEL
 
             var latest: Int? = null
             val job = underTest.level.onEach { latest = it }.launchIn(this)
@@ -108,13 +101,9 @@
     @Test
     fun gsm_alwaysShowCdmaTrue_stillUsesGsmLevel() =
         runBlocking(IMMEDIATE) {
-            connectionRepository.setConnectionInfo(
-                MobileConnectionModel(
-                    isGsm = true,
-                    primaryLevel = GSM_LEVEL,
-                    cdmaLevel = CDMA_LEVEL,
-                ),
-            )
+            connectionRepository.isGsm.value = true
+            connectionRepository.primaryLevel.value = GSM_LEVEL
+            connectionRepository.cdmaLevel.value = CDMA_LEVEL
             mobileIconsInteractor.alwaysUseCdmaLevel.value = true
 
             var latest: Int? = null
@@ -128,9 +117,7 @@
     @Test
     fun notGsm_level_default_unknown() =
         runBlocking(IMMEDIATE) {
-            connectionRepository.setConnectionInfo(
-                MobileConnectionModel(isGsm = false),
-            )
+            connectionRepository.isGsm.value = false
 
             var latest: Int? = null
             val job = underTest.level.onEach { latest = it }.launchIn(this)
@@ -142,13 +129,9 @@
     @Test
     fun notGsm_alwaysShowCdmaTrue_usesCdmaLevel() =
         runBlocking(IMMEDIATE) {
-            connectionRepository.setConnectionInfo(
-                MobileConnectionModel(
-                    isGsm = false,
-                    primaryLevel = GSM_LEVEL,
-                    cdmaLevel = CDMA_LEVEL
-                ),
-            )
+            connectionRepository.isGsm.value = false
+            connectionRepository.primaryLevel.value = GSM_LEVEL
+            connectionRepository.cdmaLevel.value = CDMA_LEVEL
             mobileIconsInteractor.alwaysUseCdmaLevel.value = true
 
             var latest: Int? = null
@@ -162,13 +145,9 @@
     @Test
     fun notGsm_alwaysShowCdmaFalse_usesPrimaryLevel() =
         runBlocking(IMMEDIATE) {
-            connectionRepository.setConnectionInfo(
-                MobileConnectionModel(
-                    isGsm = false,
-                    primaryLevel = GSM_LEVEL,
-                    cdmaLevel = CDMA_LEVEL,
-                ),
-            )
+            connectionRepository.isGsm.value = false
+            connectionRepository.primaryLevel.value = GSM_LEVEL
+            connectionRepository.cdmaLevel.value = CDMA_LEVEL
             mobileIconsInteractor.alwaysUseCdmaLevel.value = false
 
             var latest: Int? = null
@@ -197,11 +176,8 @@
     @Test
     fun iconGroup_three_g() =
         runBlocking(IMMEDIATE) {
-            connectionRepository.setConnectionInfo(
-                MobileConnectionModel(
-                    resolvedNetworkType = DefaultNetworkType(mobileMappingsProxy.toIconKey(THREE_G))
-                ),
-            )
+            connectionRepository.resolvedNetworkType.value =
+                DefaultNetworkType(mobileMappingsProxy.toIconKey(THREE_G))
 
             var latest: MobileIconGroup? = null
             val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
@@ -214,23 +190,14 @@
     @Test
     fun iconGroup_updates_on_change() =
         runBlocking(IMMEDIATE) {
-            connectionRepository.setConnectionInfo(
-                MobileConnectionModel(
-                    resolvedNetworkType = DefaultNetworkType(mobileMappingsProxy.toIconKey(THREE_G))
-                ),
-            )
+            connectionRepository.resolvedNetworkType.value =
+                DefaultNetworkType(mobileMappingsProxy.toIconKey(THREE_G))
 
             var latest: MobileIconGroup? = null
             val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
 
-            connectionRepository.setConnectionInfo(
-                MobileConnectionModel(
-                    resolvedNetworkType =
-                        DefaultNetworkType(
-                            mobileMappingsProxy.toIconKey(FOUR_G),
-                        ),
-                ),
-            )
+            connectionRepository.resolvedNetworkType.value =
+                DefaultNetworkType(mobileMappingsProxy.toIconKey(FOUR_G))
             yield()
 
             assertThat(latest).isEqualTo(TelephonyIcons.FOUR_G)
@@ -241,12 +208,8 @@
     @Test
     fun iconGroup_5g_override_type() =
         runBlocking(IMMEDIATE) {
-            connectionRepository.setConnectionInfo(
-                MobileConnectionModel(
-                    resolvedNetworkType =
-                        OverrideNetworkType(mobileMappingsProxy.toIconKeyOverride(FIVE_G_OVERRIDE))
-                ),
-            )
+            connectionRepository.resolvedNetworkType.value =
+                OverrideNetworkType(mobileMappingsProxy.toIconKeyOverride(FIVE_G_OVERRIDE))
 
             var latest: MobileIconGroup? = null
             val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
@@ -259,12 +222,8 @@
     @Test
     fun iconGroup_default_if_no_lookup() =
         runBlocking(IMMEDIATE) {
-            connectionRepository.setConnectionInfo(
-                MobileConnectionModel(
-                    resolvedNetworkType =
-                        DefaultNetworkType(mobileMappingsProxy.toIconKey(NETWORK_TYPE_UNKNOWN)),
-                ),
-            )
+            connectionRepository.resolvedNetworkType.value =
+                DefaultNetworkType(mobileMappingsProxy.toIconKey(NETWORK_TYPE_UNKNOWN))
 
             var latest: MobileIconGroup? = null
             val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
@@ -277,11 +236,7 @@
     @Test
     fun iconGroup_carrierMerged_usesOverride() =
         runBlocking(IMMEDIATE) {
-            connectionRepository.setConnectionInfo(
-                MobileConnectionModel(
-                    resolvedNetworkType = CarrierMergedNetworkType,
-                ),
-            )
+            connectionRepository.resolvedNetworkType.value = CarrierMergedNetworkType
 
             var latest: MobileIconGroup? = null
             val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
@@ -295,11 +250,8 @@
     fun `icon group - checks default data`() =
         runBlocking(IMMEDIATE) {
             mobileIconsInteractor.defaultDataSubId.value = SUB_1_ID
-            connectionRepository.setConnectionInfo(
-                MobileConnectionModel(
-                    resolvedNetworkType = DefaultNetworkType(mobileMappingsProxy.toIconKey(THREE_G))
-                ),
-            )
+            connectionRepository.resolvedNetworkType.value =
+                DefaultNetworkType(mobileMappingsProxy.toIconKey(THREE_G))
 
             var latest: MobileIconGroup? = null
             val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
@@ -380,9 +332,7 @@
             var latest: Boolean? = null
             val job = underTest.isDataConnected.onEach { latest = it }.launchIn(this)
 
-            connectionRepository.setConnectionInfo(
-                MobileConnectionModel(dataConnectionState = DataConnectionState.Connected)
-            )
+            connectionRepository.dataConnectionState.value = DataConnectionState.Connected
             yield()
 
             assertThat(latest).isTrue()
@@ -396,9 +346,7 @@
             var latest: Boolean? = null
             val job = underTest.isDataConnected.onEach { latest = it }.launchIn(this)
 
-            connectionRepository.setConnectionInfo(
-                MobileConnectionModel(dataConnectionState = DataConnectionState.Disconnected)
-            )
+            connectionRepository.dataConnectionState.value = DataConnectionState.Disconnected
 
             assertThat(latest).isFalse()
 
@@ -411,11 +359,11 @@
             var latest: Boolean? = null
             val job = underTest.isInService.onEach { latest = it }.launchIn(this)
 
-            connectionRepository.setConnectionInfo(MobileConnectionModel(isInService = true))
+            connectionRepository.isInService.value = true
 
             assertThat(latest).isTrue()
 
-            connectionRepository.setConnectionInfo(MobileConnectionModel(isInService = false))
+            connectionRepository.isInService.value = false
 
             assertThat(latest).isFalse()
 
@@ -429,22 +377,13 @@
             val job = underTest.isRoaming.onEach { latest = it }.launchIn(this)
 
             connectionRepository.cdmaRoaming.value = true
-            connectionRepository.setConnectionInfo(
-                MobileConnectionModel(
-                    isGsm = true,
-                    isRoaming = false,
-                )
-            )
+            connectionRepository.isGsm.value = true
+            connectionRepository.isRoaming.value = false
             yield()
 
             assertThat(latest).isFalse()
 
-            connectionRepository.setConnectionInfo(
-                MobileConnectionModel(
-                    isGsm = true,
-                    isRoaming = true,
-                )
-            )
+            connectionRepository.isRoaming.value = true
             yield()
 
             assertThat(latest).isTrue()
@@ -459,23 +398,15 @@
             val job = underTest.isRoaming.onEach { latest = it }.launchIn(this)
 
             connectionRepository.cdmaRoaming.value = false
-            connectionRepository.setConnectionInfo(
-                MobileConnectionModel(
-                    isGsm = false,
-                    isRoaming = true,
-                )
-            )
+            connectionRepository.isGsm.value = false
+            connectionRepository.isRoaming.value = true
             yield()
 
             assertThat(latest).isFalse()
 
             connectionRepository.cdmaRoaming.value = true
-            connectionRepository.setConnectionInfo(
-                MobileConnectionModel(
-                    isGsm = false,
-                    isRoaming = false,
-                )
-            )
+            connectionRepository.isGsm.value = false
+            connectionRepository.isRoaming.value = false
             yield()
 
             assertThat(latest).isTrue()
@@ -490,25 +421,15 @@
             val job = underTest.isRoaming.onEach { latest = it }.launchIn(this)
 
             connectionRepository.cdmaRoaming.value = true
-            connectionRepository.setConnectionInfo(
-                MobileConnectionModel(
-                    isGsm = false,
-                    isRoaming = true,
-                    carrierNetworkChangeActive = true,
-                )
-            )
+            connectionRepository.isGsm.value = false
+            connectionRepository.isRoaming.value = true
+            connectionRepository.carrierNetworkChangeActive.value = true
             yield()
 
             assertThat(latest).isFalse()
 
             connectionRepository.cdmaRoaming.value = true
-            connectionRepository.setConnectionInfo(
-                MobileConnectionModel(
-                    isGsm = true,
-                    isRoaming = true,
-                    carrierNetworkChangeActive = true,
-                )
-            )
+            connectionRepository.isGsm.value = true
             yield()
 
             assertThat(latest).isFalse()
@@ -526,24 +447,20 @@
 
             // Default network name, operator name is non-null, uses the operator name
             connectionRepository.networkName.value = DEFAULT_NAME
-            connectionRepository.setConnectionInfo(
-                MobileConnectionModel(operatorAlphaShort = testOperatorName)
-            )
+            connectionRepository.operatorAlphaShort.value = testOperatorName
             yield()
 
             assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived(testOperatorName))
 
             // Default network name, operator name is null, uses the default
-            connectionRepository.setConnectionInfo(MobileConnectionModel(operatorAlphaShort = null))
+            connectionRepository.operatorAlphaShort.value = null
             yield()
 
             assertThat(latest).isEqualTo(DEFAULT_NAME)
 
             // Derived network name, operator name non-null, uses the derived name
             connectionRepository.networkName.value = DERIVED_NAME
-            connectionRepository.setConnectionInfo(
-                MobileConnectionModel(operatorAlphaShort = testOperatorName)
-            )
+            connectionRepository.operatorAlphaShort.value = testOperatorName
             yield()
 
             assertThat(latest).isEqualTo(DERIVED_NAME)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLoggerTest.kt
new file mode 100644
index 0000000..4aa48d6
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLoggerTest.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.ui
+
+import android.widget.TextView
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.log.LogBufferFactory
+import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger.Companion.getIdForLogging
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.KeyguardMobileIconViewModel
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconViewModel
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.QsMobileIconViewModel
+import com.android.systemui.util.mockito.mock
+import com.google.common.truth.Truth.assertThat
+import java.io.PrintWriter
+import java.io.StringWriter
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+class MobileViewLoggerTest : SysuiTestCase() {
+    private val buffer = LogBufferFactory(DumpManager(), mock()).create("buffer", 10)
+    private val stringWriter = StringWriter()
+    private val printWriter = PrintWriter(stringWriter)
+
+    private val underTest = MobileViewLogger(buffer, mock())
+
+    @Mock private lateinit var flags: StatusBarPipelineFlags
+    @Mock private lateinit var commonViewModel: MobileIconViewModel
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+    }
+
+    @Test
+    fun collectionStarted_dumpHasInfo() {
+        val view = TextView(context)
+        val viewModel = QsMobileIconViewModel(commonViewModel, flags)
+
+        underTest.logCollectionStarted(view, viewModel)
+
+        val dumpString = getDumpString()
+        assertThat(dumpString).contains("${view.getIdForLogging()}, isCollecting=true")
+    }
+
+    @Test
+    fun collectionStarted_multipleViews_dumpHasInfo() {
+        val view = TextView(context)
+        val view2 = TextView(context)
+        val viewModel = QsMobileIconViewModel(commonViewModel, flags)
+        val viewModel2 = KeyguardMobileIconViewModel(commonViewModel, flags)
+
+        underTest.logCollectionStarted(view, viewModel)
+        underTest.logCollectionStarted(view2, viewModel2)
+
+        val dumpString = getDumpString()
+        assertThat(dumpString).contains("${view.getIdForLogging()}, isCollecting=true")
+        assertThat(dumpString).contains("${view2.getIdForLogging()}, isCollecting=true")
+    }
+
+    @Test
+    fun collectionStopped_dumpHasInfo() {
+        val view = TextView(context)
+        val view2 = TextView(context)
+        val viewModel = QsMobileIconViewModel(commonViewModel, flags)
+        val viewModel2 = KeyguardMobileIconViewModel(commonViewModel, flags)
+
+        underTest.logCollectionStarted(view, viewModel)
+        underTest.logCollectionStarted(view2, viewModel2)
+        underTest.logCollectionStopped(view, viewModel)
+
+        val dumpString = getDumpString()
+        assertThat(dumpString).contains("${view.getIdForLogging()}, isCollecting=false")
+        assertThat(dumpString).contains("${view2.getIdForLogging()}, isCollecting=true")
+    }
+
+    private fun getDumpString(): String {
+        underTest.dump(printWriter, args = arrayOf())
+        return stringWriter.toString()
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileViewTest.kt
index e68a397..7420db2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileViewTest.kt
@@ -32,6 +32,7 @@
 import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
 import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconInteractor
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger
 import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.LocationBasedMobileViewModel
 import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconViewModel
 import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.QsMobileIconViewModel
@@ -60,6 +61,7 @@
 
     @Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
     @Mock private lateinit var tableLogBuffer: TableLogBuffer
+    @Mock private lateinit var viewLogger: MobileViewLogger
     @Mock private lateinit var constants: ConnectivityConstants
     private lateinit var interactor: FakeMobileIconInteractor
     private lateinit var airplaneModeRepository: FakeAirplaneModeRepository
@@ -94,7 +96,13 @@
 
     @Test
     fun setVisibleState_icon_iconShownDotHidden() {
-        val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel)
+        val view =
+            ModernStatusBarMobileView.constructAndBind(
+                context,
+                viewLogger,
+                SLOT_NAME,
+                viewModel,
+            )
 
         view.setVisibleState(StatusBarIconView.STATE_ICON, /* animate= */ false)
 
@@ -109,8 +117,13 @@
 
     @Test
     fun setVisibleState_dot_iconHiddenDotShown() {
-        val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel)
-
+        val view =
+            ModernStatusBarMobileView.constructAndBind(
+                context,
+                viewLogger,
+                SLOT_NAME,
+                viewModel,
+            )
         view.setVisibleState(StatusBarIconView.STATE_DOT, /* animate= */ false)
 
         ViewUtils.attachView(view)
@@ -124,8 +137,13 @@
 
     @Test
     fun setVisibleState_hidden_iconAndDotHidden() {
-        val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel)
-
+        val view =
+            ModernStatusBarMobileView.constructAndBind(
+                context,
+                viewLogger,
+                SLOT_NAME,
+                viewModel,
+            )
         view.setVisibleState(StatusBarIconView.STATE_HIDDEN, /* animate= */ false)
 
         ViewUtils.attachView(view)
@@ -142,8 +160,13 @@
         whenever(constants.hasDataCapabilities).thenReturn(false)
         createViewModel()
 
-        val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel)
-
+        val view =
+            ModernStatusBarMobileView.constructAndBind(
+                context,
+                viewLogger,
+                SLOT_NAME,
+                viewModel,
+            )
         ViewUtils.attachView(view)
         testableLooper.processAllMessages()
 
@@ -157,8 +180,13 @@
         whenever(constants.hasDataCapabilities).thenReturn(true)
         createViewModel()
 
-        val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel)
-
+        val view =
+            ModernStatusBarMobileView.constructAndBind(
+                context,
+                viewLogger,
+                SLOT_NAME,
+                viewModel,
+            )
         ViewUtils.attachView(view)
         testableLooper.processAllMessages()
 
@@ -171,8 +199,13 @@
     fun isIconVisible_notAirplaneMode_outputsTrue() {
         airplaneModeRepository.setIsAirplaneMode(false)
 
-        val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel)
-
+        val view =
+            ModernStatusBarMobileView.constructAndBind(
+                context,
+                viewLogger,
+                SLOT_NAME,
+                viewModel,
+            )
         ViewUtils.attachView(view)
         testableLooper.processAllMessages()
 
@@ -185,8 +218,13 @@
     fun isIconVisible_airplaneMode_outputsTrue() {
         airplaneModeRepository.setIsAirplaneMode(true)
 
-        val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel)
-
+        val view =
+            ModernStatusBarMobileView.constructAndBind(
+                context,
+                viewLogger,
+                SLOT_NAME,
+                viewModel,
+            )
         ViewUtils.attachView(view)
         testableLooper.processAllMessages()
 
@@ -198,7 +236,13 @@
     @Test
     fun onDarkChanged_iconHasNewColor() {
         whenever(statusBarPipelineFlags.useDebugColoring()).thenReturn(false)
-        val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel)
+        val view =
+            ModernStatusBarMobileView.constructAndBind(
+                context,
+                viewLogger,
+                SLOT_NAME,
+                viewModel,
+            )
         ViewUtils.attachView(view)
         testableLooper.processAllMessages()
 
@@ -214,7 +258,13 @@
     @Test
     fun setStaticDrawableColor_iconHasNewColor() {
         whenever(statusBarPipelineFlags.useDebugColoring()).thenReturn(false)
-        val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel)
+        val view =
+            ModernStatusBarMobileView.constructAndBind(
+                context,
+                viewLogger,
+                SLOT_NAME,
+                viewModel,
+            )
         ViewUtils.attachView(view)
         testableLooper.processAllMessages()
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt
index f983030..a6d9152 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt
@@ -28,6 +28,7 @@
 import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconViewModelTest.Companion.defaultSignal
 import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
 import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
+import com.android.systemui.util.mockito.mock
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.launchIn
@@ -84,7 +85,7 @@
                 testScope.backgroundScope,
             )
 
-        homeIcon = HomeMobileIconViewModel(commonImpl, statusBarPipelineFlags)
+        homeIcon = HomeMobileIconViewModel(commonImpl, statusBarPipelineFlags, mock())
         qsIcon = QsMobileIconViewModel(commonImpl, statusBarPipelineFlags)
         keyguardIcon = KeyguardMobileIconViewModel(commonImpl, statusBarPipelineFlags)
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
index 4628f84..ddb7f4d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
@@ -24,6 +24,8 @@
 import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger
+import com.android.systemui.statusbar.pipeline.mobile.ui.VerboseMobileViewLogger
 import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
 import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
 import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
@@ -51,6 +53,8 @@
     private lateinit var airplaneModeInteractor: AirplaneModeInteractor
     @Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
     @Mock private lateinit var constants: ConnectivityConstants
+    @Mock private lateinit var logger: MobileViewLogger
+    @Mock private lateinit var verboseLogger: VerboseMobileViewLogger
 
     private val testDispatcher = UnconfinedTestDispatcher()
     private val testScope = TestScope(testDispatcher)
@@ -73,6 +77,8 @@
         underTest =
             MobileIconsViewModel(
                 subscriptionIdsFlow,
+                logger,
+                verboseLogger,
                 interactor,
                 airplaneModeInteractor,
                 constants,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarViewTest.kt
index e4c8fd0..b4039d9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarViewTest.kt
@@ -164,6 +164,10 @@
         override fun getShouldIconBeVisible(): Boolean {
             return shouldIconBeVisibleInternal
         }
+
+        override fun isCollecting(): Boolean {
+            return true
+        }
     }
 }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt
index 12b1664..1c71f8b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt
@@ -368,40 +368,37 @@
 
                 // network = CarrierMerged => not shown
                 TestCase(
+                    enabled = true,
+                    isDefault = true,
+                    forceHidden = false,
                     network =
                         WifiNetworkModel.CarrierMerged(NETWORK_ID, subscriptionId = 1, level = 1),
                     expected = null,
                 ),
 
-                // network = Inactive => not shown
+                // isDefault = false => no networks shown
                 TestCase(
+                    isDefault = false,
                     network = WifiNetworkModel.Inactive,
                     expected = null,
                 ),
-
-                // network = Unavailable => not shown
                 TestCase(
+                    isDefault = false,
                     network = WifiNetworkModel.Unavailable,
                     expected = null,
                 ),
-
-                // network = Active & validated = false => not shown
                 TestCase(
+                    isDefault = false,
                     network = WifiNetworkModel.Active(NETWORK_ID, isValidated = false, level = 3),
                     expected = null,
                 ),
 
-                // network = Active & validated = true => shown
+                // Even though this network is active and validated, we still doesn't want it shown
+                // because wifi isn't the default connection (b/272509965).
                 TestCase(
+                    isDefault = false,
                     network = WifiNetworkModel.Active(NETWORK_ID, isValidated = true, level = 4),
-                    expected =
-                        Expected(
-                            iconResource = WIFI_FULL_ICONS[4],
-                            contentDescription = { context ->
-                                context.getString(WIFI_CONNECTION_STRENGTH[4])
-                            },
-                            description = "Full internet level 4 icon",
-                        ),
+                    expected = null,
                 ),
             )
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImplTest.kt
index 5129f85..6980a0b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImplTest.kt
@@ -90,6 +90,12 @@
     }
 
     @Test
+    fun testFrpNotActiveByDefault() {
+        init()
+        assertThat(controller.isFrpActive).isFalse()
+    }
+
+    @Test
     fun testNotUserSetupByDefault() {
         init()
         assertThat(controller.isUserSetup(START_USER)).isFalse()
@@ -104,6 +110,14 @@
     }
 
     @Test
+    fun testFrpActiveWhenCreated() {
+        settings.putInt(Settings.Secure.SECURE_FRP_MODE, 1)
+        init()
+
+        assertThat(controller.isFrpActive).isTrue()
+    }
+
+    @Test
     fun testUserSetupWhenCreated() {
         settings.putIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 1, START_USER)
         init()
@@ -122,6 +136,16 @@
     }
 
     @Test
+    fun testFrpActiveChange() {
+        init()
+
+        settings.putInt(Settings.Secure.SECURE_FRP_MODE, 1)
+        testableLooper.processAllMessages() // background observer
+
+        assertThat(controller.isFrpActive).isTrue()
+    }
+
+    @Test
     fun testUserSetupChange() {
         init()
 
@@ -164,6 +188,7 @@
         mainExecutor.runAllReady()
 
         verify(listener, never()).onDeviceProvisionedChanged()
+        verify(listener, never()).onFrpActiveChanged()
         verify(listener, never()).onUserSetupChanged()
         verify(listener, never()).onUserSwitched()
     }
@@ -181,6 +206,7 @@
         verify(listener).onUserSwitched()
         verify(listener, never()).onUserSetupChanged()
         verify(listener, never()).onDeviceProvisionedChanged()
+        verify(listener, never()).onFrpActiveChanged()
     }
 
     @Test
@@ -195,6 +221,7 @@
         verify(listener, never()).onUserSwitched()
         verify(listener).onUserSetupChanged()
         verify(listener, never()).onDeviceProvisionedChanged()
+        verify(listener, never()).onFrpActiveChanged()
     }
 
     @Test
@@ -208,10 +235,26 @@
 
         verify(listener, never()).onUserSwitched()
         verify(listener, never()).onUserSetupChanged()
+        verify(listener, never()).onFrpActiveChanged()
         verify(listener).onDeviceProvisionedChanged()
     }
 
     @Test
+    fun testListenerCalledOnFrpActiveChanged() {
+        init()
+        controller.addCallback(listener)
+
+        settings.putInt(Settings.Secure.SECURE_FRP_MODE, 1)
+        testableLooper.processAllMessages()
+        mainExecutor.runAllReady()
+
+        verify(listener, never()).onUserSwitched()
+        verify(listener, never()).onUserSetupChanged()
+        verify(listener, never()).onDeviceProvisionedChanged()
+        verify(listener).onFrpActiveChanged()
+    }
+
+    @Test
     fun testRemoveListener() {
         init()
         controller.addCallback(listener)
@@ -220,11 +263,13 @@
         switchUser(10)
         settings.putIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 1, START_USER)
         settings.putInt(Settings.Global.DEVICE_PROVISIONED, 1)
+        settings.putInt(Settings.Secure.SECURE_FRP_MODE, 1)
 
         testableLooper.processAllMessages()
         mainExecutor.runAllReady()
 
         verify(listener, never()).onDeviceProvisionedChanged()
+        verify(listener, never()).onFrpActiveChanged()
         verify(listener, never()).onUserSetupChanged()
         verify(listener, never()).onUserSwitched()
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
index 48b1732..c8f28bc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
@@ -38,6 +38,7 @@
 import com.android.internal.view.RotationPolicy;
 import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dump.DumpManager;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.time.FakeSystemClock;
 import com.android.systemui.util.wrapper.RotationPolicyWrapper;
@@ -54,11 +55,16 @@
 public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase {
 
     private static final String[] DEFAULT_SETTINGS = new String[]{"0:1", "2:0:1", "1:2"};
+    private static final int[] DEFAULT_FOLDED_STATES = new int[]{0};
+    private static final int[] DEFAULT_HALF_FOLDED_STATES = new int[]{2};
+    private static final int[] DEFAULT_UNFOLDED_STATES = new int[]{1};
+
+    @Mock private DeviceStateManager mDeviceStateManager;
+    @Mock private DeviceStateRotationLockSettingControllerLogger mLogger;
+    @Mock private DumpManager mDumpManager;
 
     private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
     private final FakeExecutor mFakeExecutor = new FakeExecutor(mFakeSystemClock);
-    @Mock
-    private DeviceStateManager mDeviceStateManager;
     private final RotationPolicyWrapper mFakeRotationPolicy = new FakeRotationPolicy();
     private DeviceStateRotationLockSettingController mDeviceStateRotationLockSettingController;
     private DeviceStateManager.DeviceStateCallback mDeviceStateCallback;
@@ -70,6 +76,9 @@
         MockitoAnnotations.initMocks(/* testClass= */ this);
         TestableResources resources = mContext.getOrCreateTestableResources();
         resources.addOverride(R.array.config_perDeviceStateRotationLockDefaults, DEFAULT_SETTINGS);
+        resources.addOverride(R.array.config_foldedDeviceStates, DEFAULT_FOLDED_STATES);
+        resources.addOverride(R.array.config_halfFoldedDeviceStates, DEFAULT_HALF_FOLDED_STATES);
+        resources.addOverride(R.array.config_openDeviceStates, DEFAULT_UNFOLDED_STATES);
 
         ArgumentCaptor<DeviceStateManager.DeviceStateCallback> deviceStateCallbackArgumentCaptor =
                 ArgumentCaptor.forClass(DeviceStateManager.DeviceStateCallback.class);
@@ -78,7 +87,13 @@
         mSettingsManager = DeviceStateRotationLockSettingsManager.getInstance(mContext);
         mDeviceStateRotationLockSettingController =
                 new DeviceStateRotationLockSettingController(
-                        mFakeRotationPolicy, mDeviceStateManager, mFakeExecutor, mSettingsManager);
+                        mFakeRotationPolicy,
+                        mDeviceStateManager,
+                        mFakeExecutor,
+                        mSettingsManager,
+                        mLogger,
+                        mDumpManager
+                );
 
         mDeviceStateRotationLockSettingController.setListening(true);
         verify(mDeviceStateManager)
@@ -173,15 +188,11 @@
     }
 
     @Test
-    public void whenDeviceStateSwitchedToIgnoredState_usePreviousSetting() {
-        initializeSettingsWith(
-                0, DEVICE_STATE_ROTATION_LOCK_IGNORED, 1, DEVICE_STATE_ROTATION_LOCK_UNLOCKED);
-        mFakeRotationPolicy.setRotationLock(true);
-
-        mDeviceStateCallback.onStateChanged(1);
-        assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
-
+    public void whenDeviceStateSwitchedToIgnoredState_useFallbackSetting() {
         mDeviceStateCallback.onStateChanged(0);
+        assertThat(mFakeRotationPolicy.isRotationLocked()).isTrue();
+
+        mDeviceStateCallback.onStateChanged(2);
         assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt
index 586bdc6..6e24941 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt
@@ -685,7 +685,7 @@
         allowSwipeToDismiss: Boolean = false,
     ): ChipbarInfo {
         return ChipbarInfo(
-            TintedIcon(startIcon, tintAttr = null),
+            TintedIcon(startIcon, tint = null),
             text,
             endItem,
             vibrationEffect,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt
index 0413d92..9fe2f56 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt
@@ -40,7 +40,7 @@
 
     @Before
     fun setUp() {
-        progressProvider = PhysicsBasedUnfoldTransitionProgressProvider(foldStateProvider)
+        progressProvider = PhysicsBasedUnfoldTransitionProgressProvider(context, foldStateProvider)
         progressProvider.addCallback(listener)
     }
 
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 8476d0d..bf54d42 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
@@ -16,6 +16,9 @@
 
 package com.android.systemui.unfold.updates
 
+import android.content.Context
+import android.content.res.Configuration
+import android.content.res.Resources
 import android.os.Handler
 import android.testing.AndroidTestingRunner
 import androidx.core.util.Consumer
@@ -33,6 +36,7 @@
 import com.android.systemui.unfold.util.UnfoldKeyguardVisibilityProvider
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.mock
 import com.google.common.truth.Truth.assertThat
 import java.util.concurrent.Executor
 import org.junit.Before
@@ -49,20 +53,19 @@
 @SmallTest
 class DeviceFoldStateProviderTest : SysuiTestCase() {
 
-    @Mock
-    private lateinit var activityTypeProvider: ActivityManagerActivityTypeProvider
+    @Mock private lateinit var activityTypeProvider: ActivityManagerActivityTypeProvider
 
-    @Mock
-    private lateinit var handler: Handler
+    @Mock private lateinit var handler: Handler
 
-    @Mock
-    private lateinit var rotationChangeProvider: RotationChangeProvider
+    @Mock private lateinit var rotationChangeProvider: RotationChangeProvider
 
-    @Mock
-    private lateinit var unfoldKeyguardVisibilityProvider: UnfoldKeyguardVisibilityProvider
+    @Mock private lateinit var unfoldKeyguardVisibilityProvider: UnfoldKeyguardVisibilityProvider
 
-    @Captor
-    private lateinit var rotationListener: ArgumentCaptor<RotationListener>
+    @Mock private lateinit var resources: Resources
+
+    @Mock private lateinit var context: Context
+
+    @Captor private lateinit var rotationListener: ArgumentCaptor<RotationListener>
 
     private val foldProvider = TestFoldProvider()
     private val screenOnStatusProvider = TestScreenOnStatusProvider()
@@ -81,10 +84,13 @@
     fun setUp() {
         MockitoAnnotations.initMocks(this)
 
-        val config = object : UnfoldTransitionConfig by ResourceUnfoldTransitionConfig() {
-            override val halfFoldedTimeoutMillis: Int
-                get() = HALF_OPENED_TIMEOUT_MILLIS.toInt()
-        }
+        val config =
+            object : UnfoldTransitionConfig by ResourceUnfoldTransitionConfig() {
+                override val halfFoldedTimeoutMillis: Int
+                    get() = HALF_OPENED_TIMEOUT_MILLIS.toInt()
+            }
+        whenever(context.resources).thenReturn(resources)
+        whenever(context.mainExecutor).thenReturn(mContext.mainExecutor)
 
         foldStateProvider =
             DeviceFoldStateProvider(
@@ -95,6 +101,7 @@
                 activityTypeProvider,
                 unfoldKeyguardVisibilityProvider,
                 rotationChangeProvider,
+                context,
                 context.mainExecutor,
                 handler
             )
@@ -112,7 +119,8 @@
                 override fun onUnfoldedScreenAvailable() {
                     unfoldedScreenAvailabilityUpdates.add(Unit)
                 }
-            })
+            }
+        )
         foldStateProvider.start()
 
         verify(rotationChangeProvider).addCallback(capture(rotationListener))
@@ -134,6 +142,7 @@
 
         // By default, we're on launcher.
         setupForegroundActivityType(isHomeActivity = true)
+        setIsLargeScreen(true)
     }
 
     @Test
@@ -181,7 +190,7 @@
         sendHingeAngleEvent(10)
 
         assertThat(foldUpdates)
-                .containsExactly(FOLD_UPDATE_START_OPENING, FOLD_UPDATE_START_CLOSING)
+            .containsExactly(FOLD_UPDATE_START_OPENING, FOLD_UPDATE_START_CLOSING)
         assertThat(unfoldedScreenAvailabilityUpdates).hasSize(1)
     }
 
@@ -386,8 +395,10 @@
         setInitialHingeAngle(START_CLOSING_ON_APPS_THRESHOLD_DEGREES)
 
         sendHingeAngleEvent(
-                START_CLOSING_ON_APPS_THRESHOLD_DEGREES -
-                        HINGE_ANGLE_CHANGE_THRESHOLD_DEGREES.toInt() - 1)
+            START_CLOSING_ON_APPS_THRESHOLD_DEGREES -
+                HINGE_ANGLE_CHANGE_THRESHOLD_DEGREES.toInt() -
+                1
+        )
 
         assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING)
     }
@@ -429,8 +440,10 @@
         setInitialHingeAngle(START_CLOSING_ON_APPS_THRESHOLD_DEGREES)
 
         sendHingeAngleEvent(
-                START_CLOSING_ON_APPS_THRESHOLD_DEGREES -
-                        HINGE_ANGLE_CHANGE_THRESHOLD_DEGREES.toInt() - 1)
+            START_CLOSING_ON_APPS_THRESHOLD_DEGREES -
+                HINGE_ANGLE_CHANGE_THRESHOLD_DEGREES.toInt() -
+                1
+        )
 
         assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING)
     }
@@ -470,7 +483,7 @@
         sendHingeAngleEvent(130)
         sendHingeAngleEvent(120)
         assertThat(foldUpdates)
-                .containsExactly(FOLD_UPDATE_START_OPENING, FOLD_UPDATE_START_CLOSING)
+            .containsExactly(FOLD_UPDATE_START_OPENING, FOLD_UPDATE_START_CLOSING)
     }
 
     @Test
@@ -531,8 +544,8 @@
 
         rotationListener.value.onRotationChanged(1)
 
-        assertThat(foldUpdates).containsExactly(
-            FOLD_UPDATE_START_OPENING, FOLD_UPDATE_FINISH_HALF_OPEN)
+        assertThat(foldUpdates)
+            .containsExactly(FOLD_UPDATE_START_OPENING, FOLD_UPDATE_FINISH_HALF_OPEN)
     }
 
     @Test
@@ -545,6 +558,45 @@
         assertThat(foldUpdates).containsExactly(FOLD_UPDATE_FINISH_CLOSED)
     }
 
+    @Test
+    fun onFolding_onSmallScreen_tansitionDoesNotStart() {
+        setIsLargeScreen(false)
+
+        setInitialHingeAngle(120)
+        sendHingeAngleEvent(110)
+        sendHingeAngleEvent(100)
+
+        assertThat(foldUpdates).isEmpty()
+    }
+
+    @Test
+    fun onFolding_onLargeScreen_tansitionStarts() {
+        setIsLargeScreen(true)
+
+        setInitialHingeAngle(120)
+        sendHingeAngleEvent(110)
+        sendHingeAngleEvent(100)
+
+        assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING)
+    }
+
+    @Test
+    fun onUnfold_onSmallScreen_emitsStartOpening() {
+        // the new display state might arrive later, so it shouldn't be used to decide to send the
+        // start opening event, but only for the closing.
+        setFoldState(folded = true)
+        setIsLargeScreen(false)
+        foldUpdates.clear()
+
+        setFoldState(folded = false)
+        screenOnStatusProvider.notifyScreenTurningOn()
+        sendHingeAngleEvent(10)
+        sendHingeAngleEvent(20)
+        screenOnStatusProvider.notifyScreenTurnedOn()
+
+        assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_OPENING)
+    }
+
     private fun setupForegroundActivityType(isHomeActivity: Boolean?) {
         whenever(activityTypeProvider.isHomeActivity).thenReturn(isHomeActivity)
     }
@@ -566,6 +618,13 @@
         foldProvider.notifyFolded(folded)
     }
 
+    private fun setIsLargeScreen(isLargeScreen: Boolean) {
+        val smallestScreenWidth = if (isLargeScreen) { 601 } else { 10 }
+        val configuration = Configuration()
+        configuration.smallestScreenWidthDp = smallestScreenWidth
+        whenever(resources.configuration).thenReturn(configuration)
+    }
+
     private fun fireScreenOnEvent() {
         screenOnStatusProvider.notifyScreenTurnedOn()
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt
index 85cfef7..fd368eb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt
@@ -16,22 +16,24 @@
 
 package com.android.systemui.unfold.updates
 
+import android.content.Context
+import android.hardware.display.DisplayManager
+import android.os.Looper
 import android.testing.AndroidTestingRunner
-import android.view.IRotationWatcher
-import android.view.IWindowManager
+import android.view.Display
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.unfold.updates.RotationChangeProvider.RotationListener
-import com.android.systemui.util.concurrency.FakeExecutor
-import com.android.systemui.util.time.FakeSystemClock
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.utils.os.FakeHandler
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.ArgumentCaptor
 import org.mockito.ArgumentMatchers.any
-import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.Captor
 import org.mockito.Mock
+import org.mockito.Mockito.spy
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.verifyNoMoreInteractions
 import org.mockito.MockitoAnnotations
@@ -42,19 +44,23 @@
 
     private lateinit var rotationChangeProvider: RotationChangeProvider
 
-    @Mock lateinit var windowManagerInterface: IWindowManager
+    @Mock lateinit var displayManager: DisplayManager
     @Mock lateinit var listener: RotationListener
-    @Captor lateinit var rotationWatcher: ArgumentCaptor<IRotationWatcher>
-    private val fakeExecutor = FakeExecutor(FakeSystemClock())
+    @Mock lateinit var display: Display
+    @Captor lateinit var displayListener: ArgumentCaptor<DisplayManager.DisplayListener>
+    private val fakeHandler = FakeHandler(Looper.getMainLooper())
+
+    private lateinit var spyContext: Context
 
     @Before
     fun setup() {
         MockitoAnnotations.initMocks(this)
-        rotationChangeProvider =
-            RotationChangeProvider(windowManagerInterface, context, fakeExecutor)
+        spyContext = spy(context)
+        whenever(spyContext.display).thenReturn(display)
+        rotationChangeProvider = RotationChangeProvider(displayManager, spyContext, fakeHandler)
         rotationChangeProvider.addCallback(listener)
-        fakeExecutor.runAllReady()
-        verify(windowManagerInterface).watchRotation(rotationWatcher.capture(), anyInt())
+        fakeHandler.dispatchQueuedMessages()
+        verify(displayManager).registerDisplayListener(displayListener.capture(), any())
     }
 
     @Test
@@ -70,15 +76,16 @@
         verify(listener).onRotationChanged(42)
 
         rotationChangeProvider.removeCallback(listener)
-        fakeExecutor.runAllReady()
+        fakeHandler.dispatchQueuedMessages()
         sendRotationUpdate(43)
 
-        verify(windowManagerInterface).removeRotationWatcher(any())
+        verify(displayManager).unregisterDisplayListener(any())
         verifyNoMoreInteractions(listener)
     }
 
     private fun sendRotationUpdate(newRotation: Int) {
-        rotationWatcher.value.onRotationChanged(newRotation)
-        fakeExecutor.runAllReady()
+        whenever(display.rotation).thenReturn(newRotation)
+        displayListener.allValues.forEach { it.onDisplayChanged(display.displayId) }
+        fakeHandler.dispatchQueuedMessages()
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
index d00acb8..3ed6cc8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
@@ -29,6 +29,8 @@
 import android.provider.Settings
 import androidx.test.filters.SmallTest
 import com.android.internal.logging.UiEventLogger
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.keyguard.KeyguardUpdateMonitorCallback
 import com.android.systemui.GuestResetOrExitSessionReceiver
 import com.android.systemui.GuestResumeSessionReceiver
 import com.android.systemui.R
@@ -62,6 +64,7 @@
 import com.android.systemui.util.mockito.nullable
 import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
+import junit.framework.Assert.assertNotNull
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.test.StandardTestDispatcher
@@ -72,6 +75,7 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
+import org.mockito.ArgumentCaptor
 import org.mockito.ArgumentMatchers.anyBoolean
 import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.Mock
@@ -96,6 +100,7 @@
     @Mock private lateinit var resumeSessionReceiver: GuestResumeSessionReceiver
     @Mock private lateinit var resetOrExitSessionReceiver: GuestResetOrExitSessionReceiver
     @Mock private lateinit var commandQueue: CommandQueue
+    @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
 
     private lateinit var underTest: UserInteractor
 
@@ -154,6 +159,7 @@
                         repository = telephonyRepository,
                     ),
                 broadcastDispatcher = fakeBroadcastDispatcher,
+                keyguardUpdateMonitor = keyguardUpdateMonitor,
                 backgroundDispatcher = testDispatcher,
                 activityManager = activityManager,
                 refreshUsersScheduler = refreshUsersScheduler,
@@ -177,6 +183,18 @@
     }
 
     @Test
+    fun `testKeyguardUpdateMonitor_onKeyguardGoingAway`() =
+        testScope.runTest {
+            val argumentCaptor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
+            verify(keyguardUpdateMonitor).registerCallback(argumentCaptor.capture())
+
+            argumentCaptor.value.onKeyguardGoingAway()
+
+            val lastValue = collectLastValue(underTest.dialogDismissRequests)
+            assertNotNull(lastValue)
+        }
+
+    @Test
     fun `onRecordSelected - user`() =
         testScope.runTest {
             val userInfos = createUserInfos(count = 3, includeGuest = false)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt
index 22fc32a..daa71b9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt
@@ -25,6 +25,7 @@
 import android.os.UserManager
 import androidx.test.filters.SmallTest
 import com.android.internal.logging.UiEventLogger
+import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.systemui.GuestResetOrExitSessionReceiver
 import com.android.systemui.GuestResumeSessionReceiver
 import com.android.systemui.SysuiTestCase
@@ -80,6 +81,7 @@
     @Mock private lateinit var resumeSessionReceiver: GuestResumeSessionReceiver
     @Mock private lateinit var resetOrExitSessionReceiver: GuestResetOrExitSessionReceiver
     @Mock private lateinit var commandQueue: CommandQueue
+    @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
 
     private lateinit var underTest: StatusBarUserChipViewModel
 
@@ -263,6 +265,7 @@
                             repository = FakeTelephonyRepository(),
                         ),
                     broadcastDispatcher = fakeBroadcastDispatcher,
+                    keyguardUpdateMonitor = keyguardUpdateMonitor,
                     backgroundDispatcher = testDispatcher,
                     activityManager = activityManager,
                     refreshUsersScheduler = refreshUsersScheduler,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
index a2bd8d3..e08ebf4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
@@ -23,6 +23,7 @@
 import android.os.UserManager
 import androidx.test.filters.SmallTest
 import com.android.internal.logging.UiEventLogger
+import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.systemui.GuestResetOrExitSessionReceiver
 import com.android.systemui.GuestResumeSessionReceiver
 import com.android.systemui.SysuiTestCase
@@ -81,6 +82,7 @@
     @Mock private lateinit var resumeSessionReceiver: GuestResumeSessionReceiver
     @Mock private lateinit var resetOrExitSessionReceiver: GuestResetOrExitSessionReceiver
     @Mock private lateinit var commandQueue: CommandQueue
+    @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
 
     private lateinit var underTest: UserSwitcherViewModel
 
@@ -165,6 +167,7 @@
                                     repository = FakeTelephonyRepository(),
                                 ),
                             broadcastDispatcher = fakeBroadcastDispatcher,
+                            keyguardUpdateMonitor = keyguardUpdateMonitor,
                             backgroundDispatcher = testDispatcher,
                             activityManager = activityManager,
                             refreshUsersScheduler = refreshUsersScheduler,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/PostureDependentProximitySensorTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/PostureDependentProximitySensorTest.java
index 075f393..84129be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/PostureDependentProximitySensorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/PostureDependentProximitySensorTest.java
@@ -16,10 +16,16 @@
 
 package com.android.systemui.util.sensors;
 
+import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_CLOSED;
+
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 
 import android.content.res.Resources;
+import android.hardware.Sensor;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
@@ -46,28 +52,52 @@
     @Mock private Resources mResources;
     @Mock private DevicePostureController mDevicePostureController;
     @Mock private AsyncSensorManager mSensorManager;
+    @Mock private Sensor mMockedPrimaryProxSensor;
 
     @Captor private ArgumentCaptor<DevicePostureController.Callback> mPostureListenerCaptor =
             ArgumentCaptor.forClass(DevicePostureController.Callback.class);
     private DevicePostureController.Callback mPostureListener;
 
-    private PostureDependentProximitySensor mProximitySensor;
-    private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
+    private PostureDependentProximitySensor mPostureDependentProximitySensor;
+    private ThresholdSensor[] mPrimaryProxSensors;
+    private ThresholdSensor[] mSecondaryProxSensors;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
         allowTestableLooperAsMainThread();
 
-        mProximitySensor = new PostureDependentProximitySensor(
-                new ThresholdSensor[DevicePostureController.SUPPORTED_POSTURES_SIZE],
-                new ThresholdSensor[DevicePostureController.SUPPORTED_POSTURES_SIZE],
-                mFakeExecutor,
+        setupProximitySensors(DEVICE_POSTURE_CLOSED);
+        mPostureDependentProximitySensor = new PostureDependentProximitySensor(
+                mPrimaryProxSensors,
+                mSecondaryProxSensors,
+                new FakeExecutor(new FakeSystemClock()),
                 new FakeExecution(),
                 mDevicePostureController
         );
     }
 
+    /**
+     * Support a proximity sensor only for the given devicePosture for the primary sensor.
+     * Otherwise, all other postures don't support prox.
+     */
+    private void setupProximitySensors(
+            @DevicePostureController.DevicePostureInt int proxExistsForPosture) {
+        final ThresholdSensorImpl.Builder sensorBuilder = new ThresholdSensorImpl.BuilderFactory(
+                mResources, mSensorManager, new FakeExecution()).createBuilder();
+
+        mPrimaryProxSensors = new ThresholdSensor[DevicePostureController.SUPPORTED_POSTURES_SIZE];
+        mSecondaryProxSensors =
+                new ThresholdSensor[DevicePostureController.SUPPORTED_POSTURES_SIZE];
+        for (int i = 0; i < DevicePostureController.SUPPORTED_POSTURES_SIZE; i++) {
+            mPrimaryProxSensors[i] = sensorBuilder.setSensor(null).setThresholdValue(0).build();
+            mSecondaryProxSensors[i] = sensorBuilder.setSensor(null).setThresholdValue(0).build();
+        }
+
+        mPrimaryProxSensors[proxExistsForPosture] = sensorBuilder
+                .setSensor(mMockedPrimaryProxSensor).setThresholdValue(5).build();
+    }
+
     @Test
     public void testPostureChangeListenerAdded() {
         capturePostureListener();
@@ -83,30 +113,59 @@
 
         // THEN device posture is updated to DEVICE_POSTURE_OPENED
         assertEquals(DevicePostureController.DEVICE_POSTURE_OPENED,
-                mProximitySensor.mDevicePosture);
+                mPostureDependentProximitySensor.mDevicePosture);
 
         // WHEN the posture changes to DEVICE_POSTURE_CLOSED
-        mPostureListener.onPostureChanged(DevicePostureController.DEVICE_POSTURE_CLOSED);
+        mPostureListener.onPostureChanged(DEVICE_POSTURE_CLOSED);
 
         // THEN device posture is updated to DEVICE_POSTURE_CLOSED
-        assertEquals(DevicePostureController.DEVICE_POSTURE_CLOSED,
-                mProximitySensor.mDevicePosture);
+        assertEquals(DEVICE_POSTURE_CLOSED,
+                mPostureDependentProximitySensor.mDevicePosture);
 
         // WHEN the posture changes to DEVICE_POSTURE_FLIPPED
         mPostureListener.onPostureChanged(DevicePostureController.DEVICE_POSTURE_FLIPPED);
 
         // THEN device posture is updated to DEVICE_POSTURE_FLIPPED
         assertEquals(DevicePostureController.DEVICE_POSTURE_FLIPPED,
-                mProximitySensor.mDevicePosture);
+                mPostureDependentProximitySensor.mDevicePosture);
 
         // WHEN the posture changes to DEVICE_POSTURE_HALF_OPENED
         mPostureListener.onPostureChanged(DevicePostureController.DEVICE_POSTURE_HALF_OPENED);
 
         // THEN device posture is updated to DEVICE_POSTURE_HALF_OPENED
         assertEquals(DevicePostureController.DEVICE_POSTURE_HALF_OPENED,
-                mProximitySensor.mDevicePosture);
+                mPostureDependentProximitySensor.mDevicePosture);
     }
 
+    @Test
+    public void proxSensorRegisters_proxSensorValid() {
+        // GIVEN posture that supports a valid posture with a prox sensor
+        capturePostureListener();
+        mPostureListener.onPostureChanged(DEVICE_POSTURE_CLOSED);
+
+        // WHEN a listener registers
+        mPostureDependentProximitySensor.register(mock(ThresholdSensor.Listener.class));
+
+        // THEN PostureDependentProximitySensor is registered
+        assertTrue(mPostureDependentProximitySensor.isRegistered());
+    }
+
+    @Test
+    public void proxSensorReregisters_postureChangesAndNewlySupportsProx() {
+        // GIVEN there's a registered listener but posture doesn't support prox
+        assertFalse(mPostureDependentProximitySensor.isRegistered());
+        mPostureDependentProximitySensor.register(mock(ThresholdSensor.Listener.class));
+        assertFalse(mPostureDependentProximitySensor.isRegistered());
+
+        // WHEN posture that supports a valid posture with a prox sensor
+        capturePostureListener();
+        mPostureListener.onPostureChanged(DEVICE_POSTURE_CLOSED);
+
+        // THEN PostureDependentProximitySensor is registered
+        assertTrue(mPostureDependentProximitySensor.isRegistered());
+    }
+
+
     private void capturePostureListener() {
         verify(mDevicePostureController).addCallback(mPostureListenerCaptor.capture());
         mPostureListener = mPostureListenerCaptor.getValue();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java
index 046ad12..f9bfafc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.util.service;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.clearInvocations;
@@ -169,4 +171,19 @@
         verify(mCallback).onDisconnected(eq(connection),
                 eq(ObservableServiceConnection.DISCONNECT_REASON_UNBIND));
     }
+
+    @Test
+    public void testBindServiceThrowsError() {
+        ObservableServiceConnection<Foo> connection = new ObservableServiceConnection<>(mContext,
+                mIntent, mExecutor, mTransformer);
+        connection.addCallback(mCallback);
+
+        when(mContext.bindService(eq(mIntent), anyInt(), eq(mExecutor), eq(connection)))
+                .thenThrow(new SecurityException());
+
+        // Verify that the exception was caught and that bind returns false, and we properly
+        // unbind.
+        assertThat(connection.bind()).isFalse();
+        verify(mContext).unbindService(connection);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java
index b1950ea..692af6a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java
@@ -22,6 +22,9 @@
 import static org.junit.Assert.assertEquals;
 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.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -63,6 +66,7 @@
 import org.mockito.MockitoAnnotations;
 
 import java.util.Collections;
+import java.util.List;
 
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
@@ -99,6 +103,8 @@
     ArgumentCaptor<PendingIntent> mIntentCaptor;
     @Captor
     ArgumentCaptor<QuickAccessWalletClient.OnWalletCardsRetrievedCallback> mCallbackCaptor;
+    @Captor
+    ArgumentCaptor<List<WalletCardViewInfo>> mPaymentCardDataCaptor;
     private WalletScreenController mController;
     private TestableLooper mTestableLooper;
 
@@ -107,7 +113,7 @@
         MockitoAnnotations.initMocks(this);
         mTestableLooper = TestableLooper.get(this);
         when(mUserTracker.getUserContext()).thenReturn(mContext);
-        mWalletView = new WalletView(mContext);
+        mWalletView = spy(new WalletView(mContext));
         mWalletView.getCardCarousel().setExpectedViewWidth(CARD_CAROUSEL_WIDTH);
         when(mWalletClient.getLogo()).thenReturn(mWalletLogo);
         when(mWalletClient.getShortcutLongLabel()).thenReturn(SHORTCUT_LONG_LABEL);
@@ -430,6 +436,41 @@
         assertEquals(GONE, mWalletView.getVisibility());
     }
 
+    @Test
+    public void onWalletCardsRetrieved_cardDataAllUnknown_showsAllCards() {
+        List<WalletCard> walletCardList = List.of(
+                createWalletCardWithType(mContext, WalletCard.CARD_TYPE_UNKNOWN),
+                createWalletCardWithType(mContext, WalletCard.CARD_TYPE_UNKNOWN),
+                createWalletCardWithType(mContext, WalletCard.CARD_TYPE_UNKNOWN));
+        GetWalletCardsResponse response = new GetWalletCardsResponse(walletCardList, 0);
+        mController.onWalletCardsRetrieved(response);
+        mTestableLooper.processAllMessages();
+
+        verify(mWalletView).showCardCarousel(mPaymentCardDataCaptor.capture(), anyInt(),
+                anyBoolean(),
+                anyBoolean());
+        List<WalletCardViewInfo> paymentCardData = mPaymentCardDataCaptor.getValue();
+        assertEquals(paymentCardData.size(), walletCardList.size());
+    }
+
+    @Test
+    public void onWalletCardsRetrieved_cardDataDifferentTypes_onlyShowsPayment() {
+        List<WalletCard> walletCardList = List.of(createWalletCardWithType(mContext,
+                        WalletCard.CARD_TYPE_UNKNOWN),
+                createWalletCardWithType(mContext, WalletCard.CARD_TYPE_PAYMENT),
+                createWalletCardWithType(mContext, WalletCard.CARD_TYPE_NON_PAYMENT)
+                );
+        GetWalletCardsResponse response = new GetWalletCardsResponse(walletCardList, 0);
+        mController.onWalletCardsRetrieved(response);
+        mTestableLooper.processAllMessages();
+
+        verify(mWalletView).showCardCarousel(mPaymentCardDataCaptor.capture(), anyInt(),
+                anyBoolean(),
+                anyBoolean());
+        List<WalletCardViewInfo> paymentCardData = mPaymentCardDataCaptor.getValue();
+        assertEquals(paymentCardData.size(), 1);
+    }
+
     private WalletCard createNonActiveWalletCard(Context context) {
         PendingIntent pendingIntent =
                 PendingIntent.getActivity(context, 0, mWalletIntent, PendingIntent.FLAG_IMMUTABLE);
@@ -457,6 +498,15 @@
                 .build();
     }
 
+    private WalletCard createWalletCardWithType(Context context, int cardType) {
+        PendingIntent pendingIntent =
+                PendingIntent.getActivity(context, 0, mWalletIntent, PendingIntent.FLAG_IMMUTABLE);
+        return new WalletCard.Builder(CARD_ID_1, cardType, createIcon(), "•••• 1234", pendingIntent)
+                .setCardIcon(createIcon())
+                .setCardLabel("Hold to reader")
+                .build();
+    }
+
     private WalletCard createCrazyWalletCard(Context context, boolean hasLabel) {
         PendingIntent pendingIntent =
                 PendingIntent.getActivity(context, 0, mWalletIntent, PendingIntent.FLAG_IMMUTABLE);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
index 31cce4f..468c5a7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
@@ -88,7 +88,7 @@
     @Mock
     private Bitmap mWallpaperBitmap;
     FakeSystemClock mFakeSystemClock = new FakeSystemClock();
-    FakeExecutor mFakeBackgroundExecutor = new FakeExecutor(mFakeSystemClock);
+    FakeExecutor mFakeExecutor = new FakeExecutor(mFakeSystemClock);
 
     @Before
     public void setUp() throws Exception {
@@ -125,7 +125,7 @@
 
     @Test
     public void testBitmapWallpaper_normal() {
-        // Will use a image wallpaper with dimensions DISPLAY_WIDTH x DISPLAY_WIDTH.
+        // Will use an image wallpaper with dimensions DISPLAY_WIDTH x DISPLAY_WIDTH.
         // Then we expect the surface size will be also DISPLAY_WIDTH x DISPLAY_WIDTH.
         int bitmapSide = DISPLAY_WIDTH;
         testSurfaceHelper(
@@ -137,7 +137,7 @@
 
     @Test
     public void testBitmapWallpaper_low_resolution() {
-        // Will use a image wallpaper with dimensions BMP_WIDTH x BMP_HEIGHT.
+        // Will use an image wallpaper with dimensions BMP_WIDTH x BMP_HEIGHT.
         // Then we expect the surface size will be also BMP_WIDTH x BMP_HEIGHT.
         testSurfaceHelper(LOW_BMP_WIDTH /* bitmapWidth */,
                 LOW_BMP_HEIGHT /* bitmapHeight */,
@@ -161,13 +161,13 @@
         ImageWallpaper.CanvasEngine spyEngine = getSpyEngine();
         spyEngine.onCreate(mSurfaceHolder);
         spyEngine.onSurfaceRedrawNeeded(mSurfaceHolder);
-        assertThat(mFakeBackgroundExecutor.numPending()).isAtLeast(1);
+        assertThat(mFakeExecutor.numPending()).isAtLeast(1);
 
         int n = 0;
-        while (mFakeBackgroundExecutor.numPending() >= 1) {
+        while (mFakeExecutor.numPending() >= 1) {
             n++;
             assertThat(n).isAtMost(10);
-            mFakeBackgroundExecutor.runNextReady();
+            mFakeExecutor.runNextReady();
             mFakeSystemClock.advanceTime(1000);
         }
 
@@ -176,7 +176,7 @@
     }
 
     private ImageWallpaper createImageWallpaper() {
-        return new ImageWallpaper(mFakeBackgroundExecutor, mUserTracker) {
+        return new ImageWallpaper(mFakeExecutor, mUserTracker) {
             @Override
             public Engine onCreateEngine() {
                 return new CanvasEngine() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index bc33439..e180415 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -355,7 +355,6 @@
         TestableNotificationInterruptStateProviderImpl interruptionStateProvider =
                 new TestableNotificationInterruptStateProviderImpl(mContext.getContentResolver(),
                         mock(PowerManager.class),
-                        mock(IDreamManager.class),
                         mock(AmbientDisplayConfiguration.class),
                         mock(StatusBarStateController.class),
                         mock(KeyguardStateController.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java
index ceee0bc..4e14bbf6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java
@@ -20,7 +20,6 @@
 import android.hardware.display.AmbientDisplayConfiguration;
 import android.os.Handler;
 import android.os.PowerManager;
-import android.service.dreams.IDreamManager;
 
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -39,7 +38,6 @@
     TestableNotificationInterruptStateProviderImpl(
             ContentResolver contentResolver,
             PowerManager powerManager,
-            IDreamManager dreamManager,
             AmbientDisplayConfiguration ambientDisplayConfiguration,
             StatusBarStateController statusBarStateController,
             KeyguardStateController keyguardStateController,
@@ -53,7 +51,6 @@
             UserTracker userTracker) {
         super(contentResolver,
                 powerManager,
-                dreamManager,
                 ambientDisplayConfiguration,
                 batteryController,
                 statusBarStateController,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/data/repository/FakeKeyboardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/data/repository/FakeKeyboardRepository.kt
new file mode 100644
index 0000000..4e43546
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/data/repository/FakeKeyboardRepository.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyboard.data.repository
+
+import com.android.systemui.keyboard.shared.model.BacklightModel
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.filterNotNull
+
+class FakeKeyboardRepository : KeyboardRepository {
+
+    private val _keyboardConnected = MutableStateFlow(false)
+    override val keyboardConnected: Flow<Boolean> = _keyboardConnected
+
+    private val _backlightState: MutableStateFlow<BacklightModel?> = MutableStateFlow(null)
+    // filtering to make sure backlight doesn't have default initial value
+    override val backlight: Flow<BacklightModel> = _backlightState.filterNotNull()
+
+    fun setBacklight(state: BacklightModel) {
+        _backlightState.value = state
+    }
+
+    fun setKeyboardConnected(connected: Boolean) {
+        _keyboardConnected.value = connected
+    }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardBouncerRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardBouncerRepository.kt
index 9cdce20..1dda472 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardBouncerRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardBouncerRepository.kt
@@ -19,21 +19,16 @@
 
 import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN
 import com.android.systemui.keyguard.shared.model.BouncerShowMessageModel
-import com.android.systemui.keyguard.shared.model.KeyguardBouncerModel
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.asStateFlow
 
 /** Fake implementation of [KeyguardRepository] */
 class FakeKeyguardBouncerRepository : KeyguardBouncerRepository {
-    private val _primaryBouncerVisible = MutableStateFlow(false)
-    override val primaryBouncerVisible = _primaryBouncerVisible.asStateFlow()
-    private val _primaryBouncerShow = MutableStateFlow<KeyguardBouncerModel?>(null)
+    private val _primaryBouncerShow = MutableStateFlow(false)
     override val primaryBouncerShow = _primaryBouncerShow.asStateFlow()
     private val _primaryBouncerShowingSoon = MutableStateFlow(false)
     override val primaryBouncerShowingSoon = _primaryBouncerShowingSoon.asStateFlow()
-    private val _primaryBouncerHide = MutableStateFlow(false)
-    override val primaryBouncerHide = _primaryBouncerHide.asStateFlow()
     private val _primaryBouncerStartingToHide = MutableStateFlow(false)
     override val primaryBouncerStartingToHide = _primaryBouncerStartingToHide.asStateFlow()
     private val _primaryBouncerDisappearAnimation = MutableStateFlow<Runnable?>(null)
@@ -67,10 +62,6 @@
         _primaryBouncerScrimmed.value = isScrimmed
     }
 
-    override fun setPrimaryVisible(isVisible: Boolean) {
-        _primaryBouncerVisible.value = isVisible
-    }
-
     override fun setAlternateVisible(isVisible: Boolean) {
         _isAlternateBouncerVisible.value = isVisible
     }
@@ -79,18 +70,14 @@
         _isAlternateBouncerUIAvailable.value = isAvailable
     }
 
-    override fun setPrimaryShow(keyguardBouncerModel: KeyguardBouncerModel?) {
-        _primaryBouncerShow.value = keyguardBouncerModel
+    override fun setPrimaryShow(isShowing: Boolean) {
+        _primaryBouncerShow.value = isShowing
     }
 
     override fun setPrimaryShowingSoon(showingSoon: Boolean) {
         _primaryBouncerShowingSoon.value = showingSoon
     }
 
-    override fun setPrimaryHide(hide: Boolean) {
-        _primaryBouncerHide.value = hide
-    }
-
     override fun setPrimaryStartingToHide(startingToHide: Boolean) {
         _primaryBouncerStartingToHide.value = startingToHide
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java
index 926c6c5..c664c99 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java
@@ -47,7 +47,12 @@
     }
 
     @Override
-    public void setExternalIcon(String slot) {
+    public void setIconFromTile(String slot, StatusBarIcon icon) {
+
+    }
+
+    @Override
+    public void removeIconForTile(String slot) {
 
     }
 
@@ -57,11 +62,6 @@
     }
 
     @Override
-    public void setIcon(String slot, StatusBarIcon icon) {
-
-    }
-
-    @Override
     public void setWifiIcon(String slot, WifiIconState state) {
     }
 
@@ -98,10 +98,6 @@
     }
 
     @Override
-    public void removeAllIconsForExternalSlot(String slot) {
-    }
-
-    @Override
     public void setIconAccessibilityLiveRegion(String slot, int mode) {
     }
 
diff --git a/packages/SystemUI/unfold/Android.bp b/packages/SystemUI/unfold/Android.bp
index 180b611..2e0a946 100644
--- a/packages/SystemUI/unfold/Android.bp
+++ b/packages/SystemUI/unfold/Android.bp
@@ -35,6 +35,7 @@
     ],
     kotlincflags: ["-Xjvm-default=enable"],
     java_version: "1.8",
+    sdk_version: "current",
     min_sdk_version: "current",
     plugins: ["dagger2-compiler"],
 }
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt
index 068347c..c3a6cf0 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt
@@ -19,14 +19,15 @@
 import android.content.ContentResolver
 import android.content.Context
 import android.hardware.SensorManager
+import android.hardware.display.DisplayManager
 import android.os.Handler
-import android.view.IWindowManager
 import com.android.systemui.unfold.config.UnfoldTransitionConfig
 import com.android.systemui.unfold.dagger.UnfoldMain
 import com.android.systemui.unfold.dagger.UnfoldSingleThreadBg
 import com.android.systemui.unfold.progress.RemoteUnfoldTransitionReceiver
 import com.android.systemui.unfold.updates.FoldProvider
 import com.android.systemui.unfold.updates.RotationChangeProvider
+import com.android.systemui.unfold.updates.hinge.HingeAngleProvider
 import com.android.systemui.unfold.updates.screen.ScreenStatusProvider
 import com.android.systemui.unfold.util.CurrentActivityTypeProvider
 import com.android.systemui.unfold.util.UnfoldTransitionATracePrefix
@@ -61,12 +62,13 @@
             @BindsInstance @UnfoldMain executor: Executor,
             @BindsInstance @UnfoldSingleThreadBg singleThreadBgExecutor: Executor,
             @BindsInstance @UnfoldTransitionATracePrefix tracingTagPrefix: String,
-            @BindsInstance windowManager: IWindowManager,
+            @BindsInstance displayManager: DisplayManager,
             @BindsInstance contentResolver: ContentResolver = context.contentResolver
         ): UnfoldSharedComponent
     }
 
     val unfoldTransitionProvider: Optional<UnfoldTransitionProgressProvider>
+    val hingeAngleProvider: HingeAngleProvider
     val rotationChangeProvider: RotationChangeProvider
 }
 
@@ -84,8 +86,9 @@
             @BindsInstance context: Context,
             @BindsInstance config: UnfoldTransitionConfig,
             @BindsInstance @UnfoldMain executor: Executor,
+            @BindsInstance @UnfoldMain handler: Handler,
             @BindsInstance @UnfoldSingleThreadBg singleThreadBgExecutor: Executor,
-            @BindsInstance windowManager: IWindowManager,
+            @BindsInstance displayManager: DisplayManager,
             @BindsInstance @UnfoldTransitionATracePrefix tracingTagPrefix: String,
         ): RemoteUnfoldSharedComponent
     }
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
index 8eb79df..1839919 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
@@ -19,8 +19,8 @@
 
 import android.content.Context
 import android.hardware.SensorManager
+import android.hardware.display.DisplayManager
 import android.os.Handler
-import android.view.IWindowManager
 import com.android.systemui.unfold.config.UnfoldTransitionConfig
 import com.android.systemui.unfold.updates.FoldProvider
 import com.android.systemui.unfold.updates.screen.ScreenStatusProvider
@@ -47,7 +47,7 @@
         mainExecutor: Executor,
         singleThreadBgExecutor: Executor,
         tracingTagPrefix: String,
-        windowManager: IWindowManager,
+        displayManager: DisplayManager,
 ): UnfoldSharedComponent =
         DaggerUnfoldSharedComponent.factory()
                 .create(
@@ -61,7 +61,7 @@
                         mainExecutor,
                         singleThreadBgExecutor,
                         tracingTagPrefix,
-                        windowManager,
+                        displayManager,
                 )
 
 /**
@@ -73,16 +73,18 @@
         context: Context,
         config: UnfoldTransitionConfig,
         mainExecutor: Executor,
+        mainHandler: Handler,
         singleThreadBgExecutor: Executor,
         tracingTagPrefix: String,
-        windowManager: IWindowManager,
+        displayManager: DisplayManager,
         ): RemoteUnfoldSharedComponent =
         DaggerRemoteUnfoldSharedComponent.factory()
                 .create(
                         context,
                         config,
                         mainExecutor,
+                        mainHandler,
                         singleThreadBgExecutor,
-                        windowManager,
+                        displayManager,
                         tracingTagPrefix,
                 )
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/ScreenSizeFoldProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/ScreenSizeFoldProvider.kt
index 2044f05..380c1fc 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/ScreenSizeFoldProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/ScreenSizeFoldProvider.kt
@@ -53,4 +53,4 @@
     }
 }
 
-private const val INNER_SCREEN_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP = 600
+internal const val INNER_SCREEN_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP = 600
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
index d19b414..f8f168b 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
@@ -15,9 +15,15 @@
  */
 package com.android.systemui.unfold.progress
 
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.ObjectAnimator
+import android.animation.ValueAnimator
+import android.content.Context
 import android.os.Trace
-import android.os.Trace.TRACE_TAG_APP
+import android.util.FloatProperty
 import android.util.Log
+import android.view.animation.AnimationUtils.loadInterpolator
 import androidx.dynamicanimation.animation.DynamicAnimation
 import androidx.dynamicanimation.animation.FloatPropertyCompat
 import androidx.dynamicanimation.animation.SpringAnimation
@@ -35,14 +41,22 @@
 import javax.inject.Inject
 
 /** Maps fold updates to unfold transition progress using DynamicAnimation. */
-class PhysicsBasedUnfoldTransitionProgressProvider @Inject constructor(
-    private val foldStateProvider: FoldStateProvider
-) : UnfoldTransitionProgressProvider, FoldUpdatesListener, DynamicAnimation.OnAnimationEndListener {
+class PhysicsBasedUnfoldTransitionProgressProvider
+@Inject
+constructor(context: Context, private val foldStateProvider: FoldStateProvider) :
+    UnfoldTransitionProgressProvider, FoldUpdatesListener, DynamicAnimation.OnAnimationEndListener {
+
+    private val emphasizedInterpolator =
+        loadInterpolator(context, android.R.interpolator.fast_out_extra_slow_in)
+
+    private var cannedAnimator: ValueAnimator? = null
 
     private val springAnimation =
-        SpringAnimation(this, AnimationProgressProperty).apply {
-            addEndListener(this@PhysicsBasedUnfoldTransitionProgressProvider)
-        }
+        SpringAnimation(
+                this,
+                FloatPropertyCompat.createFloatPropertyCompat(AnimationProgressProperty)
+            )
+            .apply { addEndListener(this@PhysicsBasedUnfoldTransitionProgressProvider) }
 
     private var isTransitionRunning = false
     private var isAnimatedCancelRunning = false
@@ -77,7 +91,8 @@
 
     override fun onFoldUpdate(@FoldUpdate update: Int) {
         when (update) {
-            FOLD_UPDATE_FINISH_FULL_OPEN, FOLD_UPDATE_FINISH_HALF_OPEN -> {
+            FOLD_UPDATE_FINISH_FULL_OPEN,
+            FOLD_UPDATE_FINISH_HALF_OPEN -> {
                 // Do not cancel if we haven't started the transition yet.
                 // This could happen when we fully unfolded the device before the screen
                 // became available. In this case we start and immediately cancel the animation
@@ -101,6 +116,14 @@
                     // the transition continues running.
                     if (isAnimatedCancelRunning) {
                         isAnimatedCancelRunning = false
+
+                        // Switching to spring animation, start the animation if it
+                        // is not running already
+                        springAnimation.animateToFinalPosition(1.0f)
+
+                        cannedAnimator?.removeAllListeners()
+                        cannedAnimator?.cancel()
+                        cannedAnimator = null
                     }
                 } else {
                     startTransition(startValue = 1f)
@@ -110,7 +133,7 @@
 
         if (DEBUG) {
             Log.d(TAG, "onFoldUpdate = ${update.name()}")
-            Trace.traceCounter(Trace.TRACE_TAG_APP, "fold_update", update)
+            Trace.setCounter("fold_update", update.toLong())
         }
     }
 
@@ -131,13 +154,22 @@
             }
 
             isAnimatedCancelRunning = true
-            springAnimation.animateToFinalPosition(endValue)
+
+            if (USE_CANNED_ANIMATION) {
+                startCannedCancelAnimation()
+            } else {
+                springAnimation.animateToFinalPosition(endValue)
+            }
         } else {
             transitionProgress = endValue
             isAnimatedCancelRunning = false
             isTransitionRunning = false
             springAnimation.cancel()
 
+            cannedAnimator?.removeAllListeners()
+            cannedAnimator?.cancel()
+            cannedAnimator = null
+
             listeners.forEach { it.onTransitionFinished() }
 
             if (DEBUG) {
@@ -158,7 +190,7 @@
     }
 
     private fun onStartTransition() {
-        Trace.beginSection( "$TAG#onStartTransition")
+        Trace.beginSection("$TAG#onStartTransition")
         listeners.forEach { it.onTransitionStarted() }
         Trace.endSection()
 
@@ -196,8 +228,39 @@
         listeners.remove(listener)
     }
 
+    private fun startCannedCancelAnimation() {
+        cannedAnimator?.cancel()
+        cannedAnimator = null
+
+        // Temporary remove listener to cancel the spring animation without
+        // finishing the transition
+        springAnimation.removeEndListener(this)
+        springAnimation.cancel()
+        springAnimation.addEndListener(this)
+
+        cannedAnimator =
+            ObjectAnimator.ofFloat(this, AnimationProgressProperty, transitionProgress, 1f).apply {
+                addListener(CannedAnimationListener())
+                duration =
+                    (CANNED_ANIMATION_DURATION_MS.toFloat() * (1f - transitionProgress)).toLong()
+                interpolator = emphasizedInterpolator
+                start()
+            }
+    }
+
+    private inner class CannedAnimationListener : AnimatorListenerAdapter() {
+        override fun onAnimationStart(animator: Animator) {
+            Trace.beginAsyncSection("$TAG#cannedAnimatorRunning", 0)
+        }
+
+        override fun onAnimationEnd(animator: Animator) {
+            cancelTransition(1f, animate = false)
+            Trace.endAsyncSection("$TAG#cannedAnimatorRunning", 0)
+        }
+    }
+
     private object AnimationProgressProperty :
-        FloatPropertyCompat<PhysicsBasedUnfoldTransitionProgressProvider>("animation_progress") {
+        FloatProperty<PhysicsBasedUnfoldTransitionProgressProvider>("animation_progress") {
 
         override fun setValue(
             provider: PhysicsBasedUnfoldTransitionProgressProvider,
@@ -206,7 +269,7 @@
             provider.transitionProgress = value
         }
 
-        override fun getValue(provider: PhysicsBasedUnfoldTransitionProgressProvider): Float =
+        override fun get(provider: PhysicsBasedUnfoldTransitionProgressProvider): Float =
             provider.transitionProgress
     }
 }
@@ -214,6 +277,8 @@
 private const val TAG = "PhysicsBasedUnfoldTransitionProgressProvider"
 private const val DEBUG = true
 
+private const val USE_CANNED_ANIMATION = true
+private const val CANNED_ANIMATION_DURATION_MS = 1000
 private const val SPRING_STIFFNESS = 600.0f
 private const val MINIMAL_VISIBLE_CHANGE = 0.001f
 private const val FINAL_HINGE_ANGLE_POSITION = 165f
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
index 82fd225..a633a5e 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
@@ -15,12 +15,14 @@
  */
 package com.android.systemui.unfold.updates
 
+import android.content.Context
 import android.os.Handler
 import android.os.Trace
 import android.util.Log
 import androidx.annotation.FloatRange
 import androidx.annotation.VisibleForTesting
 import androidx.core.util.Consumer
+import com.android.systemui.unfold.compat.INNER_SCREEN_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP
 import com.android.systemui.unfold.config.UnfoldTransitionConfig
 import com.android.systemui.unfold.dagger.UnfoldMain
 import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdate
@@ -45,6 +47,7 @@
     private val activityTypeProvider: CurrentActivityTypeProvider,
     private val unfoldKeyguardVisibilityProvider: UnfoldKeyguardVisibilityProvider,
     private val rotationChangeProvider: RotationChangeProvider,
+    private val context: Context,
     @UnfoldMain private val mainExecutor: Executor,
     @UnfoldMain private val handler: Handler
 ) : FoldStateProvider {
@@ -119,7 +122,7 @@
                     "lastHingeAngle: $lastHingeAngle, " +
                     "lastHingeAngleBeforeTransition: $lastHingeAngleBeforeTransition"
             )
-            Trace.traceCounter(Trace.TRACE_TAG_APP, "hinge_angle", angle.toInt())
+            Trace.setCounter("hinge_angle", angle.toLong())
         }
 
         val currentDirection =
@@ -136,6 +139,7 @@
         val isFullyOpened = FULLY_OPEN_DEGREES - angle < FULLY_OPEN_THRESHOLD_DEGREES
         val eventNotAlreadyDispatched = lastFoldUpdate != transitionUpdate
         val screenAvailableEventSent = isUnfoldHandled
+        val isOnLargeScreen = isOnLargeScreen()
 
         if (
             angleChangeSurpassedThreshold && // Do not react immediately to small changes in angle
@@ -144,7 +148,9 @@
                                   // angle range as closing threshold could overlap this range
                 screenAvailableEventSent && // do not send transition event if we are still in the
                                             // process of turning on the inner display
-                isClosingThresholdMet(angle) // hinge angle is below certain threshold.
+                isClosingThresholdMet(angle) && // hinge angle is below certain threshold.
+                isOnLargeScreen // Avoids sending closing event when on small screen.
+                                // Start event is sent regardless due to hall sensor.
         ) {
             notifyFoldUpdate(transitionUpdate, lastHingeAngle)
         }
@@ -233,7 +239,7 @@
     }
 
     private fun cancelAnimation(): Unit =
-            notifyFoldUpdate(FOLD_UPDATE_FINISH_HALF_OPEN, lastHingeAngle)
+        notifyFoldUpdate(FOLD_UPDATE_FINISH_HALF_OPEN, lastHingeAngle)
 
     private inner class ScreenStatusListener : ScreenStatusProvider.ScreenListener {
 
@@ -261,6 +267,11 @@
         }
     }
 
+    private fun isOnLargeScreen(): Boolean {
+      return context.resources.configuration.smallestScreenWidthDp >
+          INNER_SCREEN_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP
+    }
+
     /** While the screen is off or the device is folded, hinge angle updates are not needed. */
     private fun updateHingeAngleProviderState() {
         if (isScreenOn && !isFolded) {
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt
index 0cf8224..ce8f1a1 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt
@@ -17,36 +17,32 @@
 package com.android.systemui.unfold.updates
 
 import android.content.Context
+import android.hardware.display.DisplayManager
+import android.os.Handler
 import android.os.RemoteException
-import android.view.IRotationWatcher
-import android.view.IWindowManager
-import android.view.Surface.Rotation
 import com.android.systemui.unfold.dagger.UnfoldMain
 import com.android.systemui.unfold.util.CallbackController
-import java.util.concurrent.Executor
 import javax.inject.Inject
 
 /**
- * Allows to subscribe to rotation changes.
- *
- * This is needed as rotation updates from [IWindowManager] are received in a binder thread, while
- * most of the times we want them in the main one. Updates are provided for the display associated
+ * Allows to subscribe to rotation changes. Updates are provided for the display associated
  * to [context].
  */
 class RotationChangeProvider
 @Inject
 constructor(
-    private val windowManagerInterface: IWindowManager,
+    private val displayManager: DisplayManager,
     private val context: Context,
-    @UnfoldMain private val mainExecutor: Executor,
+    @UnfoldMain private val mainHandler: Handler,
 ) : CallbackController<RotationChangeProvider.RotationListener> {
 
     private val listeners = mutableListOf<RotationListener>()
 
-    private val rotationWatcher = RotationWatcher()
+    private val displayListener = RotationDisplayListener()
+    private var lastRotation: Int? = null
 
     override fun addCallback(listener: RotationListener) {
-        mainExecutor.execute {
+        mainHandler.post {
             if (listeners.isEmpty()) {
                 subscribeToRotation()
             }
@@ -55,17 +51,18 @@
     }
 
     override fun removeCallback(listener: RotationListener) {
-        mainExecutor.execute {
+        mainHandler.post {
             listeners -= listener
             if (listeners.isEmpty()) {
                 unsubscribeToRotation()
+                lastRotation = null
             }
         }
     }
 
     private fun subscribeToRotation() {
         try {
-            windowManagerInterface.watchRotation(rotationWatcher, context.displayId)
+            displayManager.registerDisplayListener(displayListener, mainHandler)
         } catch (e: RemoteException) {
             throw e.rethrowFromSystemServer()
         }
@@ -73,7 +70,7 @@
 
     private fun unsubscribeToRotation() {
         try {
-            windowManagerInterface.removeRotationWatcher(rotationWatcher)
+            displayManager.unregisterDisplayListener(displayListener)
         } catch (e: RemoteException) {
             throw e.rethrowFromSystemServer()
         }
@@ -82,12 +79,25 @@
     /** Gets notified of rotation changes. */
     fun interface RotationListener {
         /** Called once rotation changes. */
-        fun onRotationChanged(@Rotation newRotation: Int)
+        fun onRotationChanged(newRotation: Int)
     }
 
-    private inner class RotationWatcher : IRotationWatcher.Stub() {
-        override fun onRotationChanged(rotation: Int) {
-            mainExecutor.execute { listeners.forEach { it.onRotationChanged(rotation) } }
+    private inner class RotationDisplayListener : DisplayManager.DisplayListener {
+
+        override fun onDisplayChanged(displayId: Int) {
+            val display = context.display ?: return
+
+            if (displayId == display.displayId) {
+                val currentRotation = display.rotation
+                if (lastRotation == null || lastRotation != currentRotation) {
+                    listeners.forEach { it.onRotationChanged(currentRotation) }
+                    lastRotation = currentRotation
+                }
+            }
         }
+
+        override fun onDisplayAdded(displayId: Int) {}
+
+        override fun onDisplayRemoved(displayId: Int) {}
     }
 }
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt
index 06ca153..ce5c5f9 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt
@@ -79,10 +79,9 @@
     companion object {
         fun ContentResolver.areAnimationsEnabled(): Boolean {
             val animationScale =
-                Settings.Global.getStringForUser(
+                Settings.Global.getString(
                         this,
                         Settings.Global.ANIMATOR_DURATION_SCALE,
-                        this.userId
                     )
                     ?.toFloatOrNull()
                     ?: 1f
diff --git a/packages/VpnDialogs/res/values-af/strings.xml b/packages/VpnDialogs/res/values-af/strings.xml
index 88ccbd9..db3c355 100644
--- a/packages/VpnDialogs/res/values-af/strings.xml
+++ b/packages/VpnDialogs/res/values-af/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Ontkoppel"</string>
     <string name="open_app" msgid="3717639178595958667">"Maak program oop"</string>
     <string name="dismiss" msgid="6192859333764711227">"Maak toe"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g> … ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-am/strings.xml b/packages/VpnDialogs/res/values-am/strings.xml
index 9fc5ff4..d86e043 100644
--- a/packages/VpnDialogs/res/values-am/strings.xml
+++ b/packages/VpnDialogs/res/values-am/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"ግንኙነት አቋርጥ"</string>
     <string name="open_app" msgid="3717639178595958667">"መተግበሪያን ክፈት"</string>
     <string name="dismiss" msgid="6192859333764711227">"አሰናብት"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-ar/strings.xml b/packages/VpnDialogs/res/values-ar/strings.xml
index 33be6a3..9307a74 100644
--- a/packages/VpnDialogs/res/values-ar/strings.xml
+++ b/packages/VpnDialogs/res/values-ar/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"قطع الاتصال"</string>
     <string name="open_app" msgid="3717639178595958667">"فتح التطبيق"</string>
     <string name="dismiss" msgid="6192859333764711227">"تجاهل"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-as/strings.xml b/packages/VpnDialogs/res/values-as/strings.xml
index 3f2e234..736bb83 100644
--- a/packages/VpnDialogs/res/values-as/strings.xml
+++ b/packages/VpnDialogs/res/values-as/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"সংযোগ বিচ্ছিন্ন কৰক"</string>
     <string name="open_app" msgid="3717639178595958667">"এপ্ খোলক"</string>
     <string name="dismiss" msgid="6192859333764711227">"অগ্ৰাহ্য কৰক"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-az/strings.xml b/packages/VpnDialogs/res/values-az/strings.xml
index d878835..9b69e3e5 100644
--- a/packages/VpnDialogs/res/values-az/strings.xml
+++ b/packages/VpnDialogs/res/values-az/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Əlaqəni kəs"</string>
     <string name="open_app" msgid="3717639178595958667">"Tətbiqi açın"</string>
     <string name="dismiss" msgid="6192859333764711227">"İmtina edin"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-b+sr+Latn/strings.xml b/packages/VpnDialogs/res/values-b+sr+Latn/strings.xml
index a1075d2..3270744 100644
--- a/packages/VpnDialogs/res/values-b+sr+Latn/strings.xml
+++ b/packages/VpnDialogs/res/values-b+sr+Latn/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Prekini vezu"</string>
     <string name="open_app" msgid="3717639178595958667">"Otvori aplikaciju"</string>
     <string name="dismiss" msgid="6192859333764711227">"Odbaci"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-be/strings.xml b/packages/VpnDialogs/res/values-be/strings.xml
index fc3f878..54908f6 100644
--- a/packages/VpnDialogs/res/values-be/strings.xml
+++ b/packages/VpnDialogs/res/values-be/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Адключыцца"</string>
     <string name="open_app" msgid="3717639178595958667">"Адкрыць праграму"</string>
     <string name="dismiss" msgid="6192859333764711227">"Адхіліць"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-bg/strings.xml b/packages/VpnDialogs/res/values-bg/strings.xml
index 6345f1d..734888f 100644
--- a/packages/VpnDialogs/res/values-bg/strings.xml
+++ b/packages/VpnDialogs/res/values-bg/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Изключване"</string>
     <string name="open_app" msgid="3717639178595958667">"Към приложението"</string>
     <string name="dismiss" msgid="6192859333764711227">"Отхвърляне"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-bn/strings.xml b/packages/VpnDialogs/res/values-bn/strings.xml
index 352b786..f176b244 100644
--- a/packages/VpnDialogs/res/values-bn/strings.xml
+++ b/packages/VpnDialogs/res/values-bn/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"সংযোগ বিচ্ছিন্ন করুন"</string>
     <string name="open_app" msgid="3717639178595958667">"অ্যাপটি খুলুন"</string>
     <string name="dismiss" msgid="6192859333764711227">"খারিজ করুন"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-bs/strings.xml b/packages/VpnDialogs/res/values-bs/strings.xml
index fa5f4ea..b2f40e2 100644
--- a/packages/VpnDialogs/res/values-bs/strings.xml
+++ b/packages/VpnDialogs/res/values-bs/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Prekini vezu"</string>
     <string name="open_app" msgid="3717639178595958667">"Otvori aplikaciju"</string>
     <string name="dismiss" msgid="6192859333764711227">"Odbaci"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-ca/strings.xml b/packages/VpnDialogs/res/values-ca/strings.xml
index cdb7547..aa64abd 100644
--- a/packages/VpnDialogs/res/values-ca/strings.xml
+++ b/packages/VpnDialogs/res/values-ca/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Desconnecta"</string>
     <string name="open_app" msgid="3717639178595958667">"Obre l\'aplicació"</string>
     <string name="dismiss" msgid="6192859333764711227">"Ignora"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-cs/strings.xml b/packages/VpnDialogs/res/values-cs/strings.xml
index c06f6ff..0658930 100644
--- a/packages/VpnDialogs/res/values-cs/strings.xml
+++ b/packages/VpnDialogs/res/values-cs/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Odpojit"</string>
     <string name="open_app" msgid="3717639178595958667">"Do aplikace"</string>
     <string name="dismiss" msgid="6192859333764711227">"Zavřít"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-da/strings.xml b/packages/VpnDialogs/res/values-da/strings.xml
index a4ddc19..63a32f9 100644
--- a/packages/VpnDialogs/res/values-da/strings.xml
+++ b/packages/VpnDialogs/res/values-da/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Fjern tilknytning"</string>
     <string name="open_app" msgid="3717639178595958667">"Åbn app"</string>
     <string name="dismiss" msgid="6192859333764711227">"Luk"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-de/strings.xml b/packages/VpnDialogs/res/values-de/strings.xml
index 1de7805..7397ddb 100644
--- a/packages/VpnDialogs/res/values-de/strings.xml
+++ b/packages/VpnDialogs/res/values-de/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Verbindung trennen"</string>
     <string name="open_app" msgid="3717639178595958667">"App öffnen"</string>
     <string name="dismiss" msgid="6192859333764711227">"Schließen"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-el/strings.xml b/packages/VpnDialogs/res/values-el/strings.xml
index e3eb460..3d14099 100644
--- a/packages/VpnDialogs/res/values-el/strings.xml
+++ b/packages/VpnDialogs/res/values-el/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Αποσύνδεση"</string>
     <string name="open_app" msgid="3717639178595958667">"Άνοιγμα εφαρμογής"</string>
     <string name="dismiss" msgid="6192859333764711227">"Παράβλεψη"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-en-rAU/strings.xml b/packages/VpnDialogs/res/values-en-rAU/strings.xml
index cb8b79d..7855b24 100644
--- a/packages/VpnDialogs/res/values-en-rAU/strings.xml
+++ b/packages/VpnDialogs/res/values-en-rAU/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Disconnect"</string>
     <string name="open_app" msgid="3717639178595958667">"Open app"</string>
     <string name="dismiss" msgid="6192859333764711227">"Dismiss"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-en-rCA/strings.xml b/packages/VpnDialogs/res/values-en-rCA/strings.xml
index f715c05..eca5db0 100644
--- a/packages/VpnDialogs/res/values-en-rCA/strings.xml
+++ b/packages/VpnDialogs/res/values-en-rCA/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Disconnect"</string>
     <string name="open_app" msgid="3717639178595958667">"Open app"</string>
     <string name="dismiss" msgid="6192859333764711227">"Dismiss"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-en-rGB/strings.xml b/packages/VpnDialogs/res/values-en-rGB/strings.xml
index cb8b79d..7855b24 100644
--- a/packages/VpnDialogs/res/values-en-rGB/strings.xml
+++ b/packages/VpnDialogs/res/values-en-rGB/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Disconnect"</string>
     <string name="open_app" msgid="3717639178595958667">"Open app"</string>
     <string name="dismiss" msgid="6192859333764711227">"Dismiss"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-en-rIN/strings.xml b/packages/VpnDialogs/res/values-en-rIN/strings.xml
index cb8b79d..7855b24 100644
--- a/packages/VpnDialogs/res/values-en-rIN/strings.xml
+++ b/packages/VpnDialogs/res/values-en-rIN/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Disconnect"</string>
     <string name="open_app" msgid="3717639178595958667">"Open app"</string>
     <string name="dismiss" msgid="6192859333764711227">"Dismiss"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-en-rXC/strings.xml b/packages/VpnDialogs/res/values-en-rXC/strings.xml
index f5e2deb..06d1421 100644
--- a/packages/VpnDialogs/res/values-en-rXC/strings.xml
+++ b/packages/VpnDialogs/res/values-en-rXC/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‏‎‏‏‏‏‎‏‏‎‎‏‎‎‏‏‎‎‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‏‏‎‏‎‏‏‎‏‎‏‏‏‏‎‎‎‎Disconnect‎‏‎‎‏‎"</string>
     <string name="open_app" msgid="3717639178595958667">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‏‎‎‏‎‏‏‏‏‎‏‏‎‏‎‏‎‎‏‎‎‎‏‎‏‏‎‏‎‎‏‏‎‏‎‎‏‎‎‏‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎Open app‎‏‎‎‏‎"</string>
     <string name="dismiss" msgid="6192859333764711227">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‏‏‏‎‎‎‏‎‏‏‏‎‏‎‎‏‏‎‎‎‎‎‎‏‎‏‏‏‏‎‏‎‎‎‎‎‎‏‎‎‎‎‎‎‎‏‏‎‎‏‏‏‎‏‏‎Dismiss‎‏‎‎‏‎"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‎‏‎‏‏‏‏‏‏‎‎‏‎‏‏‎‏‎‏‏‎‎‏‎‏‏‎‏‏‏‏‏‎‎‏‎‎‏‏‎‏‏‎‏‎‏‏‎‎‏‏‎‏‏‎‎‏‎‎‏‏‎<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>‎‏‎‎‏‏‏‎… ( ‎‏‎‎‏‏‎<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>‎‏‎‎‏‏‏‎)‎‏‎‎‏‎"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‎‎‎‎‏‏‎‏‏‏‏‎‏‎‏‏‎‎‎‎‎‎‏‎‎‏‎‏‏‎‎‏‏‎‏‎‎‏‎‎‏‎‏‏‏‎‏‎‏‏‎‎‏‏‏‎‎‎‏‎‎‏‏‎<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g>‎‏‎‎‏‏‏‎ ( ‎‏‎‎‏‏‎<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>‎‏‎‎‏‏‏‎)‎‏‎‎‏‎"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-es-rUS/strings.xml b/packages/VpnDialogs/res/values-es-rUS/strings.xml
index 232b53a..3a82cb5 100644
--- a/packages/VpnDialogs/res/values-es-rUS/strings.xml
+++ b/packages/VpnDialogs/res/values-es-rUS/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Desconectar"</string>
     <string name="open_app" msgid="3717639178595958667">"Abrir app"</string>
     <string name="dismiss" msgid="6192859333764711227">"Descartar"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-es/strings.xml b/packages/VpnDialogs/res/values-es/strings.xml
index 4e21fd09..336ac05 100644
--- a/packages/VpnDialogs/res/values-es/strings.xml
+++ b/packages/VpnDialogs/res/values-es/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Desconectar"</string>
     <string name="open_app" msgid="3717639178595958667">"Abrir aplicación"</string>
     <string name="dismiss" msgid="6192859333764711227">"Cerrar"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-et/strings.xml b/packages/VpnDialogs/res/values-et/strings.xml
index 140c183..864b9a4 100644
--- a/packages/VpnDialogs/res/values-et/strings.xml
+++ b/packages/VpnDialogs/res/values-et/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Katkesta ühendus"</string>
     <string name="open_app" msgid="3717639178595958667">"Ava rakendus"</string>
     <string name="dismiss" msgid="6192859333764711227">"Loobu"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-eu/strings.xml b/packages/VpnDialogs/res/values-eu/strings.xml
index a27a66a..01d80eb 100644
--- a/packages/VpnDialogs/res/values-eu/strings.xml
+++ b/packages/VpnDialogs/res/values-eu/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Deskonektatu"</string>
     <string name="open_app" msgid="3717639178595958667">"Ireki aplikazioa"</string>
     <string name="dismiss" msgid="6192859333764711227">"Baztertu"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-fa/strings.xml b/packages/VpnDialogs/res/values-fa/strings.xml
index 6fb5a00..47b8735 100644
--- a/packages/VpnDialogs/res/values-fa/strings.xml
+++ b/packages/VpnDialogs/res/values-fa/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"قطع اتصال"</string>
     <string name="open_app" msgid="3717639178595958667">"باز کردن برنامه"</string>
     <string name="dismiss" msgid="6192859333764711227">"رد کردن"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-fi/strings.xml b/packages/VpnDialogs/res/values-fi/strings.xml
index 8abca06..a08d66c 100644
--- a/packages/VpnDialogs/res/values-fi/strings.xml
+++ b/packages/VpnDialogs/res/values-fi/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Katkaise yhteys"</string>
     <string name="open_app" msgid="3717639178595958667">"Avaa sovellus"</string>
     <string name="dismiss" msgid="6192859333764711227">"Hylkää"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-fr-rCA/strings.xml b/packages/VpnDialogs/res/values-fr-rCA/strings.xml
index 876111c..ad450b4 100644
--- a/packages/VpnDialogs/res/values-fr-rCA/strings.xml
+++ b/packages/VpnDialogs/res/values-fr-rCA/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Déconnecter"</string>
     <string name="open_app" msgid="3717639178595958667">"Ouvrir l\'application"</string>
     <string name="dismiss" msgid="6192859333764711227">"Ignorer"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-fr/strings.xml b/packages/VpnDialogs/res/values-fr/strings.xml
index 27ebfb0..c70fd54 100644
--- a/packages/VpnDialogs/res/values-fr/strings.xml
+++ b/packages/VpnDialogs/res/values-fr/strings.xml
@@ -32,6 +32,8 @@
     <string name="always_on_disconnected_message_settings_link" msgid="6172280302829992412">"Modifier les paramètres VPN"</string>
     <string name="configure" msgid="4905518375574791375">"Configurer"</string>
     <string name="disconnect" msgid="971412338304200056">"Déconnecter"</string>
-    <string name="open_app" msgid="3717639178595958667">"Ouvrir l\'application"</string>
+    <string name="open_app" msgid="3717639178595958667">"Ouvrir l\'appli"</string>
     <string name="dismiss" msgid="6192859333764711227">"Ignorer"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-gl/strings.xml b/packages/VpnDialogs/res/values-gl/strings.xml
index 08ab9ae..5595e15 100644
--- a/packages/VpnDialogs/res/values-gl/strings.xml
+++ b/packages/VpnDialogs/res/values-gl/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Desconectar"</string>
     <string name="open_app" msgid="3717639178595958667">"Abrir aplicación"</string>
     <string name="dismiss" msgid="6192859333764711227">"Pechar"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-gu/strings.xml b/packages/VpnDialogs/res/values-gu/strings.xml
index 5ffdcb1..516d51c 100644
--- a/packages/VpnDialogs/res/values-gu/strings.xml
+++ b/packages/VpnDialogs/res/values-gu/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"ડિસ્કનેક્ટ કરો"</string>
     <string name="open_app" msgid="3717639178595958667">"ઍપ ખોલો"</string>
     <string name="dismiss" msgid="6192859333764711227">"છોડી દો"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-hi/strings.xml b/packages/VpnDialogs/res/values-hi/strings.xml
index c9c65d5..ad0cc0b 100644
--- a/packages/VpnDialogs/res/values-hi/strings.xml
+++ b/packages/VpnDialogs/res/values-hi/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"डिसकनेक्ट करें"</string>
     <string name="open_app" msgid="3717639178595958667">"ऐप खोलें"</string>
     <string name="dismiss" msgid="6192859333764711227">"खारिज करें"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-hr/strings.xml b/packages/VpnDialogs/res/values-hr/strings.xml
index 576d997..ec18688 100644
--- a/packages/VpnDialogs/res/values-hr/strings.xml
+++ b/packages/VpnDialogs/res/values-hr/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Prekini vezu"</string>
     <string name="open_app" msgid="3717639178595958667">"Otvori aplikaciju"</string>
     <string name="dismiss" msgid="6192859333764711227">"Odbaci"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-hu/strings.xml b/packages/VpnDialogs/res/values-hu/strings.xml
index 69b999f..0ce41ce 100644
--- a/packages/VpnDialogs/res/values-hu/strings.xml
+++ b/packages/VpnDialogs/res/values-hu/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Kapcsolat bontása"</string>
     <string name="open_app" msgid="3717639178595958667">"Alkalmazás indítása"</string>
     <string name="dismiss" msgid="6192859333764711227">"Bezárás"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-hy/strings.xml b/packages/VpnDialogs/res/values-hy/strings.xml
index d2a6d42..b699902 100644
--- a/packages/VpnDialogs/res/values-hy/strings.xml
+++ b/packages/VpnDialogs/res/values-hy/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Անջատել"</string>
     <string name="open_app" msgid="3717639178595958667">"Բացել հավելվածը"</string>
     <string name="dismiss" msgid="6192859333764711227">"Փակել"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-in/strings.xml b/packages/VpnDialogs/res/values-in/strings.xml
index 88a588c..342f403 100644
--- a/packages/VpnDialogs/res/values-in/strings.xml
+++ b/packages/VpnDialogs/res/values-in/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Putuskan koneksi"</string>
     <string name="open_app" msgid="3717639178595958667">"Buka aplikasi"</string>
     <string name="dismiss" msgid="6192859333764711227">"Tutup"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-is/strings.xml b/packages/VpnDialogs/res/values-is/strings.xml
index a75371d..a52292c 100644
--- a/packages/VpnDialogs/res/values-is/strings.xml
+++ b/packages/VpnDialogs/res/values-is/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Aftengja"</string>
     <string name="open_app" msgid="3717639178595958667">"Opna forrit"</string>
     <string name="dismiss" msgid="6192859333764711227">"Hunsa"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-it/strings.xml b/packages/VpnDialogs/res/values-it/strings.xml
index 118fb6a..7773c9e 100644
--- a/packages/VpnDialogs/res/values-it/strings.xml
+++ b/packages/VpnDialogs/res/values-it/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Disconnetti"</string>
     <string name="open_app" msgid="3717639178595958667">"Apri app"</string>
     <string name="dismiss" msgid="6192859333764711227">"Ignora"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-iw/strings.xml b/packages/VpnDialogs/res/values-iw/strings.xml
index 56d8105..3d4e0f0 100644
--- a/packages/VpnDialogs/res/values-iw/strings.xml
+++ b/packages/VpnDialogs/res/values-iw/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"נתק"</string>
     <string name="open_app" msgid="3717639178595958667">"פתיחת האפליקציה"</string>
     <string name="dismiss" msgid="6192859333764711227">"סגירה"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-ja/strings.xml b/packages/VpnDialogs/res/values-ja/strings.xml
index e03e9d3..658569f 100644
--- a/packages/VpnDialogs/res/values-ja/strings.xml
+++ b/packages/VpnDialogs/res/values-ja/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"切断"</string>
     <string name="open_app" msgid="3717639178595958667">"アプリを開く"</string>
     <string name="dismiss" msgid="6192859333764711227">"閉じる"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>…(<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g>(<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-ka/strings.xml b/packages/VpnDialogs/res/values-ka/strings.xml
index 9c4388e..5c4c815 100644
--- a/packages/VpnDialogs/res/values-ka/strings.xml
+++ b/packages/VpnDialogs/res/values-ka/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"კავშირის გაწყვეტა"</string>
     <string name="open_app" msgid="3717639178595958667">"გახსენით აპი"</string>
     <string name="dismiss" msgid="6192859333764711227">"დახურვა"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-kk/strings.xml b/packages/VpnDialogs/res/values-kk/strings.xml
index 9a499d3..a519e4c 100644
--- a/packages/VpnDialogs/res/values-kk/strings.xml
+++ b/packages/VpnDialogs/res/values-kk/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Ажырату"</string>
     <string name="open_app" msgid="3717639178595958667">"Қолданбаны ашу"</string>
     <string name="dismiss" msgid="6192859333764711227">"Жабу"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-km/strings.xml b/packages/VpnDialogs/res/values-km/strings.xml
index de18aba..d93c694 100644
--- a/packages/VpnDialogs/res/values-km/strings.xml
+++ b/packages/VpnDialogs/res/values-km/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"ផ្ដាច់"</string>
     <string name="open_app" msgid="3717639178595958667">"បើកកម្មវិធី"</string>
     <string name="dismiss" msgid="6192859333764711227">"ច្រានចោល"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-kn/strings.xml b/packages/VpnDialogs/res/values-kn/strings.xml
index 6308f18..4f8d90b 100644
--- a/packages/VpnDialogs/res/values-kn/strings.xml
+++ b/packages/VpnDialogs/res/values-kn/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸು"</string>
     <string name="open_app" msgid="3717639178595958667">"ಅಪ್ಲಿಕೇಶನ್ ತೆರೆಯಿರಿ"</string>
     <string name="dismiss" msgid="6192859333764711227">"ವಜಾಗೊಳಿಸಿ"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-ko/strings.xml b/packages/VpnDialogs/res/values-ko/strings.xml
index 6e179bb..ebadad7 100644
--- a/packages/VpnDialogs/res/values-ko/strings.xml
+++ b/packages/VpnDialogs/res/values-ko/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"연결 끊기"</string>
     <string name="open_app" msgid="3717639178595958667">"앱 열기"</string>
     <string name="dismiss" msgid="6192859333764711227">"닫기"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>…(<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g>(<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-ky/strings.xml b/packages/VpnDialogs/res/values-ky/strings.xml
index ea33e34..41204aa 100644
--- a/packages/VpnDialogs/res/values-ky/strings.xml
+++ b/packages/VpnDialogs/res/values-ky/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Ажыратуу"</string>
     <string name="open_app" msgid="3717639178595958667">"Колдонмону ачуу"</string>
     <string name="dismiss" msgid="6192859333764711227">"Четке кагуу"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-lo/strings.xml b/packages/VpnDialogs/res/values-lo/strings.xml
index cec69f0..4c36b71 100644
--- a/packages/VpnDialogs/res/values-lo/strings.xml
+++ b/packages/VpnDialogs/res/values-lo/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"ຕັດການເຊື່ອມຕໍ່"</string>
     <string name="open_app" msgid="3717639178595958667">"ເປີດແອັບ"</string>
     <string name="dismiss" msgid="6192859333764711227">"ປິດໄວ້"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-lt/strings.xml b/packages/VpnDialogs/res/values-lt/strings.xml
index 97abd0d..d8783d2 100644
--- a/packages/VpnDialogs/res/values-lt/strings.xml
+++ b/packages/VpnDialogs/res/values-lt/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Atsijungti"</string>
     <string name="open_app" msgid="3717639178595958667">"Atidaryti programą"</string>
     <string name="dismiss" msgid="6192859333764711227">"Atsisakyti"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-lv/strings.xml b/packages/VpnDialogs/res/values-lv/strings.xml
index 6341fbd..7e8ecc1 100644
--- a/packages/VpnDialogs/res/values-lv/strings.xml
+++ b/packages/VpnDialogs/res/values-lv/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Pārtraukt savienojumu"</string>
     <string name="open_app" msgid="3717639178595958667">"Atvērt lietotni"</string>
     <string name="dismiss" msgid="6192859333764711227">"Nerādīt"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-mk/strings.xml b/packages/VpnDialogs/res/values-mk/strings.xml
index 689d028..ec692ab 100644
--- a/packages/VpnDialogs/res/values-mk/strings.xml
+++ b/packages/VpnDialogs/res/values-mk/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Прекини врска"</string>
     <string name="open_app" msgid="3717639178595958667">"Отвори ја апликацијата"</string>
     <string name="dismiss" msgid="6192859333764711227">"Отфрли"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-ml/strings.xml b/packages/VpnDialogs/res/values-ml/strings.xml
index 8284a78..a98bcdc 100644
--- a/packages/VpnDialogs/res/values-ml/strings.xml
+++ b/packages/VpnDialogs/res/values-ml/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"വിച്ഛേദിക്കുക"</string>
     <string name="open_app" msgid="3717639178595958667">"ആപ്പ് തുറക്കുക"</string>
     <string name="dismiss" msgid="6192859333764711227">"നിരസിക്കുക"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-mn/strings.xml b/packages/VpnDialogs/res/values-mn/strings.xml
index 1dd4c15..8eb3289 100644
--- a/packages/VpnDialogs/res/values-mn/strings.xml
+++ b/packages/VpnDialogs/res/values-mn/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Салгах"</string>
     <string name="open_app" msgid="3717639178595958667">"Апп нээх"</string>
     <string name="dismiss" msgid="6192859333764711227">"Хаах"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-mr/strings.xml b/packages/VpnDialogs/res/values-mr/strings.xml
index 22fb502..cccf369 100644
--- a/packages/VpnDialogs/res/values-mr/strings.xml
+++ b/packages/VpnDialogs/res/values-mr/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"‍डिस्कनेक्ट करा"</string>
     <string name="open_app" msgid="3717639178595958667">"अ‍ॅप उघडा"</string>
     <string name="dismiss" msgid="6192859333764711227">"डिसमिस करा"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-ms/strings.xml b/packages/VpnDialogs/res/values-ms/strings.xml
index c9961d2..ad42abb 100644
--- a/packages/VpnDialogs/res/values-ms/strings.xml
+++ b/packages/VpnDialogs/res/values-ms/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Putuskan sambungan"</string>
     <string name="open_app" msgid="3717639178595958667">"Buka apl"</string>
     <string name="dismiss" msgid="6192859333764711227">"Ketepikan"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-my/strings.xml b/packages/VpnDialogs/res/values-my/strings.xml
index 36348c8..bc212a2 100644
--- a/packages/VpnDialogs/res/values-my/strings.xml
+++ b/packages/VpnDialogs/res/values-my/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"ချိတ်ဆက်မှုဖြုတ်ရန်"</string>
     <string name="open_app" msgid="3717639178595958667">"အက်ပ်ကို ဖွင့်ရန်"</string>
     <string name="dismiss" msgid="6192859333764711227">"ပယ်ရန်"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-nb/strings.xml b/packages/VpnDialogs/res/values-nb/strings.xml
index 14c84d7..bca01d0 100644
--- a/packages/VpnDialogs/res/values-nb/strings.xml
+++ b/packages/VpnDialogs/res/values-nb/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Koble fra"</string>
     <string name="open_app" msgid="3717639178595958667">"Åpne appen"</string>
     <string name="dismiss" msgid="6192859333764711227">"Lukk"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-ne/strings.xml b/packages/VpnDialogs/res/values-ne/strings.xml
index 2a5648d..675a76d 100644
--- a/packages/VpnDialogs/res/values-ne/strings.xml
+++ b/packages/VpnDialogs/res/values-ne/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"डिस्कनेक्ट गर्नुहोस्"</string>
     <string name="open_app" msgid="3717639178595958667">"एप खोल्नुहोस्"</string>
     <string name="dismiss" msgid="6192859333764711227">"खारेज गर्नुहोस्"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-nl/strings.xml b/packages/VpnDialogs/res/values-nl/strings.xml
index 76f56af..80e7f1b 100644
--- a/packages/VpnDialogs/res/values-nl/strings.xml
+++ b/packages/VpnDialogs/res/values-nl/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Verbinding verbreken"</string>
     <string name="open_app" msgid="3717639178595958667">"App openen"</string>
     <string name="dismiss" msgid="6192859333764711227">"Sluiten"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-or/strings.xml b/packages/VpnDialogs/res/values-or/strings.xml
index 4c5c259..2f5a3dd 100644
--- a/packages/VpnDialogs/res/values-or/strings.xml
+++ b/packages/VpnDialogs/res/values-or/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"ବିଚ୍ଛିନ୍ନ କରନ୍ତୁ"</string>
     <string name="open_app" msgid="3717639178595958667">"ଆପ୍‌ ଖୋଲନ୍ତୁ"</string>
     <string name="dismiss" msgid="6192859333764711227">"ଖାରଜ କରନ୍ତୁ"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-pa/strings.xml b/packages/VpnDialogs/res/values-pa/strings.xml
index d2eba0f..427cf86 100644
--- a/packages/VpnDialogs/res/values-pa/strings.xml
+++ b/packages/VpnDialogs/res/values-pa/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"ਡਿਸਕਨੈਕਟ ਕਰੋ"</string>
     <string name="open_app" msgid="3717639178595958667">"ਐਪ ਖੋਲ੍ਹੋ"</string>
     <string name="dismiss" msgid="6192859333764711227">"ਖਾਰਜ ਕਰੋ"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-pl/strings.xml b/packages/VpnDialogs/res/values-pl/strings.xml
index 82161d3..1bd89bb 100644
--- a/packages/VpnDialogs/res/values-pl/strings.xml
+++ b/packages/VpnDialogs/res/values-pl/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Rozłącz"</string>
     <string name="open_app" msgid="3717639178595958667">"Otwórz aplikację"</string>
     <string name="dismiss" msgid="6192859333764711227">"Zamknij"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-pt-rBR/strings.xml b/packages/VpnDialogs/res/values-pt-rBR/strings.xml
index 0d6dd0b..53d65af 100644
--- a/packages/VpnDialogs/res/values-pt-rBR/strings.xml
+++ b/packages/VpnDialogs/res/values-pt-rBR/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Desconectar"</string>
     <string name="open_app" msgid="3717639178595958667">"Abrir app"</string>
     <string name="dismiss" msgid="6192859333764711227">"Dispensar"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-pt-rPT/strings.xml b/packages/VpnDialogs/res/values-pt-rPT/strings.xml
index a310104..95f7c1a 100644
--- a/packages/VpnDialogs/res/values-pt-rPT/strings.xml
+++ b/packages/VpnDialogs/res/values-pt-rPT/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Desligar"</string>
     <string name="open_app" msgid="3717639178595958667">"Abrir app"</string>
     <string name="dismiss" msgid="6192859333764711227">"Ignorar"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-pt/strings.xml b/packages/VpnDialogs/res/values-pt/strings.xml
index 0d6dd0b..53d65af 100644
--- a/packages/VpnDialogs/res/values-pt/strings.xml
+++ b/packages/VpnDialogs/res/values-pt/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Desconectar"</string>
     <string name="open_app" msgid="3717639178595958667">"Abrir app"</string>
     <string name="dismiss" msgid="6192859333764711227">"Dispensar"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-ro/strings.xml b/packages/VpnDialogs/res/values-ro/strings.xml
index f86a5d6..f45609b 100644
--- a/packages/VpnDialogs/res/values-ro/strings.xml
+++ b/packages/VpnDialogs/res/values-ro/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Deconectează"</string>
     <string name="open_app" msgid="3717639178595958667">"Deschide aplicația"</string>
     <string name="dismiss" msgid="6192859333764711227">"Închide"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-ru/strings.xml b/packages/VpnDialogs/res/values-ru/strings.xml
index ce099562..2e346d3 100644
--- a/packages/VpnDialogs/res/values-ru/strings.xml
+++ b/packages/VpnDialogs/res/values-ru/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Разъединить"</string>
     <string name="open_app" msgid="3717639178595958667">"Открыть приложение"</string>
     <string name="dismiss" msgid="6192859333764711227">"Закрыть"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-si/strings.xml b/packages/VpnDialogs/res/values-si/strings.xml
index a836bae..fa5a70f 100644
--- a/packages/VpnDialogs/res/values-si/strings.xml
+++ b/packages/VpnDialogs/res/values-si/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"විසන්ධි කරන්න"</string>
     <string name="open_app" msgid="3717639178595958667">"යෙදුම විවෘත කරන්න"</string>
     <string name="dismiss" msgid="6192859333764711227">"ඉවතලන්න"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-sk/strings.xml b/packages/VpnDialogs/res/values-sk/strings.xml
index 766c139..755abb2 100644
--- a/packages/VpnDialogs/res/values-sk/strings.xml
+++ b/packages/VpnDialogs/res/values-sk/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Odpojiť"</string>
     <string name="open_app" msgid="3717639178595958667">"Otvoriť aplikáciu"</string>
     <string name="dismiss" msgid="6192859333764711227">"Zavrieť"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-sl/strings.xml b/packages/VpnDialogs/res/values-sl/strings.xml
index 361a5fa..b473ce0 100644
--- a/packages/VpnDialogs/res/values-sl/strings.xml
+++ b/packages/VpnDialogs/res/values-sl/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Prekini povezavo"</string>
     <string name="open_app" msgid="3717639178595958667">"Odpri aplikacijo"</string>
     <string name="dismiss" msgid="6192859333764711227">"Opusti"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g> … (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-sq/strings.xml b/packages/VpnDialogs/res/values-sq/strings.xml
index eb73baa..ad9f66e 100644
--- a/packages/VpnDialogs/res/values-sq/strings.xml
+++ b/packages/VpnDialogs/res/values-sq/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Shkëputu"</string>
     <string name="open_app" msgid="3717639178595958667">"Hap aplikacionin"</string>
     <string name="dismiss" msgid="6192859333764711227">"Hiq"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-sr/strings.xml b/packages/VpnDialogs/res/values-sr/strings.xml
index 01bd4df..eaa0aef 100644
--- a/packages/VpnDialogs/res/values-sr/strings.xml
+++ b/packages/VpnDialogs/res/values-sr/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Прекини везу"</string>
     <string name="open_app" msgid="3717639178595958667">"Отвори апликацију"</string>
     <string name="dismiss" msgid="6192859333764711227">"Одбаци"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-sv/strings.xml b/packages/VpnDialogs/res/values-sv/strings.xml
index 60ed752..175ebba 100644
--- a/packages/VpnDialogs/res/values-sv/strings.xml
+++ b/packages/VpnDialogs/res/values-sv/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Koppla från"</string>
     <string name="open_app" msgid="3717639178595958667">"Öppna appen"</string>
     <string name="dismiss" msgid="6192859333764711227">"Ignorera"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-sw/strings.xml b/packages/VpnDialogs/res/values-sw/strings.xml
index c4f4662..66c2899 100644
--- a/packages/VpnDialogs/res/values-sw/strings.xml
+++ b/packages/VpnDialogs/res/values-sw/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Tenganisha"</string>
     <string name="open_app" msgid="3717639178595958667">"Fungua programu"</string>
     <string name="dismiss" msgid="6192859333764711227">"Ondoa"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-ta/strings.xml b/packages/VpnDialogs/res/values-ta/strings.xml
index 1385bdc..31602a6 100644
--- a/packages/VpnDialogs/res/values-ta/strings.xml
+++ b/packages/VpnDialogs/res/values-ta/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"தொடர்பைத் துண்டி"</string>
     <string name="open_app" msgid="3717639178595958667">"பயன்பாட்டைத் திற"</string>
     <string name="dismiss" msgid="6192859333764711227">"நிராகரி"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-te/strings.xml b/packages/VpnDialogs/res/values-te/strings.xml
index 7884336..685dd26 100644
--- a/packages/VpnDialogs/res/values-te/strings.xml
+++ b/packages/VpnDialogs/res/values-te/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"డిస్‌కనెక్ట్ చేయి"</string>
     <string name="open_app" msgid="3717639178595958667">"యాప్‌ని తెరవండి"</string>
     <string name="dismiss" msgid="6192859333764711227">"తీసివేయండి"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-th/strings.xml b/packages/VpnDialogs/res/values-th/strings.xml
index 2e174cd..3e15d4b 100644
--- a/packages/VpnDialogs/res/values-th/strings.xml
+++ b/packages/VpnDialogs/res/values-th/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"ยกเลิกการเชื่อมต่อ"</string>
     <string name="open_app" msgid="3717639178595958667">"เปิดแอป"</string>
     <string name="dismiss" msgid="6192859333764711227">"ปิด"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-tl/strings.xml b/packages/VpnDialogs/res/values-tl/strings.xml
index ea69fba..0b4a106 100644
--- a/packages/VpnDialogs/res/values-tl/strings.xml
+++ b/packages/VpnDialogs/res/values-tl/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Idiskonekta"</string>
     <string name="open_app" msgid="3717639178595958667">"Buksan ang app"</string>
     <string name="dismiss" msgid="6192859333764711227">"I-dismiss"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-tr/strings.xml b/packages/VpnDialogs/res/values-tr/strings.xml
index 7ffa4bc..e3606ef 100644
--- a/packages/VpnDialogs/res/values-tr/strings.xml
+++ b/packages/VpnDialogs/res/values-tr/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Bağlantıyı kes"</string>
     <string name="open_app" msgid="3717639178595958667">"Uygulamayı aç"</string>
     <string name="dismiss" msgid="6192859333764711227">"Kapat"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-uk/strings.xml b/packages/VpnDialogs/res/values-uk/strings.xml
index 6411d7c..1dd0e8a 100644
--- a/packages/VpnDialogs/res/values-uk/strings.xml
+++ b/packages/VpnDialogs/res/values-uk/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Від’єднати"</string>
     <string name="open_app" msgid="3717639178595958667">"Відкрити додаток"</string>
     <string name="dismiss" msgid="6192859333764711227">"Закрити"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-ur/strings.xml b/packages/VpnDialogs/res/values-ur/strings.xml
index 3a23e94..803f042 100644
--- a/packages/VpnDialogs/res/values-ur/strings.xml
+++ b/packages/VpnDialogs/res/values-ur/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"منقطع کریں"</string>
     <string name="open_app" msgid="3717639178595958667">"ایپ کھولیں"</string>
     <string name="dismiss" msgid="6192859333764711227">"برخاست کریں"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-uz/strings.xml b/packages/VpnDialogs/res/values-uz/strings.xml
index a3256e7..a54fa08 100644
--- a/packages/VpnDialogs/res/values-uz/strings.xml
+++ b/packages/VpnDialogs/res/values-uz/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Aloqani uzish"</string>
     <string name="open_app" msgid="3717639178595958667">"Ilovani ochish"</string>
     <string name="dismiss" msgid="6192859333764711227">"Yopish"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-vi/strings.xml b/packages/VpnDialogs/res/values-vi/strings.xml
index 184d08d..6ce9f39 100644
--- a/packages/VpnDialogs/res/values-vi/strings.xml
+++ b/packages/VpnDialogs/res/values-vi/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Ngắt kết nối"</string>
     <string name="open_app" msgid="3717639178595958667">"Mở ứng dụng"</string>
     <string name="dismiss" msgid="6192859333764711227">"Loại bỏ"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-zh-rCN/strings.xml b/packages/VpnDialogs/res/values-zh-rCN/strings.xml
index a7262be..38a2e8d 100644
--- a/packages/VpnDialogs/res/values-zh-rCN/strings.xml
+++ b/packages/VpnDialogs/res/values-zh-rCN/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"断开连接"</string>
     <string name="open_app" msgid="3717639178595958667">"打开应用"</string>
     <string name="dismiss" msgid="6192859333764711227">"关闭"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>…(<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-zh-rHK/strings.xml b/packages/VpnDialogs/res/values-zh-rHK/strings.xml
index e4e6432..f3abf3c 100644
--- a/packages/VpnDialogs/res/values-zh-rHK/strings.xml
+++ b/packages/VpnDialogs/res/values-zh-rHK/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"中斷連線"</string>
     <string name="open_app" msgid="3717639178595958667">"開啟應用程式"</string>
     <string name="dismiss" msgid="6192859333764711227">"關閉"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-zh-rTW/strings.xml b/packages/VpnDialogs/res/values-zh-rTW/strings.xml
index f54ca4a..3f1336b 100644
--- a/packages/VpnDialogs/res/values-zh-rTW/strings.xml
+++ b/packages/VpnDialogs/res/values-zh-rTW/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"中斷連線"</string>
     <string name="open_app" msgid="3717639178595958667">"開啟應用程式"</string>
     <string name="dismiss" msgid="6192859333764711227">"關閉"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-zu/strings.xml b/packages/VpnDialogs/res/values-zu/strings.xml
index c224b13..563ed0f5 100644
--- a/packages/VpnDialogs/res/values-zu/strings.xml
+++ b/packages/VpnDialogs/res/values-zu/strings.xml
@@ -34,4 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Ayixhumekile kwi-inthanethi"</string>
     <string name="open_app" msgid="3717639178595958667">"Vula uhlelo lokusebenza"</string>
     <string name="dismiss" msgid="6192859333764711227">"Cashisa"</string>
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values/strings.xml b/packages/VpnDialogs/res/values/strings.xml
index f971a09..a85b8e4 100644
--- a/packages/VpnDialogs/res/values/strings.xml
+++ b/packages/VpnDialogs/res/values/strings.xml
@@ -100,4 +100,32 @@
          without any consequences. [CHAR LIMIT=20] -->
     <string name="dismiss">Dismiss</string>
 
+    <!-- Malicious VPN apps may provide very long labels or cunning HTML to trick the system dialogs
+         into displaying what they want. The system will attempt to sanitize the label, and if the
+         label is deemed dangerous, then this string is used instead. The first argument is the
+         first 30 characters of the label, and the second argument is the package name of the app.
+         Example : Normally a VPN app may be called "My VPN app" in which case the dialog will read
+         "My VPN app wants to set up a VPN connection...". If the label is very long, then, this
+         will be used to show "VerylongVPNlabel… (com.my.vpn.app) wants to set up a VPN
+         connection...". For this case, the code will refer to sanitized_vpn_label_with_ellipsis.
+    -->
+    <string name="sanitized_vpn_label_with_ellipsis">
+        <xliff:g id="sanitized_vpn_label_with_ellipsis" example="My VPN app">%1$s</xliff:g>… (
+        <xliff:g id="sanitized_vpn_label_with_ellipsis" example="com.my.vpn.app">%2$s</xliff:g>)
+    </string>
+
+    <!-- Malicious VPN apps may provide very long labels or cunning HTML to trick the system dialogs
+         into displaying what they want. The system will attempt to sanitize the label, and if the
+         label is deemed dangerous, then this string is used instead. The first argument is the
+         label, and the second argument is the package name of the app.
+         Example : Normally a VPN app may be called "My VPN app" in which case the dialog will read
+         "My VPN app wants to set up a VPN connection...". If the VPN label contains HTML tag but
+         the length is not very long, the dialog will show "VpnLabelWith&lt;br&gt;HtmlTag
+         (com.my.vpn.app) wants to set up a VPN connection...". For this case, the code will refer
+         to sanitized_vpn_label.
+    -->
+    <string name="sanitized_vpn_label">
+        <xliff:g id="sanitized_vpn_label" example="My VPN app">%1$s</xliff:g> (
+        <xliff:g id="sanitized_vpn_label" example="com.my.vpn.app">%2$s</xliff:g>)
+    </string>
 </resources>
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
index fb23678..2b3202e 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
@@ -40,12 +40,18 @@
         implements DialogInterface.OnClickListener, ImageGetter {
     private static final String TAG = "VpnConfirm";
 
+    // Usually the label represents the app name, 150 code points might be enough to display the app
+    // name, and 150 code points won't cover the warning message from VpnDialog.
+    static final int MAX_VPN_LABEL_LENGTH = 150;
+
     @VpnManager.VpnType private final int mVpnType;
 
     private String mPackage;
 
     private VpnManager mVm;
 
+    private View mView;
+
     public ConfirmDialog() {
         this(VpnManager.TYPE_VPN_SERVICE);
     }
@@ -54,6 +60,42 @@
         mVpnType = vpnType;
     }
 
+    /**
+     * This function will use the string resource to combine the VPN label and the package name.
+     *
+     * If the VPN label violates the length restriction, the first 30 code points of VPN label and
+     * the package name will be returned. Or return the VPN label and the package name directly if
+     * the VPN label doesn't violate the length restriction.
+     *
+     * The result will be something like,
+     * - ThisIsAVeryLongVpnAppNameWhich... (com.vpn.app)
+     *   if the VPN label violates the length restriction.
+     * or
+     * - VpnLabelWith&lt;br&gt;HtmlTag (com.vpn.app)
+     *   if the VPN label doesn't violate the length restriction.
+     *
+     */
+    private String getSimplifiedLabel(String vpnLabel, String packageName) {
+        if (vpnLabel.codePointCount(0, vpnLabel.length()) > 30) {
+            return getString(R.string.sanitized_vpn_label_with_ellipsis,
+                vpnLabel.substring(0, vpnLabel.offsetByCodePoints(0, 30)),
+                packageName);
+        }
+
+        return getString(R.string.sanitized_vpn_label, vpnLabel, packageName);
+    }
+
+    protected String getSanitizedVpnLabel(String vpnLabel, String packageName) {
+        final String sanitizedVpnLabel = Html.escapeHtml(vpnLabel);
+        final boolean exceedMaxVpnLabelLength = sanitizedVpnLabel.codePointCount(0,
+            sanitizedVpnLabel.length()) > MAX_VPN_LABEL_LENGTH;
+        if (exceedMaxVpnLabelLength || !vpnLabel.equals(sanitizedVpnLabel)) {
+            return getSimplifiedLabel(sanitizedVpnLabel, packageName);
+        }
+
+        return sanitizedVpnLabel;
+    }
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -75,15 +117,16 @@
             finish();
             return;
         }
-        View view = View.inflate(this, R.layout.confirm, null);
-        ((TextView) view.findViewById(R.id.warning)).setText(
-                Html.fromHtml(getString(R.string.warning, getVpnLabel()),
-                        this, null /* tagHandler */));
+        mView = View.inflate(this, R.layout.confirm, null);
+        ((TextView) mView.findViewById(R.id.warning)).setText(
+                Html.fromHtml(getString(R.string.warning, getSanitizedVpnLabel(
+                    getVpnLabel().toString(), mPackage)),
+                    this /* imageGetter */, null /* tagHandler */));
         mAlertParams.mTitle = getText(R.string.prompt);
         mAlertParams.mPositiveButtonText = getText(android.R.string.ok);
         mAlertParams.mPositiveButtonListener = this;
         mAlertParams.mNegativeButtonText = getText(android.R.string.cancel);
-        mAlertParams.mView = view;
+        mAlertParams.mView = mView;
         setupAlert();
 
         getWindow().setCloseOnTouchOutside(false);
diff --git a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
index 3d24588..aafcd9d 100644
--- a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
+++ b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
@@ -19,7 +19,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
-import android.graphics.Camera;
 import android.graphics.GraphicBuffer;
 import android.graphics.Rect;
 import android.hardware.HardwareBuffer;
@@ -1855,6 +1854,7 @@
         ret.outputId.id = output.getId();
         ret.physicalCameraId = output.getPhysicalCameraId();
         ret.surfaceGroupId = output.getSurfaceGroupId();
+        ret.isMultiResolutionOutput = false;
         if (output instanceof SurfaceOutputConfigImpl) {
             SurfaceOutputConfigImpl surfaceConfig = (SurfaceOutputConfigImpl) output;
             ret.type = CameraOutputConfig.TYPE_SURFACE;
@@ -1874,6 +1874,7 @@
             ret.type = CameraOutputConfig.TYPE_MULTIRES_IMAGEREADER;
             ret.imageFormat = multiResReaderConfig.getImageFormat();
             ret.capacity = multiResReaderConfig.getMaxImages();
+            ret.isMultiResolutionOutput = true;
         } else {
             throw new IllegalStateException("Unknown output config type!");
         }
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index ff1a495..8025748 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -168,6 +168,7 @@
     @GuardedBy("mLock") int mDevCfgTextChangeFlushingFrequencyMs;
     @GuardedBy("mLock") int mDevCfgLogHistorySize;
     @GuardedBy("mLock") int mDevCfgIdleUnbindTimeoutMs;
+    @GuardedBy("mLock") boolean mDevCfgDisableFlushForViewTreeAppearing;
 
     private final Executor mDataShareExecutor = Executors.newCachedThreadPool();
     private final Handler mHandler = new Handler(Looper.getMainLooper());
@@ -358,6 +359,8 @@
                 case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE:
                 case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_TEXT_CHANGE_FLUSH_FREQUENCY:
                 case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_UNBIND_TIMEOUT:
+                case ContentCaptureManager
+                        .DEVICE_CONFIG_PROPERTY_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING:
                     setFineTuneParamsFromDeviceConfig();
                     return;
                 default:
@@ -387,13 +390,20 @@
                     DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
                     ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_UNBIND_TIMEOUT,
                     (int) AbstractRemoteService.PERMANENT_BOUND_TIMEOUT_MS);
+            mDevCfgDisableFlushForViewTreeAppearing = DeviceConfig.getBoolean(
+                    DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+                    ContentCaptureManager
+                        .DEVICE_CONFIG_PROPERTY_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING,
+                    false);
             if (verbose) {
                 Slog.v(TAG, "setFineTuneParamsFromDeviceConfig(): "
                         + "bufferSize=" + mDevCfgMaxBufferSize
                         + ", idleFlush=" + mDevCfgIdleFlushingFrequencyMs
                         + ", textFluxh=" + mDevCfgTextChangeFlushingFrequencyMs
                         + ", logHistory=" + mDevCfgLogHistorySize
-                        + ", idleUnbindTimeoutMs=" + mDevCfgIdleUnbindTimeoutMs);
+                        + ", idleUnbindTimeoutMs=" + mDevCfgIdleUnbindTimeoutMs
+                        + ", disableFlushForViewTreeAppearing="
+                        + mDevCfgDisableFlushForViewTreeAppearing);
             }
         }
     }
@@ -628,6 +638,7 @@
     }
 
     @Override // from AbstractMasterSystemService
+    @GuardedBy("mLock")
     protected void dumpLocked(String prefix, PrintWriter pw) {
         super.dumpLocked(prefix, pw);
 
@@ -645,6 +656,8 @@
         pw.print(prefix2); pw.print("logHistorySize: "); pw.println(mDevCfgLogHistorySize);
         pw.print(prefix2); pw.print("idleUnbindTimeoutMs: ");
         pw.println(mDevCfgIdleUnbindTimeoutMs);
+        pw.print(prefix2); pw.print("disableFlushForViewTreeAppearing: ");
+        pw.println(mDevCfgDisableFlushForViewTreeAppearing);
         pw.print(prefix); pw.println("Global Options:");
         mGlobalContentCaptureOptions.dump(prefix2, pw);
     }
@@ -1003,12 +1016,15 @@
                 return null;
             }
 
-            final ContentCaptureOptions options = new ContentCaptureOptions(mDevCfgLoggingLevel,
-                    mDevCfgMaxBufferSize, mDevCfgIdleFlushingFrequencyMs,
-                    mDevCfgTextChangeFlushingFrequencyMs, mDevCfgLogHistorySize,
-                    whitelistedComponents);
-            if (verbose) Slog.v(TAG, "getOptionsForPackage(" + packageName + "): " + options);
-            return options;
+            synchronized (mLock) {
+                final ContentCaptureOptions options = new ContentCaptureOptions(mDevCfgLoggingLevel,
+                        mDevCfgMaxBufferSize, mDevCfgIdleFlushingFrequencyMs,
+                        mDevCfgTextChangeFlushingFrequencyMs, mDevCfgLogHistorySize,
+                        mDevCfgDisableFlushForViewTreeAppearing,
+                        whitelistedComponents);
+                if (verbose) Slog.v(TAG, "getOptionsForPackage(" + packageName + "): " + options);
+                return options;
+            }
         }
 
         @Override
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 4251581..1dc0942 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -4893,10 +4893,6 @@
             if (intent.getClipData() == null) {
                 intent.setClipData(ClipData.newPlainText(null, null));
             }
-            intent.setFlags(intent.getFlags() & ~(Intent.FLAG_GRANT_READ_URI_PERMISSION
-                    | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
-                    | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
-                    | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION));
             final long bid = Binder.clearCallingIdentity();
             try {
                 PackageManager pm = mContext.getPackageManager();
@@ -4942,7 +4938,19 @@
             if (intent == null) {
                 return (simulateIntent == null);
             }
-            return intent.filterEquals(simulateIntent);
+            if (!intent.filterEquals(simulateIntent)) {
+                return false;
+            }
+
+            if (intent.getSelector() != simulateIntent.getSelector()) {
+                return false;
+            }
+
+            int prohibitedFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION
+                    | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+                    | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
+                    | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION;
+            return (simulateIntent.getFlags() & prohibitedFlags) == 0;
         }
 
         private boolean isExportedSystemActivity(ActivityInfo activityInfo) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5dcdbd4..f0dac260 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -13117,12 +13117,17 @@
     public Intent registerReceiverWithFeature(IApplicationThread caller, String callerPackage,
             String callerFeatureId, String receiverId, IIntentReceiver receiver,
             IntentFilter filter, String permission, int userId, int flags) {
+        enforceNotIsolatedCaller("registerReceiver");
+
         // Allow Sandbox process to register only unexported receivers.
-        if ((flags & Context.RECEIVER_NOT_EXPORTED) != 0) {
-            enforceNotIsolatedCaller("registerReceiver");
-        } else if (mSdkSandboxSettings.isBroadcastReceiverRestrictionsEnforced()) {
-            enforceNotIsolatedOrSdkSandboxCaller("registerReceiver");
+        boolean unexported = (flags & Context.RECEIVER_NOT_EXPORTED) != 0;
+        if (mSdkSandboxSettings.isBroadcastReceiverRestrictionsEnforced()
+                && Process.isSdkSandboxUid(Binder.getCallingUid())
+                && !unexported) {
+            throw new SecurityException("SDK sandbox process not allowed to call "
+                + "registerReceiver");
         }
+
         ArrayList<Intent> stickyIntents = null;
         ProcessRecord callerApp = null;
         final boolean visibleToInstantApps
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 702526a..dc1ef7e 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -891,6 +891,7 @@
                     break;
                 case EnergyConsumerType.MOBILE_RADIO:
                     buckets[MeasuredEnergyStats.POWER_BUCKET_MOBILE_RADIO] = true;
+                    buckets[MeasuredEnergyStats.POWER_BUCKET_PHONE] = true;
                     break;
                 case EnergyConsumerType.DISPLAY:
                     buckets[MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON] = true;
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 207c10c..2a2e783 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -822,7 +822,10 @@
 
                     final long sessionStart = mBatteryUsageStatsStore
                             .getLastBatteryUsageStatsBeforeResetAtomPullTimestamp();
-                    final long sessionEnd = mStats.getStartClockTime();
+                    final long sessionEnd;
+                    synchronized (mStats) {
+                        sessionEnd = mStats.getStartClockTime();
+                    }
                     final BatteryUsageStatsQuery queryBeforeReset =
                             new BatteryUsageStatsQuery.Builder()
                                     .setMaxStatsAgeMs(0)
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index cee9f79..347557c 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -110,6 +110,8 @@
 
     private static final String ATRACE_COMPACTION_TRACK = "Compaction";
 
+    @VisibleForTesting static final boolean ENABLE_FILE_COMPACT = false;
+
     // Defaults for phenotype flags.
     @VisibleForTesting static final Boolean DEFAULT_USE_COMPACTION = false;
     @VisibleForTesting static final Boolean DEFAULT_USE_FREEZER = true;
@@ -515,9 +517,11 @@
 
     @GuardedBy("mProcLock")
     void compactAppSome(ProcessRecord app, boolean force) {
-        app.mOptRecord.setReqCompactAction(COMPACT_PROCESS_SOME);
-        ++mSomeCompactRequest;
-        compactApp(app, force, "some");
+        if (ENABLE_FILE_COMPACT) {
+            app.mOptRecord.setReqCompactAction(COMPACT_PROCESS_SOME);
+            ++mSomeCompactRequest;
+            compactApp(app, force, "some");
+        }
     }
 
     // This method returns true only if requirements are met. Note, that requirements are different
@@ -1278,6 +1282,15 @@
             }
         }
 
+        if (!ENABLE_FILE_COMPACT) {
+            // Turn off file compaction
+            if (resolvedAction == COMPACT_ACTION_FULL) {
+                resolvedAction = COMPACT_ACTION_ANON;
+            } else if (resolvedAction == COMPACT_ACTION_FILE) {
+                resolvedAction = COMPACT_ACTION_NONE;
+            }
+        }
+
         return resolvedAction;
     }
 
@@ -1545,6 +1558,9 @@
                     }
 
                     int resolvedAction = resolveCompactionAction(requestedAction);
+                    if (resolvedAction == COMPACT_ACTION_NONE) {
+                        return;
+                    }
                     action = compactActionIntToString(resolvedAction);
 
                     try {
diff --git a/services/core/java/com/android/server/am/ProcessStatsService.java b/services/core/java/com/android/server/am/ProcessStatsService.java
index 7371d07..7d9de91 100644
--- a/services/core/java/com/android/server/am/ProcessStatsService.java
+++ b/services/core/java/com/android/server/am/ProcessStatsService.java
@@ -69,7 +69,7 @@
     // define the encoding of that data in an integer.
 
     static final int MAX_HISTORIC_STATES = 8;   // Maximum number of historic states we will keep.
-    static final String STATE_FILE_PREFIX = "state-"; // Prefix to use for state filenames.
+    static final String STATE_FILE_PREFIX = "state-v2-"; // Prefix to use for state filenames.
     static final String STATE_FILE_SUFFIX = ".bin"; // Suffix to use for state filenames.
     static final String STATE_FILE_CHECKIN_SUFFIX = ".ci"; // State files that have checked in.
     static long WRITE_PERIOD = 30*60*1000;      // Write file every 30 minutes or so.
@@ -462,6 +462,10 @@
             File file = files[i];
             String fileStr = file.getPath();
             if (DEBUG) Slog.d(TAG, "Collecting: " + fileStr);
+            if (!file.getName().startsWith(STATE_FILE_PREFIX)) {
+                if (DEBUG) Slog.d(TAG, "Skipping: mismatching prefix");
+                continue;
+            }
             if (!inclCheckedIn && fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX)) {
                 if (DEBUG) Slog.d(TAG, "Skipping: already checked in");
                 continue;
@@ -478,6 +482,14 @@
 
     @GuardedBy("mFileLock")
     private void trimHistoricStatesWriteLF() {
+        File[] files = mBaseDir.listFiles();
+        if (files != null) {
+            for (int i = 0; i < files.length; i++) {
+                if (!files[i].getName().startsWith(STATE_FILE_PREFIX)) {
+                    files[i].delete();
+                }
+            }
+        }
         ArrayList<String> filesArray = getCommittedFilesLF(MAX_HISTORIC_STATES, false, true);
         if (filesArray == null) {
             return;
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 9f15128..1584920 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1017,9 +1017,14 @@
 
         mSfxHelper = new SoundEffectsHelper(mContext, playerBase -> ignorePlayerLogs(playerBase));
 
-        final boolean headTrackingDefault = mContext.getResources().getBoolean(
+        final boolean binauralEnabledDefault = SystemProperties.getBoolean(
+                "ro.audio.spatializer_binaural_enabled_default", true);
+        final boolean transauralEnabledDefault = SystemProperties.getBoolean(
+                "ro.audio.spatializer_transaural_enabled_default", true);
+        final boolean headTrackingEnabledDefault = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_spatial_audio_head_tracking_enabled_default);
-        mSpatializerHelper = new SpatializerHelper(this, mAudioSystem, headTrackingDefault);
+        mSpatializerHelper = new SpatializerHelper(this, mAudioSystem,
+                binauralEnabledDefault, transauralEnabledDefault, headTrackingEnabledDefault);
 
         mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
         mHasVibrator = mVibrator == null ? false : mVibrator.hasVibrator();
@@ -1352,8 +1357,8 @@
         intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
         if (mMonitorRotation) {
             RotationHelper.init(mContext, mAudioHandler,
-                    rotationParam -> onRotationUpdate(rotationParam),
-                    foldParam -> onFoldUpdate(foldParam));
+                    rotation -> onRotationUpdate(rotation),
+                    foldState -> onFoldStateUpdate(foldState));
         }
 
         intentFilter.addAction(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION);
@@ -1502,16 +1507,20 @@
 
     //-----------------------------------------------------------------
     // rotation/fold updates coming from RotationHelper
-    void onRotationUpdate(String rotationParameter) {
+    void onRotationUpdate(Integer rotation) {
+        mSpatializerHelper.setDisplayOrientation((float) (rotation * Math.PI / 180.));
         // use REPLACE as only the last rotation matters
+        final String rotationParameter = "rotation=" + rotation;
         sendMsg(mAudioHandler, MSG_ROTATION_UPDATE, SENDMSG_REPLACE, /*arg1*/ 0, /*arg2*/ 0,
                 /*obj*/ rotationParameter, /*delay*/ 0);
     }
 
-    void onFoldUpdate(String foldParameter) {
+    void onFoldStateUpdate(Boolean foldState) {
+        mSpatializerHelper.setFoldState(foldState);
         // use REPLACE as only the last fold state matters
+        final String foldStateParameter = "device_folded=" + (foldState ? "on" : "off");
         sendMsg(mAudioHandler, MSG_FOLD_UPDATE, SENDMSG_REPLACE, /*arg1*/ 0, /*arg2*/ 0,
-                /*obj*/ foldParameter, /*delay*/ 0);
+                /*obj*/ foldStateParameter, /*delay*/ 0);
     }
 
     //-----------------------------------------------------------------
@@ -1726,6 +1735,11 @@
 
         mSpatializerHelper.reset(/* featureEnabled */ mHasSpatializerEffect);
 
+        // Restore rotation information.
+        if (mMonitorRotation) {
+            RotationHelper.forceUpdate();
+        }
+
         onIndicateSystemReady();
         // indicate the end of reconfiguration phase to audio HAL
         AudioSystem.setParameters("restarting=false");
@@ -8396,7 +8410,9 @@
                     if (isMutable()) {
                         // For call stream, align mute only when muted, not when index is set to 0
                         mVolumeGroupState.mute(
-                                forceMuteState ? mIsMuted : groupIndex == 0 || mIsMuted);
+                                forceMuteState ? mIsMuted :
+                                        (groupIndex == 0 && !isCallStream(mStreamType))
+                                                || mIsMuted);
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/audio/RotationHelper.java b/services/core/java/com/android/server/audio/RotationHelper.java
index 5cdf58b..394e4af 100644
--- a/services/core/java/com/android/server/audio/RotationHelper.java
+++ b/services/core/java/com/android/server/audio/RotationHelper.java
@@ -55,14 +55,14 @@
     private static AudioDisplayListener sDisplayListener;
     private static FoldStateListener sFoldStateListener;
     /** callback to send rotation updates to AudioSystem */
-    private static Consumer<String> sRotationUpdateCb;
+    private static Consumer<Integer> sRotationCallback;
     /** callback to send folded state updates to AudioSystem */
-    private static Consumer<String> sFoldUpdateCb;
+    private static Consumer<Boolean> sFoldStateCallback;
 
     private static final Object sRotationLock = new Object();
     private static final Object sFoldStateLock = new Object();
-    private static int sDeviceRotation = Surface.ROTATION_0; // R/W synchronized on sRotationLock
-    private static boolean sDeviceFold = true; // R/W synchronized on sFoldStateLock
+    private static Integer sRotation = null; // R/W synchronized on sRotationLock
+    private static Boolean sFoldState = null; // R/W synchronized on sFoldStateLock
 
     private static Context sContext;
     private static Handler sHandler;
@@ -73,15 +73,15 @@
      * - sContext != null
      */
     static void init(Context context, Handler handler,
-            Consumer<String> rotationUpdateCb, Consumer<String> foldUpdateCb) {
+            Consumer<Integer> rotationCallback, Consumer<Boolean> foldStateCallback) {
         if (context == null) {
             throw new IllegalArgumentException("Invalid null context");
         }
         sContext = context;
         sHandler = handler;
         sDisplayListener = new AudioDisplayListener();
-        sRotationUpdateCb = rotationUpdateCb;
-        sFoldUpdateCb = foldUpdateCb;
+        sRotationCallback = rotationCallback;
+        sFoldStateCallback = foldStateCallback;
         enable();
     }
 
@@ -112,9 +112,9 @@
         int newRotation = DisplayManagerGlobal.getInstance()
                 .getDisplayInfo(Display.DEFAULT_DISPLAY).rotation;
         synchronized(sRotationLock) {
-            if (newRotation != sDeviceRotation) {
-                sDeviceRotation = newRotation;
-                publishRotation(sDeviceRotation);
+            if (sRotation == null || sRotation != newRotation) {
+                sRotation = newRotation;
+                publishRotation(sRotation);
             }
         }
     }
@@ -123,43 +123,52 @@
         if (DEBUG_ROTATION) {
             Log.i(TAG, "publishing device rotation =" + rotation + " (x90deg)");
         }
-        String rotationParam;
+        int rotationDegrees;
         switch (rotation) {
             case Surface.ROTATION_0:
-                rotationParam = "rotation=0";
+                rotationDegrees = 0;
                 break;
             case Surface.ROTATION_90:
-                rotationParam = "rotation=90";
+                rotationDegrees = 90;
                 break;
             case Surface.ROTATION_180:
-                rotationParam = "rotation=180";
+                rotationDegrees = 180;
                 break;
             case Surface.ROTATION_270:
-                rotationParam = "rotation=270";
+                rotationDegrees = 270;
                 break;
             default:
                 Log.e(TAG, "Unknown device rotation");
-                rotationParam = null;
+                rotationDegrees = -1;
         }
-        if (rotationParam != null) {
-            sRotationUpdateCb.accept(rotationParam);
+        if (rotationDegrees != -1) {
+            sRotationCallback.accept(rotationDegrees);
         }
     }
 
     /**
      * publish the change of device folded state if any.
      */
-    static void updateFoldState(boolean newFolded) {
+    static void updateFoldState(boolean foldState) {
         synchronized (sFoldStateLock) {
-            if (sDeviceFold != newFolded) {
-                sDeviceFold = newFolded;
-                String foldParam;
-                if (newFolded) {
-                    foldParam = "device_folded=on";
-                } else {
-                    foldParam = "device_folded=off";
-                }
-                sFoldUpdateCb.accept(foldParam);
+            if (sFoldState == null || sFoldState != foldState) {
+                sFoldState = foldState;
+                sFoldStateCallback.accept(foldState);
+            }
+        }
+    }
+
+    /**
+     *  forceUpdate is called when audioserver restarts.
+     */
+    static void forceUpdate() {
+        synchronized (sRotationLock) {
+            sRotation = null;
+        }
+        updateOrientation(); // We will get at least one orientation update now.
+        synchronized (sFoldStateLock) {
+            if (sFoldState  != null) {
+                sFoldStateCallback.accept(sFoldState);
             }
         }
     }
@@ -185,4 +194,4 @@
             updateOrientation();
         }
     }
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java
index 8e8fd05..a9e7d4b 100644
--- a/services/core/java/com/android/server/audio/SpatializerHelper.java
+++ b/services/core/java/com/android/server/audio/SpatializerHelper.java
@@ -171,13 +171,17 @@
     // initialization
     @SuppressWarnings("StaticAssignmentInConstructor")
     SpatializerHelper(@NonNull AudioService mother, @NonNull AudioSystemAdapter asa,
-            boolean headTrackingEnabledByDefault) {
+            boolean binauralEnabledDefault,
+            boolean transauralEnabledDefault,
+            boolean headTrackingEnabledDefault) {
         mAudioService = mother;
         mASA = asa;
         // "StaticAssignmentInConstructor" warning is suppressed as the SpatializerHelper being
         // constructed here is the factory for SADeviceState, thus SADeviceState and its
         // private static field sHeadTrackingEnabledDefault should never be accessed directly.
-        SADeviceState.sHeadTrackingEnabledDefault = headTrackingEnabledByDefault;
+        SADeviceState.sBinauralEnabledDefault = binauralEnabledDefault;
+        SADeviceState.sTransauralEnabledDefault = transauralEnabledDefault;
+        SADeviceState.sHeadTrackingEnabledDefault = headTrackingEnabledDefault;
     }
 
     synchronized void initForTest(boolean hasBinaural, boolean hasTransaural) {
@@ -1063,7 +1067,7 @@
         if (transform.length != 6) {
             throw new IllegalArgumentException("invalid array size" + transform.length);
         }
-        if (!checkSpatForHeadTracking("setGlobalTransform")) {
+        if (!checkSpatializerForHeadTracking("setGlobalTransform")) {
             return;
         }
         try {
@@ -1074,7 +1078,7 @@
     }
 
     synchronized void recenterHeadTracker() {
-        if (!checkSpatForHeadTracking("recenterHeadTracker")) {
+        if (!checkSpatializerForHeadTracking("recenterHeadTracker")) {
             return;
         }
         try {
@@ -1084,8 +1088,30 @@
         }
     }
 
+    synchronized void setDisplayOrientation(float displayOrientation) {
+        if (!checkSpatializer("setDisplayOrientation")) {
+            return;
+        }
+        try {
+            mSpat.setDisplayOrientation(displayOrientation);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling setDisplayOrientation", e);
+        }
+    }
+
+    synchronized void setFoldState(boolean folded) {
+        if (!checkSpatializer("setFoldState")) {
+            return;
+        }
+        try {
+            mSpat.setFoldState(folded);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling setFoldState", e);
+        }
+    }
+
     synchronized void setDesiredHeadTrackingMode(@Spatializer.HeadTrackingModeSet int mode) {
-        if (!checkSpatForHeadTracking("setDesiredHeadTrackingMode")) {
+        if (!checkSpatializerForHeadTracking("setDesiredHeadTrackingMode")) {
             return;
         }
         if (mode != Spatializer.HEAD_TRACKING_MODE_DISABLED) {
@@ -1178,7 +1204,7 @@
         return mHeadTrackerAvailable;
     }
 
-    private boolean checkSpatForHeadTracking(String funcName) {
+    private boolean checkSpatializer(String funcName) {
         switch (mState) {
             case STATE_UNINITIALIZED:
             case STATE_NOT_SUPPORTED:
@@ -1189,14 +1215,18 @@
             case STATE_ENABLED_AVAILABLE:
                 if (mSpat == null) {
                     // try to recover by resetting the native spatializer state
-                    Log.e(TAG, "checkSpatForHeadTracking(): "
-                            + "native spatializer should not be null in state: " + mState);
+                    Log.e(TAG, "checkSpatializer(): called from " + funcName
+                            + "(), native spatializer should not be null in state: " + mState);
                     postReset();
                     return false;
                 }
                 break;
         }
-        return mIsHeadTrackingSupported;
+        return true;
+    }
+
+    private boolean checkSpatializerForHeadTracking(String funcName) {
+        return checkSpatializer(funcName) && mIsHeadTrackingSupported;
     }
 
     private void dispatchActualHeadTrackingMode(int newMode) {
@@ -1513,10 +1543,12 @@
     }
 
     /*package*/ static final class SADeviceState {
+        private static boolean sBinauralEnabledDefault = true;
+        private static boolean sTransauralEnabledDefault = true;
         private static boolean sHeadTrackingEnabledDefault = false;
         final @AudioDeviceInfo.AudioDeviceType int mDeviceType;
         final @NonNull String mDeviceAddress;
-        boolean mEnabled = true;               // by default, SA is enabled on any device
+        boolean mEnabled;
         boolean mHasHeadTracker = false;
         boolean mHeadTrackerEnabled;
         static final String SETTING_FIELD_SEPARATOR = ",";
@@ -1532,6 +1564,12 @@
         SADeviceState(@AudioDeviceInfo.AudioDeviceType int deviceType, @Nullable String address) {
             mDeviceType = deviceType;
             mDeviceAddress = isWireless(deviceType) ? Objects.requireNonNull(address) : "";
+            final int spatMode = SPAT_MODE_FOR_DEVICE_TYPE.get(deviceType, Integer.MIN_VALUE);
+            mEnabled = spatMode == SpatializationMode.SPATIALIZER_BINAURAL
+                    ? sBinauralEnabledDefault
+                    : spatMode == SpatializationMode.SPATIALIZER_TRANSAURAL
+                            ? sTransauralEnabledDefault
+                            : false;
             mHeadTrackerEnabled = sHeadTrackingEnabledDefault;
         }
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index 598e2b9..d55dd8a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -343,7 +343,8 @@
             final FingerprintSensorPropertiesInternal sensorProps =
                     provider.second.getSensorProperties(sensorId);
             if (!isKeyguard && !Utils.isSettings(getContext(), opPackageName)
-                    && sensorProps != null && sensorProps.isAnyUdfpsType()) {
+                    && sensorProps != null && (sensorProps.isAnyUdfpsType()
+                    || sensorProps.isAnySidefpsType())) {
                 try {
                     return authenticateWithPrompt(operationId, sensorProps, callingUid,
                             callingUserId, receiver, opPackageName, ignoreEnrollmentState);
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 8b579ac..2292d9b 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -1127,6 +1127,14 @@
         }
     }
 
+    public float convertToFloatScale(float nits) {
+        if (mCurrentBrightnessMapper != null) {
+            return mCurrentBrightnessMapper.convertToFloatScale(nits);
+        } else {
+            return PowerManager.BRIGHTNESS_INVALID_FLOAT;
+        }
+    }
+
     public void recalculateSplines(boolean applyAdjustment, float[] adjustment) {
         mCurrentBrightnessMapper.recalculateSplines(applyAdjustment, adjustment);
 
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
index 3fc50c4..d047183 100644
--- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
+++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
@@ -322,6 +322,14 @@
     public abstract float convertToNits(float brightness);
 
     /**
+     * Converts the provided nit value to a float scale value if possible.
+     *
+     * Returns {@link PowerManager.BRIGHTNESS_INVALID_FLOAT} if there's no available mapping for
+     * the nits to float scale.
+     */
+    public abstract float convertToFloatScale(float nits);
+
+    /**
      * Adds a user interaction data point to the brightness mapping.
      *
      * This data point <b>must</b> exist on the brightness curve as a result of this call. This is
@@ -671,6 +679,11 @@
         }
 
         @Override
+        public float convertToFloatScale(float nits) {
+            return PowerManager.BRIGHTNESS_INVALID_FLOAT;
+        }
+
+        @Override
         public void addUserDataPoint(float lux, float brightness) {
             float unadjustedBrightness = getUnadjustedBrightness(lux);
             if (mLoggingEnabled) {
@@ -913,6 +926,11 @@
         }
 
         @Override
+        public float convertToFloatScale(float nits) {
+            return mNitsToBrightnessSpline.interpolate(nits);
+        }
+
+        @Override
         public void addUserDataPoint(float lux, float brightness) {
             float unadjustedBrightness = getUnadjustedBrightness(lux);
             if (mLoggingEnabled) {
diff --git a/services/core/java/com/android/server/display/BrightnessSetting.java b/services/core/java/com/android/server/display/BrightnessSetting.java
index 7448611..9982d2e 100644
--- a/services/core/java/com/android/server/display/BrightnessSetting.java
+++ b/services/core/java/com/android/server/display/BrightnessSetting.java
@@ -117,6 +117,23 @@
         }
     }
 
+    /**
+     * @return The brightness for the default display in nits. Used when the underlying display
+     * device has changed but we want to persist the nit value.
+     */
+    float getBrightnessNitsForDefaultDisplay() {
+        return mPersistentDataStore.getBrightnessNitsForDefaultDisplay();
+    }
+
+    /**
+     * Set brightness in nits for the default display. Used when we want to persist the nit value
+     * even if the underlying display device changes.
+     * @param nits The brightness value in nits
+     */
+    void setBrightnessNitsForDefaultDisplay(float nits) {
+        mPersistentDataStore.setBrightnessNitsForDefaultDisplay(nits);
+    }
+
     private void notifyListeners(float brightness) {
         for (BrightnessSettingListener l : mListeners) {
             l.onBrightnessChanged(brightness);
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index dbbd354..84dfe86 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -180,7 +180,7 @@
     public static final int TOUCH_VIRTUAL = 3;
 
     /**
-     * Diff result: The {@link #state} fields differ.
+     * Diff result: The {@link #state} or {@link #committedState} fields differ.
      */
     public static final int DIFF_STATE = 1 << 0;
 
@@ -342,6 +342,13 @@
     public int state = Display.STATE_ON;
 
     /**
+     * Display committed state.
+     *
+     * This matches {@link DisplayDeviceInfo#state} only after the power state change finishes.
+     */
+    public int committedState = Display.STATE_UNKNOWN;
+
+    /**
      * The UID of the application that owns this display, or zero if it is owned by the system.
      * <p>
      * If the display is private, then only the owner can use it.
@@ -394,7 +401,7 @@
      */
     public int diff(DisplayDeviceInfo other) {
         int diff = 0;
-        if (state != other.state) {
+        if (state != other.state || committedState != other.committedState) {
             diff |= DIFF_STATE;
         }
         if (colorMode != other.colorMode) {
@@ -468,6 +475,7 @@
         address = other.address;
         deviceProductInfo = other.deviceProductInfo;
         state = other.state;
+        committedState = other.committedState;
         ownerUid = other.ownerUid;
         ownerPackageName = other.ownerPackageName;
         frameRateOverrides = other.frameRateOverrides;
@@ -508,6 +516,7 @@
         }
         sb.append(", deviceProductInfo ").append(deviceProductInfo);
         sb.append(", state ").append(Display.stateToString(state));
+        sb.append(", committedState ").append(Display.stateToString(committedState));
         if (ownerUid != 0 || ownerPackageName != null) {
             sb.append(", owner ").append(ownerPackageName);
             sb.append(" (uid ").append(ownerUid).append(")");
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index 1bbdc20..8c83be3 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -1230,13 +1230,12 @@
         }
 
         public void onDeviceConfigDefaultPeakRefreshRateChanged(Float defaultPeakRefreshRate) {
-            if (defaultPeakRefreshRate == null) {
-                defaultPeakRefreshRate = (float) mContext.getResources().getInteger(
-                        R.integer.config_defaultPeakRefreshRate);
-            }
-
-            if (mDefaultPeakRefreshRate != defaultPeakRefreshRate) {
-                synchronized (mLock) {
+            synchronized (mLock) {
+                if (defaultPeakRefreshRate == null) {
+                    setDefaultPeakRefreshRate(mDefaultDisplayDeviceConfig,
+                        /* attemptLoadingFromDeviceConfig= */ false);
+                    updateRefreshRateSettingLocked();
+                } else if (mDefaultPeakRefreshRate != defaultPeakRefreshRate) {
                     mDefaultPeakRefreshRate = defaultPeakRefreshRate;
                     updateRefreshRateSettingLocked();
                 }
@@ -1869,11 +1868,20 @@
                 mLowDisplayBrightnessThresholds = displayThresholds;
                 mLowAmbientBrightnessThresholds = ambientThresholds;
             } else {
-                // Invalid or empty. Use device default.
-                mLowDisplayBrightnessThresholds = mContext.getResources().getIntArray(
-                        R.array.config_brightnessThresholdsOfPeakRefreshRate);
-                mLowAmbientBrightnessThresholds = mContext.getResources().getIntArray(
-                        R.array.config_ambientThresholdsOfPeakRefreshRate);
+                DisplayDeviceConfig displayDeviceConfig;
+                synchronized (mLock) {
+                    displayDeviceConfig = mDefaultDisplayDeviceConfig;
+                }
+                mLowDisplayBrightnessThresholds = loadBrightnessThresholds(
+                    () -> mDeviceConfigDisplaySettings.getLowDisplayBrightnessThresholds(),
+                    () -> displayDeviceConfig.getLowDisplayBrightnessThresholds(),
+                    R.array.config_brightnessThresholdsOfPeakRefreshRate,
+                    displayDeviceConfig, /* attemptLoadingFromDeviceConfig= */ false);
+                mLowAmbientBrightnessThresholds = loadBrightnessThresholds(
+                    () -> mDeviceConfigDisplaySettings.getLowAmbientBrightnessThresholds(),
+                    () -> displayDeviceConfig.getLowAmbientBrightnessThresholds(),
+                    R.array.config_ambientThresholdsOfPeakRefreshRate,
+                    displayDeviceConfig, /* attemptLoadingFromDeviceConfig= */ false);
             }
             restartObserver();
         }
@@ -1883,24 +1891,41 @@
          * DeviceConfig properties.
          */
         public void onDeviceConfigRefreshRateInLowZoneChanged(int refreshRate) {
-            if (refreshRate != mRefreshRateInLowZone) {
+            if (refreshRate == -1) {
+                // Given there is no value available in DeviceConfig, lets not attempt loading it
+                // from there.
+                synchronized (mLock) {
+                    loadRefreshRateInLowZone(mDefaultDisplayDeviceConfig,
+                        /* attemptLoadingFromDeviceConfig= */ false);
+                }
+                restartObserver();
+            } else if (refreshRate != mRefreshRateInLowZone) {
                 mRefreshRateInLowZone = refreshRate;
                 restartObserver();
             }
         }
 
-        public void onDeviceConfigHighBrightnessThresholdsChanged(int[] displayThresholds,
+        private void onDeviceConfigHighBrightnessThresholdsChanged(int[] displayThresholds,
                 int[] ambientThresholds) {
             if (displayThresholds != null && ambientThresholds != null
                     && displayThresholds.length == ambientThresholds.length) {
                 mHighDisplayBrightnessThresholds = displayThresholds;
                 mHighAmbientBrightnessThresholds = ambientThresholds;
             } else {
-                // Invalid or empty. Use device default.
-                mHighDisplayBrightnessThresholds = mContext.getResources().getIntArray(
-                        R.array.config_highDisplayBrightnessThresholdsOfFixedRefreshRate);
-                mHighAmbientBrightnessThresholds = mContext.getResources().getIntArray(
-                        R.array.config_highAmbientBrightnessThresholdsOfFixedRefreshRate);
+                DisplayDeviceConfig displayDeviceConfig;
+                synchronized (mLock) {
+                    displayDeviceConfig = mDefaultDisplayDeviceConfig;
+                }
+                mHighDisplayBrightnessThresholds = loadBrightnessThresholds(
+                    () -> mDeviceConfigDisplaySettings.getHighDisplayBrightnessThresholds(),
+                    () -> displayDeviceConfig.getHighDisplayBrightnessThresholds(),
+                    R.array.config_highDisplayBrightnessThresholdsOfFixedRefreshRate,
+                    displayDeviceConfig, /* attemptLoadingFromDeviceConfig= */ false);
+                mHighAmbientBrightnessThresholds = loadBrightnessThresholds(
+                    () -> mDeviceConfigDisplaySettings.getHighAmbientBrightnessThresholds(),
+                    () -> displayDeviceConfig.getHighAmbientBrightnessThresholds(),
+                    R.array.config_highAmbientBrightnessThresholdsOfFixedRefreshRate,
+                    displayDeviceConfig, /* attemptLoadingFromDeviceConfig= */ false);
             }
             restartObserver();
         }
@@ -1910,7 +1935,15 @@
          * DeviceConfig properties.
          */
         public void onDeviceConfigRefreshRateInHighZoneChanged(int refreshRate) {
-            if (refreshRate != mRefreshRateInHighZone) {
+            if (refreshRate == -1) {
+                // Given there is no value available in DeviceConfig, lets not attempt loading it
+                // from there.
+                synchronized (mLock) {
+                    loadRefreshRateInHighZone(mDefaultDisplayDeviceConfig,
+                        /* attemptLoadingFromDeviceConfig= */ false);
+                }
+                restartObserver();
+            } else if (refreshRate != mRefreshRateInHighZone) {
                 mRefreshRateInHighZone = refreshRate;
                 restartObserver();
             }
@@ -2870,10 +2903,8 @@
                     new Pair<>(lowDisplayBrightnessThresholds, lowAmbientBrightnessThresholds))
                     .sendToTarget();
 
-            if (refreshRateInLowZone != -1) {
-                mHandler.obtainMessage(MSG_REFRESH_RATE_IN_LOW_ZONE_CHANGED, refreshRateInLowZone,
-                        0).sendToTarget();
-            }
+            mHandler.obtainMessage(MSG_REFRESH_RATE_IN_LOW_ZONE_CHANGED, refreshRateInLowZone,
+                0).sendToTarget();
 
             int[] highDisplayBrightnessThresholds = getHighDisplayBrightnessThresholds();
             int[] highAmbientBrightnessThresholds = getHighAmbientBrightnessThresholds();
@@ -2883,10 +2914,8 @@
                     new Pair<>(highDisplayBrightnessThresholds, highAmbientBrightnessThresholds))
                     .sendToTarget();
 
-            if (refreshRateInHighZone != -1) {
-                mHandler.obtainMessage(MSG_REFRESH_RATE_IN_HIGH_ZONE_CHANGED, refreshRateInHighZone,
-                        0).sendToTarget();
-            }
+            mHandler.obtainMessage(MSG_REFRESH_RATE_IN_HIGH_ZONE_CHANGED, refreshRateInHighZone,
+                0).sendToTarget();
 
             synchronized (mLock) {
                 final int refreshRateInHbmSunlight =
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 5ecc7f2..47e880a 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -233,6 +233,10 @@
     // True if should use light sensor to automatically determine doze screen brightness.
     private final boolean mAllowAutoBrightnessWhileDozingConfig;
 
+    // True if we want to persist the brightness value in nits even if the underlying display
+    // device changes.
+    private final boolean mPersistBrightnessNitsForDefaultDisplay;
+
     // True if the brightness config has changed and the short-term model needs to be reset
     private boolean mShouldResetShortTermModel;
 
@@ -583,6 +587,9 @@
         mAllowAutoBrightnessWhileDozingConfig = resources.getBoolean(
                 com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing);
 
+        mPersistBrightnessNitsForDefaultDisplay = resources.getBoolean(
+                com.android.internal.R.bool.config_persistBrightnessNitsForDefaultDisplay);
+
         mDisplayDeviceConfig = logicalDisplay.getPrimaryDisplayDeviceLocked()
                 .getDisplayDeviceConfig();
 
@@ -651,7 +658,7 @@
 
         loadProximitySensor();
 
-        mCurrentScreenBrightnessSetting = getScreenBrightnessSetting();
+        loadNitBasedBrightnessSetting();
         mScreenBrightnessForVr = getScreenBrightnessForVrSetting();
         mAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting();
         mTemporaryScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
@@ -829,6 +836,7 @@
                 mDisplayStatsId = mUniqueDisplayId.hashCode();
                 mDisplayDeviceConfig = config;
                 loadFromDisplayDeviceConfig(token, info, hbmMetadata);
+                loadNitBasedBrightnessSetting();
 
                 /// Since the underlying display-device changed, we really don't know the
                 // last command that was sent to change it's state. Lets assume it is unknown so
@@ -873,10 +881,6 @@
                 mAutomaticBrightnessController.stop();
             }
 
-            if (mScreenOffBrightnessSensorController != null) {
-                mScreenOffBrightnessSensorController.stop();
-            }
-
             if (mBrightnessSetting != null) {
                 mBrightnessSetting.unregisterListener(mBrightnessSettingListener);
             }
@@ -1125,6 +1129,7 @@
 
             if (mScreenOffBrightnessSensorController != null) {
                 mScreenOffBrightnessSensorController.stop();
+                mScreenOffBrightnessSensorController = null;
             }
             loadScreenOffBrightnessSensor();
             int[] sensorValueToLux = mDisplayDeviceConfig.getScreenOffBrightnessSensorValueToLux();
@@ -1242,6 +1247,10 @@
             mPowerState.stop();
             mPowerState = null;
         }
+
+        if (mScreenOffBrightnessSensorController != null) {
+            mScreenOffBrightnessSensorController.stop();
+        }
     }
 
     private void updatePowerState() {
@@ -1363,8 +1372,17 @@
                 sendOnProximityNegativeWithWakelock();
             }
         } else {
+            setProximitySensorEnabled(false);
             mWaitingForNegativeProximity = false;
             mIgnoreProximityUntilChanged = false;
+
+            if (mScreenOffBecauseOfProximity) {
+                // The screen *was* off due to prox being near, but now there's no prox sensor, so
+                // let's turn the screen back on.
+                mScreenOffBecauseOfProximity = false;
+                skipRampBecauseOfProximityChangeToNegative = true;
+                sendOnProximityNegativeWithWakelock();
+            }
         }
 
         if (!mIsEnabled
@@ -2497,10 +2515,33 @@
         return clampScreenBrightnessForVr(brightnessFloat);
     }
 
+    private void loadNitBasedBrightnessSetting() {
+        if (mDisplayId == Display.DEFAULT_DISPLAY && mPersistBrightnessNitsForDefaultDisplay) {
+            float brightnessNitsForDefaultDisplay =
+                    mBrightnessSetting.getBrightnessNitsForDefaultDisplay();
+            if (brightnessNitsForDefaultDisplay >= 0) {
+                float brightnessForDefaultDisplay = convertToFloatScale(
+                        brightnessNitsForDefaultDisplay);
+                if (isValidBrightnessValue(brightnessForDefaultDisplay)) {
+                    mBrightnessSetting.setBrightness(brightnessForDefaultDisplay);
+                    mCurrentScreenBrightnessSetting = brightnessForDefaultDisplay;
+                    return;
+                }
+            }
+        }
+        mCurrentScreenBrightnessSetting = getScreenBrightnessSetting();
+    }
+
     void setBrightness(float brightnessValue) {
         // Update the setting, which will eventually call back into DPC to have us actually update
         // the display with the new value.
         mBrightnessSetting.setBrightness(brightnessValue);
+        if (mDisplayId == Display.DEFAULT_DISPLAY && mPersistBrightnessNitsForDefaultDisplay) {
+            float nits = convertToNits(brightnessValue);
+            if (nits >= 0) {
+                mBrightnessSetting.setBrightnessNitsForDefaultDisplay(nits);
+            }
+        }
     }
 
     void onBootCompleted() {
@@ -2513,7 +2554,7 @@
             return;
         }
         setCurrentScreenBrightness(brightnessValue);
-        mBrightnessSetting.setBrightness(brightnessValue);
+        setBrightness(brightnessValue);
     }
 
     private void setCurrentScreenBrightness(float brightnessValue) {
@@ -2592,6 +2633,13 @@
         return mAutomaticBrightnessController.convertToNits(brightness);
     }
 
+    private float convertToFloatScale(float nits) {
+        if (mAutomaticBrightnessController == null) {
+            return PowerManager.BRIGHTNESS_INVALID_FLOAT;
+        }
+        return mAutomaticBrightnessController.convertToFloatScale(nits);
+    }
+
     @GuardedBy("mLock")
     private void updatePendingProximityRequestsLocked() {
         mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked;
@@ -2689,25 +2737,27 @@
         pw.println("  mScreenBrightnessForVrRangeMaximum=" + mScreenBrightnessForVrRangeMaximum);
         pw.println("  mScreenBrightnessForVrDefault=" + mScreenBrightnessForVrDefault);
         pw.println("  mUseSoftwareAutoBrightnessConfig=" + mUseSoftwareAutoBrightnessConfig);
-        pw.println("  mAllowAutoBrightnessWhileDozingConfig=" +
-                mAllowAutoBrightnessWhileDozingConfig);
+        pw.println("  mAllowAutoBrightnessWhileDozingConfig="
+                + mAllowAutoBrightnessWhileDozingConfig);
+        pw.println("  mPersistBrightnessNitsForDefaultDisplay="
+                + mPersistBrightnessNitsForDefaultDisplay);
         pw.println("  mSkipScreenOnBrightnessRamp=" + mSkipScreenOnBrightnessRamp);
         pw.println("  mColorFadeFadesConfig=" + mColorFadeFadesConfig);
         pw.println("  mColorFadeEnabled=" + mColorFadeEnabled);
         synchronized (mCachedBrightnessInfo) {
-            pw.println("  mCachedBrightnessInfo.brightness=" +
-                    mCachedBrightnessInfo.brightness.value);
-            pw.println("  mCachedBrightnessInfo.adjustedBrightness=" +
-                    mCachedBrightnessInfo.adjustedBrightness.value);
-            pw.println("  mCachedBrightnessInfo.brightnessMin=" +
-                    mCachedBrightnessInfo.brightnessMin.value);
-            pw.println("  mCachedBrightnessInfo.brightnessMax=" +
-                    mCachedBrightnessInfo.brightnessMax.value);
+            pw.println("  mCachedBrightnessInfo.brightness="
+                    + mCachedBrightnessInfo.brightness.value);
+            pw.println("  mCachedBrightnessInfo.adjustedBrightness="
+                    + mCachedBrightnessInfo.adjustedBrightness.value);
+            pw.println("  mCachedBrightnessInfo.brightnessMin="
+                    + mCachedBrightnessInfo.brightnessMin.value);
+            pw.println("  mCachedBrightnessInfo.brightnessMax="
+                    + mCachedBrightnessInfo.brightnessMax.value);
             pw.println("  mCachedBrightnessInfo.hbmMode=" + mCachedBrightnessInfo.hbmMode.value);
-            pw.println("  mCachedBrightnessInfo.hbmTransitionPoint=" +
-                    mCachedBrightnessInfo.hbmTransitionPoint.value);
-            pw.println("  mCachedBrightnessInfo.brightnessMaxReason =" +
-                    mCachedBrightnessInfo.brightnessMaxReason.value);
+            pw.println("  mCachedBrightnessInfo.hbmTransitionPoint="
+                    + mCachedBrightnessInfo.hbmTransitionPoint.value);
+            pw.println("  mCachedBrightnessInfo.brightnessMaxReason ="
+                    + mCachedBrightnessInfo.brightnessMaxReason.value);
         }
         pw.println("  mDisplayBlanksAfterDozeConfig=" + mDisplayBlanksAfterDozeConfig);
         pw.println("  mBrightnessBucketsInDozeConfig=" + mBrightnessBucketsInDozeConfig);
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index efb2cb7..58a182a 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -198,6 +198,8 @@
         private DisplayDeviceInfo mInfo;
         private boolean mHavePendingChanges;
         private int mState = Display.STATE_UNKNOWN;
+        private int mCommittedState = Display.STATE_UNKNOWN;
+
         // This is only set in the runnable returned from requestDisplayStateLocked.
         private float mBrightnessState = PowerManager.BRIGHTNESS_INVALID_FLOAT;
         private float mSdrBrightnessState = PowerManager.BRIGHTNESS_INVALID_FLOAT;
@@ -635,6 +637,7 @@
                 mInfo.appVsyncOffsetNanos = mActiveSfDisplayMode.appVsyncOffsetNanos;
                 mInfo.presentationDeadlineNanos = mActiveSfDisplayMode.presentationDeadlineNanos;
                 mInfo.state = mState;
+                mInfo.committedState = mCommittedState;
                 mInfo.uniqueId = getUniqueId();
                 final DisplayAddress.Physical physicalAddress =
                         DisplayAddress.fromPhysicalDisplayId(mPhysicalDisplayId);
@@ -822,6 +825,7 @@
                         } finally {
                             Trace.traceEnd(Trace.TRACE_TAG_POWER);
                         }
+                        setCommittedState(state);
                         // If we're entering a suspended (but not OFF) power state and we
                         // have a sidekick available, tell it now that it can take control.
                         if (Display.isSuspendedState(state) && state != Display.STATE_OFF
@@ -836,6 +840,16 @@
                         }
                     }
 
+                    private void setCommittedState(int state) {
+                        // After the display state is set, let's update the committed state.
+                        getHandler().post(() -> {
+                            synchronized (getSyncRoot()) {
+                                mCommittedState = state;
+                                updateDeviceInfoLocked();
+                            }
+                        });
+                    }
+
                     private void setDisplayBrightness(float brightnessState,
                             float sdrBrightnessState) {
                         // brightnessState includes invalid, off and full range.
@@ -1108,6 +1122,7 @@
             pw.println("mDefaultModeId=" + mDefaultModeId);
             pw.println("mUserPreferredModeId=" + mUserPreferredModeId);
             pw.println("mState=" + Display.stateToString(mState));
+            pw.println("mCommittedState=" + Display.stateToString(mCommittedState));
             pw.println("mBrightnessState=" + mBrightnessState);
             pw.println("mBacklightAdapter=" + mBacklightAdapter);
             pw.println("mAllmSupported=" + mAllmSupported);
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 7dc412e..178278e 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -390,6 +390,7 @@
             mBaseDisplayInfo.appVsyncOffsetNanos = deviceInfo.appVsyncOffsetNanos;
             mBaseDisplayInfo.presentationDeadlineNanos = deviceInfo.presentationDeadlineNanos;
             mBaseDisplayInfo.state = deviceInfo.state;
+            mBaseDisplayInfo.committedState = deviceInfo.committedState;
             mBaseDisplayInfo.smallestNominalAppWidth = maskedWidth;
             mBaseDisplayInfo.smallestNominalAppHeight = maskedHeight;
             mBaseDisplayInfo.largestNominalAppWidth = maskedWidth;
diff --git a/services/core/java/com/android/server/display/PersistentDataStore.java b/services/core/java/com/android/server/display/PersistentDataStore.java
index 73131a1..a8e0d58 100644
--- a/services/core/java/com/android/server/display/PersistentDataStore.java
+++ b/services/core/java/com/android/server/display/PersistentDataStore.java
@@ -94,6 +94,7 @@
  *          &lt;/brightness-curve>
  *      &lt;/brightness-configuration>
  *  &lt;/brightness-configurations>
+ *  &lt;brightness-nits-for-default-display>600&lt;/brightness-nits-for-default-display>
  * &lt;/display-manager-state>
  * </code>
  *
@@ -130,6 +131,9 @@
     private static final String TAG_RESOLUTION_HEIGHT = "resolution-height";
     private static final String TAG_REFRESH_RATE = "refresh-rate";
 
+    private static final String TAG_BRIGHTNESS_NITS_FOR_DEFAULT_DISPLAY =
+            "brightness-nits-for-default-display";
+
     // Remembered Wifi display devices.
     private ArrayList<WifiDisplay> mRememberedWifiDisplays = new ArrayList<WifiDisplay>();
 
@@ -137,6 +141,8 @@
     private final HashMap<String, DisplayState> mDisplayStates =
             new HashMap<String, DisplayState>();
 
+    private float mBrightnessNitsForDefaultDisplay = -1;
+
     // Display values which should be stable across the device's lifetime.
     private final StableDeviceValues mStableDeviceValues = new StableDeviceValues();
 
@@ -312,6 +318,19 @@
         return false;
     }
 
+    public float getBrightnessNitsForDefaultDisplay() {
+        return mBrightnessNitsForDefaultDisplay;
+    }
+
+    public boolean setBrightnessNitsForDefaultDisplay(float nits) {
+        if (nits != mBrightnessNitsForDefaultDisplay) {
+            mBrightnessNitsForDefaultDisplay = nits;
+            setDirty();
+            return true;
+        }
+        return false;
+    }
+
     public boolean setUserPreferredRefreshRate(DisplayDevice displayDevice, float refreshRate) {
         final String displayDeviceUniqueId = displayDevice.getUniqueId();
         if (!displayDevice.hasStableUniqueId() || displayDeviceUniqueId == null) {
@@ -513,6 +532,10 @@
             if (parser.getName().equals(TAG_BRIGHTNESS_CONFIGURATIONS)) {
                 mGlobalBrightnessConfigurations.loadFromXml(parser);
             }
+            if (parser.getName().equals(TAG_BRIGHTNESS_NITS_FOR_DEFAULT_DISPLAY)) {
+                String value = parser.nextText();
+                mBrightnessNitsForDefaultDisplay = Float.parseFloat(value);
+            }
         }
     }
 
@@ -592,6 +615,9 @@
         serializer.startTag(null, TAG_BRIGHTNESS_CONFIGURATIONS);
         mGlobalBrightnessConfigurations.saveToXml(serializer);
         serializer.endTag(null, TAG_BRIGHTNESS_CONFIGURATIONS);
+        serializer.startTag(null, TAG_BRIGHTNESS_NITS_FOR_DEFAULT_DISPLAY);
+        serializer.text(Float.toString(mBrightnessNitsForDefaultDisplay));
+        serializer.endTag(null, TAG_BRIGHTNESS_NITS_FOR_DEFAULT_DISPLAY);
         serializer.endTag(null, TAG_DISPLAY_MANAGER_STATE);
         serializer.endDocument();
     }
@@ -615,6 +641,7 @@
         mStableDeviceValues.dump(pw, "      ");
         pw.println("  GlobalBrightnessConfigurations:");
         mGlobalBrightnessConfigurations.dump(pw, "      ");
+        pw.println("  mBrightnessNitsForDefaultDisplay=" + mBrightnessNitsForDefaultDisplay);
     }
 
     private static final class DisplayState {
diff --git a/services/core/java/com/android/server/media/projection/OWNERS b/services/core/java/com/android/server/media/projection/OWNERS
index 9ca3910..832bcd9 100644
--- a/services/core/java/com/android/server/media/projection/OWNERS
+++ b/services/core/java/com/android/server/media/projection/OWNERS
@@ -1,2 +1 @@
-michaelwr@google.com
-santoscordon@google.com
+include /media/java/android/media/projection/OWNERS
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index ff10cbc..4df34ca 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -17,6 +17,7 @@
 package com.android.server.notification;
 
 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
+import static android.app.ActivityManagerInternal.ServiceNotificationPolicy.NOT_FOREGROUND_SERVICE;
 import static android.app.AppOpsManager.MODE_ALLOWED;
 import static android.app.Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
 import static android.app.Notification.FLAG_AUTOGROUP_SUMMARY;
@@ -6323,21 +6324,40 @@
             checkCallerIsSystem();
             mHandler.post(() -> {
                 synchronized (mNotificationLock) {
-                    // strip flag from all enqueued notifications. listeners will be informed
-                    // in post runnable.
-                    List<NotificationRecord> enqueued = findNotificationsByListLocked(
-                            mEnqueuedNotifications, pkg, null, notificationId, userId);
-                    for (int i = 0; i < enqueued.size(); i++) {
-                        removeForegroundServiceFlagLocked(enqueued.get(i));
+                    int count = getNotificationCount(pkg, userId);
+                    boolean removeFgsNotification = false;
+                    if (count > MAX_PACKAGE_NOTIFICATIONS) {
+                        mUsageStats.registerOverCountQuota(pkg);
+                        removeFgsNotification = true;
                     }
+                    if (removeFgsNotification) {
+                        NotificationRecord r = findNotificationLocked(pkg, null, notificationId,
+                                userId);
+                        if (r != null) {
+                            if (DBG) {
+                                Slog.d(TAG, "Remove FGS flag not allow. Cancel FGS notification");
+                            }
+                            removeFromNotificationListsLocked(r);
+                            cancelNotificationLocked(r, false, REASON_APP_CANCEL, true,
+                                    null, SystemClock.elapsedRealtime());
+                        }
+                    } else {
+                        // strip flag from all enqueued notifications. listeners will be informed
+                        // in post runnable.
+                        List<NotificationRecord> enqueued = findNotificationsByListLocked(
+                                mEnqueuedNotifications, pkg, null, notificationId, userId);
+                        for (int i = 0; i < enqueued.size(); i++) {
+                            removeForegroundServiceFlagLocked(enqueued.get(i));
+                        }
 
-                    // if posted notification exists, strip its flag and tell listeners
-                    NotificationRecord r = findNotificationByListLocked(
-                            mNotificationList, pkg, null, notificationId, userId);
-                    if (r != null) {
-                        removeForegroundServiceFlagLocked(r);
-                        mRankingHelper.sort(mNotificationList);
-                        mListeners.notifyPostedLocked(r, r);
+                        // if posted notification exists, strip its flag and tell listeners
+                        NotificationRecord r = findNotificationByListLocked(
+                                mNotificationList, pkg, null, notificationId, userId);
+                        if (r != null) {
+                            removeForegroundServiceFlagLocked(r);
+                            mRankingHelper.sort(mNotificationList);
+                            mListeners.notifyPostedLocked(r, r);
+                        }
                     }
                 }
             });
@@ -6483,9 +6503,17 @@
 
         checkRestrictedCategories(notification);
 
+        // Notifications passed to setForegroundService() have FLAG_FOREGROUND_SERVICE,
+        // but it's also possible that the app has called notify() with an update to an
+        // FGS notification that hasn't yet been displayed.  Make sure we check for any
+        // FGS-related situation up front, outside of any locks so it's safe to call into
+        // the Activity Manager.
+        final ServiceNotificationPolicy policy = mAmi.applyForegroundServiceNotification(
+                notification, tag, id, pkg, userId);
+
         // Fix the notification as best we can.
         try {
-            fixNotification(notification, pkg, tag, id, userId);
+            fixNotification(notification, pkg, tag, id, userId, notificationUid, policy);
         } catch (Exception e) {
             if (notification.isForegroundService()) {
                 throw new SecurityException("Invalid FGS notification", e);
@@ -6494,13 +6522,7 @@
             return;
         }
 
-        // Notifications passed to setForegroundService() have FLAG_FOREGROUND_SERVICE,
-        // but it's also possible that the app has called notify() with an update to an
-        // FGS notification that hasn't yet been displayed.  Make sure we check for any
-        // FGS-related situation up front, outside of any locks so it's safe to call into
-        // the Activity Manager.
-        final ServiceNotificationPolicy policy = mAmi.applyForegroundServiceNotification(
-                notification, tag, id, pkg, userId);
+
         if (policy == ServiceNotificationPolicy.UPDATE_ONLY) {
             // Proceed if the notification is already showing/known, otherwise ignore
             // because the service lifecycle logic has retained responsibility for its
@@ -6663,14 +6685,20 @@
 
     @VisibleForTesting
     protected void fixNotification(Notification notification, String pkg, String tag, int id,
-            int userId) throws NameNotFoundException, RemoteException {
+            @UserIdInt int userId, int notificationUid, ServiceNotificationPolicy fgsPolicy)
+            throws NameNotFoundException, RemoteException {
         final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
                 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
                 (userId == UserHandle.USER_ALL) ? USER_SYSTEM : userId);
         Notification.addFieldsFromContext(ai, notification);
 
-        int canColorize = mPackageManagerClient.checkPermission(
-                android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, pkg);
+        if (notification.isForegroundService() && fgsPolicy == NOT_FOREGROUND_SERVICE) {
+            notification.flags &= ~FLAG_FOREGROUND_SERVICE;
+        }
+
+        int canColorize = getContext().checkPermission(
+                android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, -1, notificationUid);
+
         if (canColorize == PERMISSION_GRANTED) {
             notification.flags |= Notification.FLAG_CAN_COLORIZE;
         } else {
@@ -6723,7 +6751,8 @@
         }
 
         // Ensure MediaStyle has correct permissions for remote device extras
-        if (notification.isStyle(Notification.MediaStyle.class)) {
+        if (notification.isStyle(Notification.MediaStyle.class)
+                || notification.isStyle(Notification.DecoratedMediaCustomViewStyle.class)) {
             int hasMediaContentControlPermission = mPackageManager.checkPermission(
                     android.Manifest.permission.MEDIA_CONTENT_CONTROL, pkg, userId);
             if (hasMediaContentControlPermission != PERMISSION_GRANTED) {
@@ -7059,6 +7088,29 @@
         return mPermissionHelper.hasPermission(uid);
     }
 
+    private int getNotificationCount(String pkg, int userId) {
+        int count = 0;
+        synchronized (mNotificationLock) {
+            final int numListSize = mNotificationList.size();
+            for (int i = 0; i < numListSize; i++) {
+                final NotificationRecord existing = mNotificationList.get(i);
+                if (existing.getSbn().getPackageName().equals(pkg)
+                        && existing.getSbn().getUserId() == userId) {
+                    count++;
+                }
+            }
+            final int numEnqSize = mEnqueuedNotifications.size();
+            for (int i = 0; i < numEnqSize; i++) {
+                final NotificationRecord existing = mEnqueuedNotifications.get(i);
+                if (existing.getSbn().getPackageName().equals(pkg)
+                        && existing.getSbn().getUserId() == userId) {
+                    count++;
+                }
+            }
+        }
+        return count;
+    }
+
     protected int getNotificationCount(String pkg, int userId, int excludedId,
             String excludedTag) {
         int count = 0;
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 7fc46fd..a2b2983 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -1641,7 +1641,7 @@
             return false;
         }
         int uid = injectGetPackageUid(systemChooser.getPackageName(), UserHandle.USER_SYSTEM);
-        return uid == callingUid;
+        return UserHandle.getAppId(uid) == UserHandle.getAppId(callingUid);
     }
 
     private void enforceSystemOrShell() {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 866a995..88aeb17 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -96,6 +96,7 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.AtomicFile;
+import android.util.EventLog;
 import android.util.IndentingPrintWriter;
 import android.util.IntArray;
 import android.util.Slog;
@@ -5028,6 +5029,13 @@
     public void setApplicationRestrictions(String packageName, Bundle restrictions,
             @UserIdInt int userId) {
         checkSystemOrRoot("set application restrictions");
+        String validationResult = validateName(packageName);
+        if (validationResult != null) {
+            if (packageName.contains("../")) {
+                EventLog.writeEvent(0x534e4554, "239701237", -1, "");
+            }
+            throw new IllegalArgumentException("Invalid package name: " + validationResult);
+        }
         if (restrictions != null) {
             restrictions.setDefusable(true);
         }
@@ -5054,6 +5062,39 @@
         mContext.sendBroadcastAsUser(changeIntent, UserHandle.of(userId));
     }
 
+    /**
+     * Check if the given name is valid.
+     *
+     * Note: the logic is taken from FrameworkParsingPackageUtils in master, edited to remove
+     * unnecessary parts. Copied here for a security fix.
+     *
+     * @param name The name to check.
+     * @return null if it's valid, error message if not
+     */
+    @VisibleForTesting
+    static String validateName(String name) {
+        final int n = name.length();
+        boolean front = true;
+        for (int i = 0; i < n; i++) {
+            final char c = name.charAt(i);
+            if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
+                front = false;
+                continue;
+            }
+            if (!front) {
+                if ((c >= '0' && c <= '9') || c == '_') {
+                    continue;
+                }
+                if (c == '.') {
+                    front = true;
+                    continue;
+                }
+            }
+            return "bad character '" + c + "'";
+        }
+        return null;
+    }
+
     private int getUidForPackage(String packageName) {
         final long ident = Binder.clearCallingIdentity();
         try {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index f913cef..afd9316 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -199,6 +199,7 @@
 import com.android.internal.policy.TransitionAnimation;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.widget.LockPatternUtils;
 import com.android.server.ExtconStateObserver;
 import com.android.server.ExtconUEventObserver;
 import com.android.server.GestureLauncherService;
@@ -407,6 +408,7 @@
     AppOpsManager mAppOpsManager;
     PackageManager mPackageManager;
     SideFpsEventHandler mSideFpsEventHandler;
+    LockPatternUtils mLockPatternUtils;
     private boolean mHasFeatureAuto;
     private boolean mHasFeatureWatch;
     private boolean mHasFeatureLeanback;
@@ -627,6 +629,9 @@
 
     private boolean mLockNowPending = false;
 
+    // Timeout for showing the keyguard after the screen is on, in case no "ready" is received.
+    private int mKeyguardDrawnTimeout = 1000;
+
     private static final int MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK = 3;
     private static final int MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK = 4;
     private static final int MSG_KEYGUARD_DRAWN_COMPLETE = 5;
@@ -1056,8 +1061,10 @@
         }
 
         synchronized (mLock) {
-            // Lock the device after the dream transition has finished.
-            mLockAfterAppTransitionFinished = true;
+            // If the setting to lock instantly on power button press is true, then set the flag to
+            // lock after the dream transition has finished.
+            mLockAfterAppTransitionFinished =
+                    mLockPatternUtils.getPowerButtonInstantlyLocks(mCurrentUserId);
         }
 
         dreamManagerInternal.requestDream();
@@ -1501,7 +1508,9 @@
 
     private void interceptScreenshotChord(int source, long pressDelay) {
         mHandler.removeMessages(MSG_SCREENSHOT_CHORD);
-        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SCREENSHOT_CHORD, source),
+        // arg2 is unused, but necessary to insure we call the correct method signature
+        // since the screenshot source is read from message.arg1
+        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SCREENSHOT_CHORD, source, 0),
                 pressDelay);
     }
 
@@ -1929,6 +1938,7 @@
         mHasFeatureHdmiCec = mPackageManager.hasSystemFeature(FEATURE_HDMI_CEC);
         mAccessibilityShortcutController =
                 new AccessibilityShortcutController(mContext, new Handler(), mCurrentUserId);
+        mLockPatternUtils = new LockPatternUtils(mContext);
         mLogger = new MetricsLogger();
 
         mScreenOffSleepTokenAcquirer = mActivityTaskManagerInternal
@@ -2156,6 +2166,8 @@
             }
         });
 
+        mKeyguardDrawnTimeout = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_keyguardDrawnTimeout);
         mKeyguardDelegate = new KeyguardServiceDelegate(mContext,
                 new StateCallback() {
                     @Override
@@ -3329,8 +3341,7 @@
             mPendingKeyguardOccluded = occluded;
             mKeyguardOccludedChanged = true;
         } else {
-            setKeyguardOccludedLw(occluded, false /* force */,
-                    false /* transitionStarted */);
+            setKeyguardOccludedLw(occluded, false /* transitionStarted */);
         }
     }
 
@@ -3339,8 +3350,7 @@
         if (mKeyguardOccludedChanged) {
             if (DEBUG_KEYGUARD) Slog.d(TAG, "transition/occluded changed occluded="
                     + mPendingKeyguardOccluded);
-            if (setKeyguardOccludedLw(mPendingKeyguardOccluded, false /* force */,
-                    transitionStarted)) {
+            if (setKeyguardOccludedLw(mPendingKeyguardOccluded, transitionStarted)) {
                 return FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_WALLPAPER;
             }
         }
@@ -3589,22 +3599,15 @@
     }
 
     /**
-     * Updates the occluded state of the Keyguard.
+     * Updates the occluded state of the Keyguard immediately via
+     * {@link com.android.internal.policy.IKeyguardService}.
      *
      * @param isOccluded Whether the Keyguard is occluded by another window.
-     * @param force notify the occluded status to KeyguardService and update flags even though
-     *             occlude status doesn't change.
      * @param transitionStarted {@code true} if keyguard (un)occluded transition started.
      * @return Whether the flags have changed and we have to redo the layout.
      */
-    private boolean setKeyguardOccludedLw(boolean isOccluded, boolean force,
-            boolean transitionStarted) {
+    private boolean setKeyguardOccludedLw(boolean isOccluded, boolean transitionStarted) {
         if (DEBUG_KEYGUARD) Slog.d(TAG, "setKeyguardOccluded occluded=" + isOccluded);
-        mKeyguardOccludedChanged = false;
-        if (isKeyguardOccluded() == isOccluded && !force) {
-            return false;
-        }
-
         final boolean showing = mKeyguardDelegate.isShowing();
         final boolean animate = showing && !isOccluded;
         // When remote animation is enabled for keyguard (un)occlude transition, KeyguardService
@@ -3612,7 +3615,10 @@
         // to notify here.
         final boolean notify = !WindowManagerService.sEnableRemoteKeyguardOccludeAnimation
                 || !transitionStarted;
-        mKeyguardDelegate.setOccluded(isOccluded, animate, notify);
+        if (notify) {
+            mKeyguardOccludedChanged = false;
+            mKeyguardDelegate.setOccluded(isOccluded, animate, notify);
+        }
         return showing;
     }
 
@@ -4761,7 +4767,7 @@
         final boolean bootCompleted =
                 LocalServices.getService(SystemServiceManager.class).isBootCompleted();
         // Set longer timeout if it has not booted yet to prevent showing empty window.
-        return bootCompleted ? 1000 : 5000;
+        return bootCompleted ? mKeyguardDrawnTimeout : 5000;
     }
 
     // Called on the DisplayManager's DisplayPowerController thread.
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 3baaa9d..45d2e3c 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -29,6 +29,7 @@
 import com.android.internal.policy.IKeyguardService;
 import com.android.server.UiThread;
 import com.android.server.policy.WindowManagerPolicy.OnKeyguardExitResult;
+import com.android.server.wm.EventLogTags;
 
 import java.io.PrintWriter;
 
@@ -257,6 +258,11 @@
     public void setOccluded(boolean isOccluded, boolean animate, boolean notify) {
         if (mKeyguardService != null && notify) {
             if (DEBUG) Log.v(TAG, "setOccluded(" + isOccluded + ") animate=" + animate);
+            EventLogTags.writeWmSetKeyguardOccluded(
+                    isOccluded ? 1 : 0,
+                    animate ? 1 : 0,
+                    0 /* transit */,
+                    "setOccluded");
             mKeyguardService.setOccluded(isOccluded, animate);
         }
         mKeyguardState.occluded = isOccluded;
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
index ce1157e..70932fa 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
@@ -26,6 +26,7 @@
 import android.media.soundtrigger.PhraseSoundModel;
 import android.media.soundtrigger.RecognitionConfig;
 import android.media.soundtrigger.RecognitionEvent;
+import android.media.soundtrigger.RecognitionStatus;
 import android.media.soundtrigger.SoundModel;
 import android.media.soundtrigger_middleware.ISoundTriggerCallback;
 import android.media.soundtrigger_middleware.ISoundTriggerModule;
@@ -34,6 +35,7 @@
 import android.os.RemoteException;
 import android.util.Log;
 
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.LatencyTracker;
 
 import java.io.PrintWriter;
@@ -358,14 +360,19 @@
              * Starts the latency tracking log for keyphrase hotword invocation.
              * The measurement covers from when the SoundTrigger HAL emits an event to when the
              * {@link android.service.voice.VoiceInteractionSession} system UI view is shown.
+             *
+             * <p>The session is only started if the {@link PhraseRecognitionEvent} has a status of
+             * {@link RecognitionStatus#SUCCESS}
              */
             private void startKeyphraseEventLatencyTracking(PhraseRecognitionEvent event) {
-                String latencyTrackerTag = null;
-                if (event.phraseExtras.length > 0) {
-                    latencyTrackerTag = "KeyphraseId=" + event.phraseExtras[0].id;
+                if (event.common.status != RecognitionStatus.SUCCESS
+                        || ArrayUtils.isEmpty(event.phraseExtras)) {
+                    return;
                 }
+
                 LatencyTracker latencyTracker = LatencyTracker.getInstance(mContext);
-                // To avoid adding cancel to all of the different failure modes between here and
+                String latencyTrackerTag = "KeyphraseId=" + event.phraseExtras[0].id;
+                // To avoid adding cancel to all the different failure modes between here and
                 // showing the system UI, we defensively cancel once.
                 // Either we hit the LatencyTracker timeout of 15 seconds or we defensively cancel
                 // here if any error occurs.
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index b4b8cf9..43fb44c 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -169,6 +169,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.procstats.IProcessStats;
 import com.android.internal.app.procstats.ProcessStats;
+import com.android.internal.app.procstats.StatsEventOutput;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.os.BinderCallsStats.ExportedCallStat;
 import com.android.internal.os.KernelAllocationStats;
@@ -612,12 +613,19 @@
                         }
                     case FrameworkStatsLog.PROC_STATS:
                         synchronized (mProcStatsLock) {
-                            return pullProcStatsLocked(ProcessStats.REPORT_ALL, atomTag, data);
+                            return pullProcStatsLocked(atomTag, data);
                         }
                     case FrameworkStatsLog.PROC_STATS_PKG_PROC:
                         synchronized (mProcStatsLock) {
-                            return pullProcStatsLocked(ProcessStats.REPORT_PKG_PROC_STATS, atomTag,
-                                    data);
+                            return pullProcStatsLocked(atomTag, data);
+                        }
+                    case FrameworkStatsLog.PROCESS_STATE:
+                        synchronized (mProcStatsLock) {
+                            return pullProcessStateLocked(atomTag, data);
+                        }
+                    case FrameworkStatsLog.PROCESS_ASSOCIATION:
+                        synchronized (mProcStatsLock) {
+                            return pullProcessAssociationLocked(atomTag, data);
                         }
                     case FrameworkStatsLog.DISK_IO:
                         synchronized (mDiskIoLock) {
@@ -890,6 +898,8 @@
         registerNumFacesEnrolled();
         registerProcStats();
         registerProcStatsPkgProc();
+        registerProcessState();
+        registerProcessAssociation();
         registerDiskIO();
         registerPowerProfile();
         registerProcessCpuTime();
@@ -2870,59 +2880,138 @@
         );
     }
 
-    private int pullProcStatsLocked(int section, int atomTag, List<StatsEvent> pulledData) {
+    private void registerProcessState() {
+        int tagId = FrameworkStatsLog.PROCESS_STATE;
+        mStatsManager.setPullAtomCallback(
+                tagId,
+                null, // use default PullAtomMetadata values
+                DIRECT_EXECUTOR,
+                mStatsCallbackImpl);
+    }
+
+    private void registerProcessAssociation() {
+        int tagId = FrameworkStatsLog.PROCESS_ASSOCIATION;
+        mStatsManager.setPullAtomCallback(
+                tagId,
+                null, // use default PullAtomMetadata values
+                DIRECT_EXECUTOR,
+                mStatsCallbackImpl);
+    }
+
+    @GuardedBy("mProcStatsLock")
+    private ProcessStats getStatsFromProcessStatsService(int atomTag) {
         IProcessStats processStatsService = getIProcessStatsService();
         if (processStatsService == null) {
-            return StatsManager.PULL_SKIP;
+            return null;
         }
-
         final long token = Binder.clearCallingIdentity();
         try {
             // force procstats to flush & combine old files into one store
-            long lastHighWaterMark = readProcStatsHighWaterMark(section);
-
-            ProtoOutputStream[] protoStreams = new ProtoOutputStream[MAX_PROCSTATS_SHARDS];
-            for (int i = 0; i < protoStreams.length; i++) {
-                protoStreams[i] = new ProtoOutputStream();
-            }
-
+            long lastHighWaterMark = readProcStatsHighWaterMark(atomTag);
             ProcessStats procStats = new ProcessStats(false);
             // Force processStatsService to aggregate all in-storage and in-memory data.
-            long highWaterMark = processStatsService.getCommittedStatsMerged(
-                    lastHighWaterMark, section, true, null, procStats);
-            procStats.dumpAggregatedProtoForStatsd(protoStreams, MAX_PROCSTATS_RAW_SHARD_SIZE);
-
-            for (int i = 0; i < protoStreams.length; i++) {
-                byte[] bytes = protoStreams[i].getBytes(); // cache the value
-                if (bytes.length > 0) {
-                    pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, bytes,
-                            // This is a shard ID, and is specified in the metric definition to be
-                            // a dimension. This will result in statsd using RANDOM_ONE_SAMPLE to
-                            // keep all the shards, as it thinks each shard is a different dimension
-                            // of data.
-                            i));
-                }
-            }
-
-            new File(mBaseDir.getAbsolutePath() + "/" + section + "_" + lastHighWaterMark)
+            long highWaterMark =
+                    processStatsService.getCommittedStatsMerged(
+                            lastHighWaterMark,
+                            ProcessStats.REPORT_ALL, // ignored since committedStats below is null.
+                            true,
+                            null, // committedStats
+                            procStats);
+            new File(
+                            mBaseDir.getAbsolutePath()
+                                    + "/"
+                                    + highWaterMarkFilePrefix(atomTag)
+                                    + "_"
+                                    + lastHighWaterMark)
                     .delete();
-            new File(mBaseDir.getAbsolutePath() + "/" + section + "_" + highWaterMark)
+            new File(
+                            mBaseDir.getAbsolutePath()
+                                    + "/"
+                                    + highWaterMarkFilePrefix(atomTag)
+                                    + "_"
+                                    + highWaterMark)
                     .createNewFile();
+            return procStats;
         } catch (RemoteException | IOException e) {
             Slog.e(TAG, "Getting procstats failed: ", e);
-            return StatsManager.PULL_SKIP;
+            return null;
         } finally {
             Binder.restoreCallingIdentity(token);
         }
+    }
+
+    @GuardedBy("mProcStatsLock")
+    private int pullProcStatsLocked(int atomTag, List<StatsEvent> pulledData) {
+        ProcessStats procStats = getStatsFromProcessStatsService(atomTag);
+        if (procStats == null) {
+            return StatsManager.PULL_SKIP;
+        }
+        ProtoOutputStream[] protoStreams = new ProtoOutputStream[MAX_PROCSTATS_SHARDS];
+        for (int i = 0; i < protoStreams.length; i++) {
+            protoStreams[i] = new ProtoOutputStream();
+        }
+        procStats.dumpAggregatedProtoForStatsd(protoStreams, MAX_PROCSTATS_RAW_SHARD_SIZE);
+        for (int i = 0; i < protoStreams.length; i++) {
+            byte[] bytes = protoStreams[i].getBytes(); // cache the value
+            if (bytes.length > 0) {
+                pulledData.add(
+                        FrameworkStatsLog.buildStatsEvent(
+                                atomTag,
+                                bytes,
+                                // This is a shard ID, and is specified in the metric definition to
+                                // be
+                                // a dimension. This will result in statsd using RANDOM_ONE_SAMPLE
+                                // to
+                                // keep all the shards, as it thinks each shard is a different
+                                // dimension
+                                // of data.
+                                i));
+            }
+        }
         return StatsManager.PULL_SUCCESS;
     }
 
+    @GuardedBy("mProcStatsLock")
+    private int pullProcessStateLocked(int atomTag, List<StatsEvent> pulledData) {
+        ProcessStats procStats = getStatsFromProcessStatsService(atomTag);
+        if (procStats == null) {
+            return StatsManager.PULL_SKIP;
+        }
+        procStats.dumpProcessState(atomTag, new StatsEventOutput(pulledData));
+        return StatsManager.PULL_SUCCESS;
+    }
+
+    @GuardedBy("mProcStatsLock")
+    private int pullProcessAssociationLocked(int atomTag, List<StatsEvent> pulledData) {
+        ProcessStats procStats = getStatsFromProcessStatsService(atomTag);
+        if (procStats == null) {
+            return StatsManager.PULL_SKIP;
+        }
+        procStats.dumpProcessAssociation(atomTag, new StatsEventOutput(pulledData));
+        return StatsManager.PULL_SUCCESS;
+    }
+
+    private String highWaterMarkFilePrefix(int atomTag) {
+        // For backward compatibility, use the legacy ProcessStats enum value as the prefix for
+        // PROC_STATS and PROC_STATS_PKG_PROC.
+        if (atomTag == FrameworkStatsLog.PROC_STATS) {
+            return String.valueOf(ProcessStats.REPORT_ALL);
+        }
+        if (atomTag == FrameworkStatsLog.PROC_STATS_PKG_PROC) {
+            return String.valueOf(ProcessStats.REPORT_PKG_PROC_STATS);
+        }
+        return "atom-" + atomTag;
+    }
+
     // read high watermark for section
-    private long readProcStatsHighWaterMark(int section) {
+    private long readProcStatsHighWaterMark(int atomTag) {
         try {
-            File[] files = mBaseDir.listFiles((d, name) -> {
-                return name.toLowerCase().startsWith(String.valueOf(section) + '_');
-            });
+            File[] files =
+                    mBaseDir.listFiles(
+                            (d, name) -> {
+                                return name.toLowerCase()
+                                        .startsWith(highWaterMarkFilePrefix(atomTag) + '_');
+                            });
             if (files == null || files.length == 0) {
                 return 0;
             }
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index ab7292d..6e34293 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -152,6 +152,13 @@
     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2)
     static final long REQUEST_LISTENING_MUST_MATCH_PACKAGE = 172251878L;
 
+    /**
+     * @hide
+     */
+    @ChangeId
+    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
+    static final long REQUEST_LISTENING_OTHER_USER_NOOP = 242194868L;
+
     private final Context mContext;
 
     private final Handler mHandler = new Handler();
@@ -1859,7 +1866,12 @@
 
             // Check current user
             if (userId != currentUser) {
-                throw new IllegalArgumentException("User " + userId + " is not the current user.");
+                if (CompatChanges.isChangeEnabled(REQUEST_LISTENING_OTHER_USER_NOOP, callingUid)) {
+                    return;
+                } else {
+                    throw new IllegalArgumentException(
+                            "User " + userId + " is not the current user.");
+                }
             }
         }
         if (mBar != null) {
diff --git a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
index 4b8a5b7..26f781f 100644
--- a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
+++ b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
@@ -861,7 +861,7 @@
 
         private static void getLetterBoxBounds(WindowState windowState, Region outRegion) {
             final Rect letterboxInsets = windowState.mActivityRecord.getLetterboxInsets();
-            final Rect nonLetterboxRect = windowState.getBounds();
+            final Rect nonLetterboxRect = new Rect(windowState.getBounds());
 
             nonLetterboxRect.inset(letterboxInsets);
             outRegion.set(windowState.getBounds());
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 7489f80..7c9244e 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -696,6 +696,8 @@
             synchronized (mGlobalLock) {
                 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token);
                 if (r != null) {
+                    EventLogTags.writeWmSetRequestedOrientation(requestedOrientation,
+                            r.shortComponentName);
                     r.setRequestedOrientation(requestedOrientation);
                 }
             }
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 9944f12..a8626df 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1487,6 +1487,12 @@
             mLastReportedMultiWindowMode = inPictureInPictureMode;
             ensureActivityConfiguration(0 /* globalChanges */, PRESERVE_WINDOWS,
                     true /* ignoreVisibility */);
+            if (inPictureInPictureMode && findMainWindow() == null) {
+                // Prevent malicious app entering PiP without valid WindowState, which can in turn
+                // result a non-touchable PiP window since the InputConsumer for PiP requires it.
+                EventLog.writeEvent(0x534e4554, "265293293", -1, "");
+                removeImmediately();
+            }
         }
     }
 
@@ -7727,25 +7733,35 @@
 
     /**
      * Returns the requested {@link Configuration.Orientation} for the current activity.
-     *
-     * <p>When The current orientation is set to {@link SCREEN_ORIENTATION_BEHIND} it returns the
-     * requested orientation for the activity below which is the first activity with an explicit
-     * (different from {@link SCREEN_ORIENTATION_UNSET}) orientation which is not {@link
-     * SCREEN_ORIENTATION_BEHIND}.
      */
     @Configuration.Orientation
     @Override
     int getRequestedConfigurationOrientation(boolean forDisplay) {
+        return getRequestedConfigurationOrientation(forDisplay, getOverrideOrientation());
+    }
+
+    /**
+     * Returns the requested {@link Configuration.Orientation} for the requested
+     * {@link ActivityInfo.ScreenOrientation}.
+     *
+     * <p>When the current screen orientation is set to {@link SCREEN_ORIENTATION_BEHIND} it returns
+     * the requested orientation for the activity below which is the first activity with an explicit
+     * (different from {@link SCREEN_ORIENTATION_UNSET}) orientation which is not {@link
+     * SCREEN_ORIENTATION_BEHIND}.
+     */
+    @Configuration.Orientation
+    int getRequestedConfigurationOrientation(boolean forDisplay,
+            @ActivityInfo.ScreenOrientation int requestedOrientation) {
         if (mLetterboxUiController.hasInheritedOrientation()) {
             final RootDisplayArea root = getRootDisplayArea();
             if (forDisplay && root != null && root.isOrientationDifferentFromDisplay()) {
-                return ActivityInfo.reverseOrientation(
+                return reverseConfigurationOrientation(
                         mLetterboxUiController.getInheritedOrientation());
             } else {
                 return mLetterboxUiController.getInheritedOrientation();
             }
         }
-        if (task != null && getOverrideOrientation() == SCREEN_ORIENTATION_BEHIND) {
+        if (task != null && requestedOrientation == SCREEN_ORIENTATION_BEHIND) {
             // We use Task here because we want to be consistent with what happens in
             // multi-window mode where other tasks orientations are ignored.
             final ActivityRecord belowCandidate = task.getActivity(
@@ -7756,7 +7772,23 @@
                 return belowCandidate.getRequestedConfigurationOrientation(forDisplay);
             }
         }
-        return super.getRequestedConfigurationOrientation(forDisplay);
+        return super.getRequestedConfigurationOrientation(forDisplay, requestedOrientation);
+    }
+
+    /**
+     * Returns the reversed configuration orientation.
+     * @hide
+     */
+    @Configuration.Orientation
+    public static int reverseConfigurationOrientation(@Configuration.Orientation int orientation) {
+        switch (orientation) {
+            case ORIENTATION_LANDSCAPE:
+                return ORIENTATION_PORTRAIT;
+            case ORIENTATION_PORTRAIT:
+                return ORIENTATION_LANDSCAPE;
+            default:
+                return orientation;
+        }
     }
 
     /**
@@ -7802,6 +7834,19 @@
         if (mLetterboxUiController.shouldIgnoreRequestedOrientation(requestedOrientation)) {
             return;
         }
+        // This is necessary in order to avoid going into size compat mode when the orientation
+        // change request comes from the app
+        if (mWmService.mLetterboxConfiguration
+                    .isSizeCompatModeDisabledAfterOrientationChangeFromApp()
+                && getRequestedConfigurationOrientation(false, requestedOrientation)
+                    != getRequestedConfigurationOrientation(false /*forDisplay */)) {
+            // Do not change the requested configuration now, because this will be done when setting
+            // the orientation below with the new mCompatDisplayInsets
+            clearSizeCompatModeAttributes();
+        }
+        ProtoLog.v(WM_DEBUG_ORIENTATION,
+                "Setting requested orientation %s for %s",
+                ActivityInfo.screenOrientationToString(requestedOrientation), this);
         setOrientation(requestedOrientation, this);
 
         // Push the new configuration to the requested app in case where it's not pushed, e.g. when
@@ -8008,9 +8053,7 @@
         // The smallest screen width is the short side of screen bounds. Because the bounds
         // and density won't be changed, smallestScreenWidthDp is also fixed.
         overrideConfig.smallestScreenWidthDp = fullConfig.smallestScreenWidthDp;
-        // TODO(b/264276741): Check whether the runtime orietnation request is fixed rather than
-        // the manifest orientation which may be obsolete.
-        if (info.isFixedOrientation()) {
+        if (ActivityInfo.isFixedOrientation(getOverrideOrientation())) {
             // lock rotation too. When in size-compat, onConfigurationChanged will watch for and
             // apply runtime rotation changes.
             overrideConfig.windowConfiguration.setRotation(
@@ -8023,19 +8066,29 @@
                         mDisplayContent, this, mLetterboxBoundsForFixedOrientationAndAspectRatio);
     }
 
-    @VisibleForTesting
-    void clearSizeCompatMode() {
-        final float lastSizeCompatScale = mSizeCompatScale;
+    private void clearSizeCompatModeAttributes() {
         mInSizeCompatModeForBounds = false;
         mSizeCompatScale = 1f;
         mSizeCompatBounds = null;
         mCompatDisplayInsets = null;
+        mLetterboxUiController.clearInheritedCompatDisplayInsets();
+    }
+
+    @VisibleForTesting
+    void clearSizeCompatMode() {
+        final float lastSizeCompatScale = mSizeCompatScale;
+        clearSizeCompatModeAttributes();
         if (mSizeCompatScale != lastSizeCompatScale) {
             forAllWindows(WindowState::updateGlobalScale, false /* traverseTopToBottom */);
         }
-
         // Clear config override in #updateCompatDisplayInsets().
-        onRequestedOverrideConfigurationChanged(EMPTY);
+        final int activityType = getActivityType();
+        final Configuration overrideConfig = getRequestedOverrideConfiguration();
+        overrideConfig.unset();
+        // Keep the activity type which was set when attaching to a task to prevent leaving it
+        // undefined.
+        overrideConfig.windowConfiguration.setActivityType(activityType);
+        onRequestedOverrideConfigurationChanged(overrideConfig);
     }
 
     @Override
@@ -8095,9 +8148,9 @@
         if (isFixedOrientationLetterboxAllowed) {
             resolveFixedOrientationConfiguration(newParentConfiguration);
         }
-
-        if (getCompatDisplayInsets() != null) {
-            resolveSizeCompatModeConfiguration(newParentConfiguration);
+        final CompatDisplayInsets compatDisplayInsets = getCompatDisplayInsets();
+        if (compatDisplayInsets != null) {
+            resolveSizeCompatModeConfiguration(newParentConfiguration, compatDisplayInsets);
         } else if (inMultiWindowMode() && !isFixedOrientationLetterboxAllowed) {
             // We ignore activities' requested orientation in multi-window modes. They may be
             // taken into consideration in resolveFixedOrientationConfiguration call above.
@@ -8114,7 +8167,7 @@
             resolveAspectRatioRestriction(newParentConfiguration);
         }
 
-        if (isFixedOrientationLetterboxAllowed || getCompatDisplayInsets() != null
+        if (isFixedOrientationLetterboxAllowed || compatDisplayInsets != null
                 // In fullscreen, can be letterboxed for aspect ratio.
                 || !inMultiWindowMode()) {
             updateResolvedBoundsPosition(newParentConfiguration);
@@ -8122,7 +8175,7 @@
 
         boolean isIgnoreOrientationRequest = mDisplayContent != null
                 && mDisplayContent.getIgnoreOrientationRequest();
-        if (getCompatDisplayInsets() == null
+        if (compatDisplayInsets == null
                 // for size compat mode set in updateCompatDisplayInsets
                 // Fixed orientation letterboxing is possible on both large screen devices
                 // with ignoreOrientationRequest enabled and on phones in split screen even with
@@ -8169,7 +8222,7 @@
                         info.neverSandboxDisplayApis(sConstrainDisplayApisConfig),
                         info.alwaysSandboxDisplayApis(sConstrainDisplayApisConfig),
                         !matchParentBounds(),
-                        getCompatDisplayInsets() != null,
+                        compatDisplayInsets != null,
                         shouldCreateCompatDisplayInsets());
             }
             resolvedConfig.windowConfiguration.setMaxBounds(mTmpBounds);
@@ -8181,7 +8234,7 @@
     /**
      * @return The orientation to use to understand if reachability is enabled.
      */
-    @ActivityInfo.ScreenOrientation
+    @Configuration.Orientation
     int getOrientationForReachability() {
         return mLetterboxUiController.hasInheritedLetterboxBehavior()
                 ? mLetterboxUiController.getInheritedOrientation()
@@ -8255,6 +8308,10 @@
      * requested in the config or via an ADB command. For more context see {@link
      * LetterboxUiController#getHorizontalPositionMultiplier(Configuration)} and
      * {@link LetterboxUiController#getVerticalPositionMultiplier(Configuration)}
+     * <p>
+     * Note that this is the final step that can change the resolved bounds. After this method
+     * is called, the position of the bounds will be moved to app space as sandboxing if the
+     * activity has a size compat scale.
      */
     private void updateResolvedBoundsPosition(Configuration newParentConfiguration) {
         final Configuration resolvedConfig = getResolvedOverrideConfiguration();
@@ -8316,6 +8373,24 @@
 
         // Since bounds has changed, the configuration needs to be computed accordingly.
         getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration);
+
+        // The position of configuration bounds were calculated in screen space because that is
+        // easier to resolve the relative position in parent container. However, if the activity is
+        // scaled, the position should follow the scale because the configuration will be sent to
+        // the client which is expected to be in a scaled environment.
+        if (mSizeCompatScale != 1f) {
+            final int screenPosX = resolvedBounds.left;
+            final int screenPosY = resolvedBounds.top;
+            final int dx = (int) (screenPosX / mSizeCompatScale + 0.5f) - screenPosX;
+            final int dy = (int) (screenPosY / mSizeCompatScale + 0.5f) - screenPosY;
+            offsetBounds(resolvedConfig, dx, dy);
+        }
+    }
+
+    @NonNull Rect getScreenResolvedBounds() {
+        final Configuration resolvedConfig = getResolvedOverrideConfiguration();
+        final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();
+        return mSizeCompatBounds != null ? mSizeCompatBounds : resolvedBounds;
     }
 
     void recomputeConfiguration() {
@@ -8517,7 +8592,7 @@
         resolvedBounds.set(containingBounds);
 
         final float letterboxAspectRatioOverride =
-                mLetterboxUiController.getFixedOrientationLetterboxAspectRatio();
+                mLetterboxUiController.getFixedOrientationLetterboxAspectRatio(newParentConfig);
         final float desiredAspectRatio =
                 letterboxAspectRatioOverride > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO
                         ? letterboxAspectRatioOverride : computeAspectRatio(parentBounds);
@@ -8577,7 +8652,8 @@
      * Resolves consistent screen configuration for orientation and rotation changes without
      * inheriting the parent bounds.
      */
-    private void resolveSizeCompatModeConfiguration(Configuration newParentConfiguration) {
+    private void resolveSizeCompatModeConfiguration(Configuration newParentConfiguration,
+            @NonNull CompatDisplayInsets compatDisplayInsets) {
         final Configuration resolvedConfig = getResolvedOverrideConfiguration();
         final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();
 
@@ -8598,13 +8674,13 @@
                 ? requestedOrientation
                 // We should use the original orientation of the activity when possible to avoid
                 // forcing the activity in the opposite orientation.
-                : getCompatDisplayInsets().mOriginalRequestedOrientation != ORIENTATION_UNDEFINED
-                        ? getCompatDisplayInsets().mOriginalRequestedOrientation
+                : compatDisplayInsets.mOriginalRequestedOrientation != ORIENTATION_UNDEFINED
+                        ? compatDisplayInsets.mOriginalRequestedOrientation
                         : newParentConfiguration.orientation;
         int rotation = newParentConfiguration.windowConfiguration.getRotation();
         final boolean isFixedToUserRotation = mDisplayContent == null
                 || mDisplayContent.getDisplayRotation().isFixedToUserRotation();
-        if (!isFixedToUserRotation && !getCompatDisplayInsets().mIsFloating) {
+        if (!isFixedToUserRotation && !compatDisplayInsets.mIsFloating) {
             // Use parent rotation because the original display can be rotated.
             resolvedConfig.windowConfiguration.setRotation(rotation);
         } else {
@@ -8620,11 +8696,11 @@
         // rely on them to contain the original and unchanging width and height of the app.
         final Rect containingAppBounds = new Rect();
         final Rect containingBounds = mTmpBounds;
-        getCompatDisplayInsets().getContainerBounds(containingAppBounds, containingBounds, rotation,
+        compatDisplayInsets.getContainerBounds(containingAppBounds, containingBounds, rotation,
                 orientation, orientationRequested, isFixedToUserRotation);
         resolvedBounds.set(containingBounds);
         // The size of floating task is fixed (only swap), so the aspect ratio is already correct.
-        if (!getCompatDisplayInsets().mIsFloating) {
+        if (!compatDisplayInsets.mIsFloating) {
             mIsAspectRatioApplied =
                     applyAspectRatio(resolvedBounds, containingAppBounds, containingBounds);
         }
@@ -8633,7 +8709,7 @@
         // are calculated in compat container space. The actual position on screen will be applied
         // later, so the calculation is simpler that doesn't need to involve offset from parent.
         getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
-                getCompatDisplayInsets());
+                compatDisplayInsets);
         // Use current screen layout as source because the size of app is independent to parent.
         resolvedConfig.screenLayout = TaskFragment.computeScreenLayoutOverride(
                 getConfiguration().screenLayout, resolvedConfig.screenWidthDp,
@@ -8892,6 +8968,7 @@
 
         final boolean wasInPictureInPicture = inPinnedWindowingMode();
         final DisplayContent display = mDisplayContent;
+        final int activityType = getActivityType();
         if (wasInPictureInPicture && attachedToProcess() && display != null) {
             // If the PIP activity is changing to fullscreen with display orientation change, the
             // fixed rotation will take effect that requires to send fixed rotation adjustments
@@ -8916,6 +8993,11 @@
         } else {
             super.onConfigurationChanged(newParentConfig);
         }
+        if (activityType != ACTIVITY_TYPE_UNDEFINED
+                && activityType != getActivityType()) {
+            Slog.w(TAG, "Can't change activity type once set: " + this
+                    + " activityType=" + activityTypeToString(getActivityType()));
+        }
 
         // Configuration's equality doesn't consider seq so if only seq number changes in resolved
         // override configuration. Therefore ConfigurationContainer doesn't change merged override
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index 4663662..39106f6 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -98,6 +98,8 @@
     /** Whether an {@link ActivityStarter} is currently executing (starting an Activity). */
     private boolean mInExecution = false;
 
+    private final BackgroundActivityStartController mBalController;
+
     /**
      * TODO(b/64750076): Capture information necessary for dump and
      * {@link #postStartActivityProcessingForLastStarter} rather than keeping the entire object
@@ -120,6 +122,7 @@
         mFactory.setController(this);
         mPendingRemoteAnimationRegistry = new PendingRemoteAnimationRegistry(service.mGlobalLock,
                 service.mH);
+        mBalController = new BackgroundActivityStartController(mService, mSupervisor);
     }
 
     /**
@@ -670,4 +673,8 @@
             pw.println("(nothing)");
         }
     }
+
+    BackgroundActivityStartController getBackgroundActivityLaunchController() {
+        return mBalController;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index aad89b4..d1a5ead 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -16,7 +16,6 @@
 
 package com.android.server.wm;
 
-import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
 import static android.app.Activity.RESULT_CANCELED;
 import static android.app.ActivityManager.START_ABORTED;
 import static android.app.ActivityManager.START_CANCELED;
@@ -52,7 +51,6 @@
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
 import static android.content.pm.ActivityInfo.launchModeToString;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.os.Process.INVALID_UID;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.TRANSIT_NONE;
@@ -63,7 +61,6 @@
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
 import static com.android.server.wm.ActivityRecord.State.RESUMED;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ACTIVITY_STARTS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_USER_LEAVING;
@@ -74,11 +71,11 @@
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.ActivityTaskManagerService.ANIMATE;
-import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_ALLOW;
-import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_FG_ONLY;
 import static com.android.server.wm.ActivityTaskSupervisor.DEFER_RESUME;
 import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP;
 import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
+import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_DEFAULT;
+import static com.android.server.wm.BackgroundActivityStartController.BAL_BLOCK;
 import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS;
 import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_DISPLAY;
 import static com.android.server.wm.Task.REPARENT_MOVE_ROOT_TASK_TO_FRONT;
@@ -99,7 +96,6 @@
 import android.app.WindowConfiguration;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledSince;
-import android.content.ComponentName;
 import android.content.IIntentSender;
 import android.content.Intent;
 import android.content.IntentSender;
@@ -115,15 +111,12 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
-import android.os.Process;
 import android.os.RemoteException;
 import android.os.Trace;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.service.voice.IVoiceInteractionSession;
 import android.text.TextUtils;
-import android.util.ArraySet;
-import android.util.DebugUtils;
 import android.util.Pools.SynchronizedPool;
 import android.util.Slog;
 import android.window.RemoteTransition;
@@ -139,6 +132,7 @@
 import com.android.server.statusbar.StatusBarManagerInternal;
 import com.android.server.uri.NeededUriGrants;
 import com.android.server.wm.ActivityMetricsLogger.LaunchingState;
+import com.android.server.wm.BackgroundActivityStartController.BalCode;
 import com.android.server.wm.LaunchParamsController.LaunchParams;
 import com.android.server.wm.TaskFragment.EmbeddingCheckResult;
 
@@ -180,9 +174,10 @@
     private int mCallingUid;
     private ActivityOptions mOptions;
 
-    // If it is true, background activity can only be started in an existing task that contains
+    // If it is BAL_BLOCK, background activity can only be started in an existing task that contains
     // an activity with same uid, or if activity starts are enabled in developer options.
-    private boolean mRestrictedBgActivity;
+    @BalCode
+    private int mBalCode;
 
     private int mLaunchMode;
     private boolean mLaunchTaskBehind;
@@ -264,8 +259,6 @@
 
         /**
          * Generates an {@link ActivityStarter} that is ready to handle a new start request.
-         * @param controller The {@link ActivityStartController} which the starter who will own
-         *                   this instance.
          * @return an {@link ActivityStarter}
          */
         ActivityStarter obtain();
@@ -600,7 +593,7 @@
         mIntent = starter.mIntent;
         mCallingUid = starter.mCallingUid;
         mOptions = starter.mOptions;
-        mRestrictedBgActivity = starter.mRestrictedBgActivity;
+        mBalCode = starter.mBalCode;
 
         mLaunchTaskBehind = starter.mLaunchTaskBehind;
         mLaunchFlags = starter.mLaunchFlags;
@@ -1031,15 +1024,25 @@
         ActivityOptions checkedOptions = options != null
                 ? options.getOptions(intent, aInfo, callerApp, mSupervisor) : null;
 
-        boolean restrictedBgActivity = false;
+        @BalCode int balCode = BAL_ALLOW_DEFAULT;
         if (!abort) {
             try {
                 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER,
                         "shouldAbortBackgroundActivityStart");
-                restrictedBgActivity = shouldAbortBackgroundActivityStart(callingUid,
-                        callingPid, callingPackage, realCallingUid, realCallingPid, callerApp,
-                        request.originatingPendingIntent, request.allowBackgroundActivityStart,
-                        intent, checkedOptions);
+                BackgroundActivityStartController balController =
+                        mController.getBackgroundActivityLaunchController();
+                balCode =
+                        balController.checkBackgroundActivityStart(
+                                callingUid,
+                                callingPid,
+                                callingPackage,
+                                realCallingUid,
+                                realCallingPid,
+                                callerApp,
+                                request.originatingPendingIntent,
+                                request.allowBackgroundActivityStart,
+                                intent,
+                                checkedOptions);
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
             }
@@ -1217,13 +1220,13 @@
         WindowProcessController homeProcess = mService.mHomeProcess;
         boolean isHomeProcess = homeProcess != null
                 && aInfo.applicationInfo.uid == homeProcess.mUid;
-        if (!restrictedBgActivity && !isHomeProcess) {
+        if (balCode != BAL_BLOCK && !isHomeProcess) {
             mService.resumeAppSwitches();
         }
 
         mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
                 request.voiceInteractor, startFlags, true /* doResume */, checkedOptions,
-                inTask, inTaskFragment, restrictedBgActivity, intentGrants);
+                inTask, inTaskFragment, balCode, intentGrants);
 
         if (request.outActivity != null) {
             request.outActivity[0] = mLastStartActivityRecord;
@@ -1273,282 +1276,6 @@
         mController.onExecutionStarted();
     }
 
-    private boolean isHomeApp(int uid, @Nullable String packageName) {
-        if (mService.mHomeProcess != null) {
-            // Fast check
-            return uid == mService.mHomeProcess.mUid;
-        }
-        if (packageName == null) {
-            return false;
-        }
-        ComponentName activity =
-                mService.getPackageManagerInternalLocked().getDefaultHomeActivity(
-                        UserHandle.getUserId(uid));
-        return activity != null && packageName.equals(activity.getPackageName());
-    }
-
-    boolean shouldAbortBackgroundActivityStart(int callingUid, int callingPid,
-            final String callingPackage, int realCallingUid, int realCallingPid,
-            WindowProcessController callerApp, PendingIntentRecord originatingPendingIntent,
-            boolean allowBackgroundActivityStart, Intent intent, ActivityOptions checkedOptions) {
-        // don't abort for the most important UIDs
-        final int callingAppId = UserHandle.getAppId(callingUid);
-        final boolean useCallingUidState =
-                originatingPendingIntent == null || checkedOptions == null
-                        || !checkedOptions.getIgnorePendingIntentCreatorForegroundState();
-        if (useCallingUidState) {
-            if (callingUid == Process.ROOT_UID || callingAppId == Process.SYSTEM_UID
-                    || callingAppId == Process.NFC_UID) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(TAG,
-                            "Activity start allowed for important callingUid (" + callingUid + ")");
-                }
-                return false;
-            }
-
-            // Always allow home application to start activities.
-            if (isHomeApp(callingUid, callingPackage)) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(TAG,
-                            "Activity start allowed for home app callingUid (" + callingUid + ")");
-                }
-                return false;
-            }
-
-            // IME should always be allowed to start activity, like IME settings.
-            final WindowState imeWindow = mRootWindowContainer.getCurrentInputMethodWindow();
-            if (imeWindow != null && callingAppId == imeWindow.mOwnerUid) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(TAG, "Activity start allowed for active ime (" + callingUid + ")");
-                }
-                return false;
-            }
-        }
-
-        // This is used to block background activity launch even if the app is still
-        // visible to user after user clicking home button.
-        final int appSwitchState = mService.getBalAppSwitchesState();
-
-        // don't abort if the callingUid has a visible window or is a persistent system process
-        final int callingUidProcState = mService.mActiveUids.getUidState(callingUid);
-        final boolean callingUidHasAnyVisibleWindow = mService.hasActiveVisibleWindow(callingUid);
-        final boolean isCallingUidForeground = callingUidHasAnyVisibleWindow
-                || callingUidProcState == ActivityManager.PROCESS_STATE_TOP
-                || callingUidProcState == ActivityManager.PROCESS_STATE_BOUND_TOP;
-        final boolean isCallingUidPersistentSystemProcess =
-                callingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI;
-
-        // Normal apps with visible app window will be allowed to start activity if app switching
-        // is allowed, or apps like live wallpaper with non app visible window will be allowed.
-        final boolean appSwitchAllowedOrFg =
-                appSwitchState == APP_SWITCH_ALLOW || appSwitchState == APP_SWITCH_FG_ONLY;
-        final boolean allowCallingUidStartActivity =
-                ((appSwitchAllowedOrFg || mService.mActiveUids.hasNonAppVisibleWindow(callingUid))
-                && callingUidHasAnyVisibleWindow)
-                || isCallingUidPersistentSystemProcess;
-        if (useCallingUidState && allowCallingUidStartActivity) {
-            if (DEBUG_ACTIVITY_STARTS) {
-                Slog.d(TAG, "Activity start allowed: callingUidHasAnyVisibleWindow = " + callingUid
-                        + ", isCallingUidPersistentSystemProcess = "
-                        + isCallingUidPersistentSystemProcess);
-            }
-            return false;
-        }
-        // take realCallingUid into consideration
-        final int realCallingUidProcState = (callingUid == realCallingUid)
-                ? callingUidProcState
-                : mService.mActiveUids.getUidState(realCallingUid);
-        final boolean realCallingUidHasAnyVisibleWindow = (callingUid == realCallingUid)
-                ? callingUidHasAnyVisibleWindow
-                : mService.hasActiveVisibleWindow(realCallingUid);
-        final boolean isRealCallingUidForeground = (callingUid == realCallingUid)
-                ? isCallingUidForeground
-                : realCallingUidHasAnyVisibleWindow
-                        || realCallingUidProcState == ActivityManager.PROCESS_STATE_TOP;
-        final int realCallingAppId = UserHandle.getAppId(realCallingUid);
-        final boolean isRealCallingUidPersistentSystemProcess = (callingUid == realCallingUid)
-                ? isCallingUidPersistentSystemProcess
-                : (realCallingAppId == Process.SYSTEM_UID)
-                        || realCallingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI;
-
-        // In the case of an SDK sandbox calling uid, check if the corresponding app uid has a
-        // visible window.
-        if (Process.isSdkSandboxUid(realCallingUid)) {
-            int realCallingSdkSandboxUidToAppUid = Process.getAppUidForSdkSandboxUid(
-                    UserHandle.getAppId(realCallingUid));
-
-            if (mService.hasActiveVisibleWindow(realCallingSdkSandboxUidToAppUid)) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(TAG, "Activity start allowed: uid in SDK sandbox ("
-                            + realCallingUid + ") has visible (non-toast) window.");
-                }
-                return false;
-            }
-        }
-
-        // Legacy behavior allows to use caller foreground state to bypass BAL restriction.
-        final boolean balAllowedByPiSender =
-                PendingIntentRecord.isPendingIntentBalAllowedByCaller(checkedOptions);
-
-        if (balAllowedByPiSender && realCallingUid != callingUid) {
-            final boolean useCallerPermission =
-                    PendingIntentRecord.isPendingIntentBalAllowedByPermission(checkedOptions);
-            if (useCallerPermission && ActivityManager.checkComponentPermission(
-                    android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND,
-                    realCallingUid, -1, true)
-                    == PackageManager.PERMISSION_GRANTED) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(TAG, "Activity start allowed: realCallingUid (" + realCallingUid
-                            + ") has BAL permission.");
-                }
-                return false;
-            }
-
-            // don't abort if the realCallingUid has a visible window
-            // TODO(b/171459802): We should check appSwitchAllowed also
-            if (realCallingUidHasAnyVisibleWindow) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(TAG, "Activity start allowed: realCallingUid (" + realCallingUid
-                            + ") has visible (non-toast) window");
-                }
-                return false;
-            }
-            // if the realCallingUid is a persistent system process, abort if the IntentSender
-            // wasn't allowed to start an activity
-            if (isRealCallingUidPersistentSystemProcess && allowBackgroundActivityStart) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(TAG, "Activity start allowed: realCallingUid (" + realCallingUid
-                            + ") is persistent system process AND intent sender allowed "
-                            + "(allowBackgroundActivityStart = true)");
-                }
-                return false;
-            }
-            // don't abort if the realCallingUid is an associated companion app
-            if (mService.isAssociatedCompanionApp(UserHandle.getUserId(realCallingUid),
-                    realCallingUid)) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(TAG, "Activity start allowed: realCallingUid (" + realCallingUid
-                            + ") is companion app");
-                }
-                return false;
-            }
-        }
-        if (useCallingUidState) {
-            // don't abort if the callingUid has START_ACTIVITIES_FROM_BACKGROUND permission
-            if (mService.checkPermission(
-                    START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid)
-                    == PERMISSION_GRANTED) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(TAG,
-                            "Background activity start allowed: START_ACTIVITIES_FROM_BACKGROUND "
-                                    + "permission granted for uid "
-                                    + callingUid);
-                }
-                return false;
-            }
-            // don't abort if the caller has the same uid as the recents component
-            if (mSupervisor.mRecentTasks.isCallerRecents(callingUid)) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(TAG, "Background activity start allowed: callingUid (" + callingUid
-                            + ") is recents");
-                }
-                return false;
-            }
-            // don't abort if the callingUid is the device owner
-            if (mService.isDeviceOwner(callingUid)) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(TAG, "Background activity start allowed: callingUid (" + callingUid
-                            + ") is device owner");
-                }
-                return false;
-            }
-            // don't abort if the callingUid has companion device
-            final int callingUserId = UserHandle.getUserId(callingUid);
-            if (mService.isAssociatedCompanionApp(callingUserId,
-                    callingUid)) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(TAG, "Background activity start allowed: callingUid (" + callingUid
-                            + ") is companion app");
-                }
-                return false;
-            }
-            // don't abort if the callingUid has SYSTEM_ALERT_WINDOW permission
-            if (mService.hasSystemAlertWindowPermission(callingUid,
-                    callingPid, callingPackage)) {
-                Slog.w(TAG, "Background activity start for " + callingPackage
-                        + " allowed because SYSTEM_ALERT_WINDOW permission is granted.");
-                return false;
-            }
-        }
-        // If we don't have callerApp at this point, no caller was provided to startActivity().
-        // That's the case for PendingIntent-based starts, since the creator's process might not be
-        // up and alive. If that's the case, we retrieve the WindowProcessController for the send()
-        // caller if caller allows, so that we can make the decision based on its state.
-        int callerAppUid = callingUid;
-        if (callerApp == null && balAllowedByPiSender) {
-            callerApp = mService.getProcessController(realCallingPid, realCallingUid);
-            callerAppUid = realCallingUid;
-        }
-        // don't abort if the callerApp or other processes of that uid are allowed in any way
-        if (callerApp != null && useCallingUidState) {
-            // first check the original calling process
-            if (callerApp.areBackgroundActivityStartsAllowed(appSwitchState)) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(TAG, "Background activity start allowed: callerApp process (pid = "
-                            + callerApp.getPid() + ", uid = " + callerAppUid + ") is allowed");
-                }
-                return false;
-            }
-            // only if that one wasn't allowed, check the other ones
-            final ArraySet<WindowProcessController> uidProcesses =
-                    mService.mProcessMap.getProcesses(callerAppUid);
-            if (uidProcesses != null) {
-                for (int i = uidProcesses.size() - 1; i >= 0; i--) {
-                    final WindowProcessController proc = uidProcesses.valueAt(i);
-                    if (proc != callerApp
-                            && proc.areBackgroundActivityStartsAllowed(appSwitchState)) {
-                        if (DEBUG_ACTIVITY_STARTS) {
-                            Slog.d(TAG,
-                                    "Background activity start allowed: process " + proc.getPid()
-                                            + " from uid " + callerAppUid + " is allowed");
-                        }
-                        return false;
-                    }
-                }
-            }
-        }
-        // anything that has fallen through would currently be aborted
-        Slog.w(TAG, "Background activity start [callingPackage: " + callingPackage
-                + "; callingUid: " + callingUid
-                + "; appSwitchState: " + appSwitchState
-                + "; isCallingUidForeground: " + isCallingUidForeground
-                + "; callingUidHasAnyVisibleWindow: " + callingUidHasAnyVisibleWindow
-                + "; callingUidProcState: " + DebugUtils.valueToString(ActivityManager.class,
-                "PROCESS_STATE_", callingUidProcState)
-                + "; isCallingUidPersistentSystemProcess: " + isCallingUidPersistentSystemProcess
-                + "; realCallingUid: " + realCallingUid
-                + "; isRealCallingUidForeground: " + isRealCallingUidForeground
-                + "; realCallingUidHasAnyVisibleWindow: " + realCallingUidHasAnyVisibleWindow
-                + "; realCallingUidProcState: " + DebugUtils.valueToString(ActivityManager.class,
-                "PROCESS_STATE_", realCallingUidProcState)
-                + "; isRealCallingUidPersistentSystemProcess: "
-                + isRealCallingUidPersistentSystemProcess
-                + "; originatingPendingIntent: " + originatingPendingIntent
-                + "; allowBackgroundActivityStart: " + allowBackgroundActivityStart
-                + "; intent: " + intent
-                + "; callerApp: " + callerApp
-                + "; inVisibleTask: " + (callerApp != null && callerApp.hasActivityInVisibleTask())
-                + "]");
-        // log aborted activity start to TRON
-        if (mService.isActivityStartsLoggingEnabled()) {
-            mSupervisor.getActivityMetricsLogger().logAbortedBgActivityStart(intent, callerApp,
-                    callingUid, callingPackage, callingUidProcState, callingUidHasAnyVisibleWindow,
-                    realCallingUid, realCallingUidProcState, realCallingUidHasAnyVisibleWindow,
-                    (originatingPendingIntent != null));
-        }
-        return true;
-    }
-
     /**
      * Creates a launch intent for the given auxiliary resolution data.
      */
@@ -1649,7 +1376,7 @@
     private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
             int startFlags, boolean doResume, ActivityOptions options, Task inTask,
-            TaskFragment inTaskFragment, boolean restrictedBgActivity,
+            TaskFragment inTaskFragment, @BalCode int balCode,
             NeededUriGrants intentGrants) {
         int result = START_CANCELED;
         final Task startedActivityRootTask;
@@ -1669,7 +1396,7 @@
             try {
                 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner");
                 result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
-                        startFlags, doResume, options, inTask, inTaskFragment, restrictedBgActivity,
+                        startFlags, doResume, options, inTask, inTaskFragment, balCode,
                         intentGrants);
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
@@ -1816,10 +1543,10 @@
     int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
             int startFlags, boolean doResume, ActivityOptions options, Task inTask,
-            TaskFragment inTaskFragment, boolean restrictedBgActivity,
+            TaskFragment inTaskFragment, @BalCode int balCode,
             NeededUriGrants intentGrants) {
         setInitialState(r, options, inTask, inTaskFragment, doResume, startFlags, sourceRecord,
-                voiceSession, voiceInteractor, restrictedBgActivity);
+                voiceSession, voiceInteractor, balCode);
 
         computeLaunchingTaskFlags();
         mIntent.setFlags(mLaunchFlags);
@@ -2055,7 +1782,8 @@
                 || !targetTask.isUidPresent(mCallingUid)
                 || (LAUNCH_SINGLE_INSTANCE == mLaunchMode && targetTask.inPinnedWindowingMode()));
 
-        if (mRestrictedBgActivity && blockBalInTask && handleBackgroundActivityAbort(r)) {
+        if (mBalCode == BAL_BLOCK && blockBalInTask
+                && handleBackgroundActivityAbort(r)) {
             Slog.e(TAG, "Abort background activity starts from " + mCallingUid);
             return START_ABORTED;
         }
@@ -2452,7 +2180,7 @@
         mIntent = null;
         mCallingUid = -1;
         mOptions = null;
-        mRestrictedBgActivity = false;
+        mBalCode = BAL_ALLOW_DEFAULT;
 
         mLaunchTaskBehind = false;
         mLaunchFlags = 0;
@@ -2497,7 +2225,7 @@
     private void setInitialState(ActivityRecord r, ActivityOptions options, Task inTask,
             TaskFragment inTaskFragment, boolean doResume, int startFlags,
             ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession,
-            IVoiceInteractor voiceInteractor, boolean restrictedBgActivity) {
+            IVoiceInteractor voiceInteractor, @BalCode int balCode) {
         reset(false /* clearRequest */);
 
         mStartActivity = r;
@@ -2508,7 +2236,7 @@
         mSourceRootTask = mSourceRecord != null ? mSourceRecord.getRootTask() : null;
         mVoiceSession = voiceSession;
         mVoiceInteractor = voiceInteractor;
-        mRestrictedBgActivity = restrictedBgActivity;
+        mBalCode = balCode;
 
         mLaunchParams.reset();
 
@@ -2645,7 +2373,7 @@
 
         mNoAnimation = (mLaunchFlags & FLAG_ACTIVITY_NO_ANIMATION) != 0;
 
-        if (mRestrictedBgActivity && !mService.isBackgroundActivityStartsEnabled()) {
+        if (mBalCode == BAL_BLOCK && !mService.isBackgroundActivityStartsEnabled()) {
             mAvoidMoveToFront = true;
             mDoResume = false;
         }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 491e58b..f6e92a6 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1486,7 +1486,7 @@
         a.persistableMode = ActivityInfo.PERSIST_NEVER;
         a.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
         a.colorMode = ActivityInfo.COLOR_MODE_DEFAULT;
-        a.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS | ActivityInfo.FLAG_NO_HISTORY;
+        a.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
         a.resizeMode = RESIZE_MODE_UNRESIZEABLE;
         a.configChanges = 0xffffffff;
 
@@ -2182,10 +2182,19 @@
         if (appThread != null) {
             callerApp = getProcessController(appThread);
         }
-        final ActivityStarter starter = getActivityStartController().obtainStarter(
-                null /* intent */, "moveTaskToFront");
-        if (starter.shouldAbortBackgroundActivityStart(callingUid, callingPid, callingPackage, -1,
-                -1, callerApp, null, false, null, null)) {
+        final BackgroundActivityStartController balController =
+                getActivityStartController().getBackgroundActivityLaunchController();
+        if (balController.shouldAbortBackgroundActivityStart(
+                callingUid,
+                callingPid,
+                callingPackage,
+                -1,
+                -1,
+                callerApp,
+                null,
+                false,
+                null,
+                null)) {
             if (!isBackgroundActivityStartsEnabled()) {
                 return;
             }
diff --git a/services/core/java/com/android/server/wm/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java
index 0bfc48b..b160af6a 100644
--- a/services/core/java/com/android/server/wm/AppTaskImpl.java
+++ b/services/core/java/com/android/server/wm/AppTaskImpl.java
@@ -119,10 +119,20 @@
                 if (appThread != null) {
                     callerApp = mService.getProcessController(appThread);
                 }
-                final ActivityStarter starter = mService.getActivityStartController().obtainStarter(
-                        null /* intent */, "moveToFront");
-                if (starter.shouldAbortBackgroundActivityStart(callingUid, callingPid,
-                        callingPackage, -1, -1, callerApp, null, false, null, null)) {
+                final BackgroundActivityStartController balController =
+                        mService.getActivityStartController()
+                                .getBackgroundActivityLaunchController();
+                if (balController.shouldAbortBackgroundActivityStart(
+                        callingUid,
+                        callingPid,
+                        callingPackage,
+                        -1,
+                        -1,
+                        callerApp,
+                        null,
+                        false,
+                        null,
+                        null)) {
                     if (!mService.isBackgroundActivityStartsEnabled()) {
                         return;
                     }
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
new file mode 100644
index 0000000..c7e44b3
--- /dev/null
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -0,0 +1,483 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ACTIVITY_STARTS;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_ALLOW;
+import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_FG_ONLY;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Process;
+import android.os.UserHandle;
+import android.util.ArraySet;
+import android.util.DebugUtils;
+import android.util.Slog;
+
+import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.am.PendingIntentRecord;
+
+import java.lang.annotation.Retention;
+
+/**
+ * Helper class to check permissions for starting Activities.
+ *
+ * <p>This class collects all the logic to prevent malicious attempts to start activities.
+ */
+public class BackgroundActivityStartController {
+
+    private static final String TAG =
+            TAG_WITH_CLASS_NAME ? "BackgroundActivityStartController" : TAG_ATM;
+
+    private final ActivityTaskManagerService mService;
+    private final ActivityTaskSupervisor mSupervisor;
+
+    // TODO(b/263368846) Rename when ASM logic is moved in
+    @Retention(SOURCE)
+    @IntDef({BAL_BLOCK,
+            BAL_ALLOW_DEFAULT,
+            BAL_ALLOW_ALLOWLISTED_UID,
+            BAL_ALLOW_ALLOWLISTED_COMPONENT,
+            BAL_ALLOW_VISIBLE_WINDOW,
+            BAL_ALLOW_PENDING_INTENT,
+            BAL_ALLOW_BAL_PERMISSION,
+            BAL_ALLOW_SAW_PERMISSION,
+            BAL_ALLOW_GRACE_PERIOD,
+            BAL_ALLOW_FOREGROUND,
+            BAL_ALLOW_SDK_SANDBOX
+    })
+    public @interface BalCode {}
+
+    static final int BAL_BLOCK = 0;
+
+    static final int BAL_ALLOW_DEFAULT = 1;
+
+    // Following codes are in order of precedence
+
+    /** Important UIDs which should be always allowed to launch activities */
+    static final int BAL_ALLOW_ALLOWLISTED_UID = 2;
+
+    /** Apps that fulfill a certain role that can can always launch new tasks */
+    static final int BAL_ALLOW_ALLOWLISTED_COMPONENT = 3;
+
+    /** Apps which currently have a visible window */
+    static final int BAL_ALLOW_VISIBLE_WINDOW = 4;
+
+    /** Allowed due to the PendingIntent sender */
+    static final int BAL_ALLOW_PENDING_INTENT = 5;
+
+    /** App has START_ACTIVITIES_FROM_BACKGROUND permission or BAL instrumentation privileges
+     * granted to it */
+    static final int BAL_ALLOW_BAL_PERMISSION = 6;
+
+    /** Process has SYSTEM_ALERT_WINDOW permission granted to it */
+    static final int BAL_ALLOW_SAW_PERMISSION = 7;
+
+    /** App is in grace period after an activity was started or finished */
+    static final int BAL_ALLOW_GRACE_PERIOD = 8;
+
+    /** App is in a foreground task or bound to a foreground service (but not itself visible) */
+    static final int BAL_ALLOW_FOREGROUND = 9;
+
+    /** Process belongs to a SDK sandbox */
+    static final int BAL_ALLOW_SDK_SANDBOX = 10;
+
+    BackgroundActivityStartController(
+            final ActivityTaskManagerService service, final ActivityTaskSupervisor supervisor) {
+        mService = service;
+        mSupervisor = supervisor;
+    }
+
+    private boolean isHomeApp(int uid, @Nullable String packageName) {
+        if (mService.mHomeProcess != null) {
+            // Fast check
+            return uid == mService.mHomeProcess.mUid;
+        }
+        if (packageName == null) {
+            return false;
+        }
+        ComponentName activity =
+                mService.getPackageManagerInternalLocked()
+                        .getDefaultHomeActivity(UserHandle.getUserId(uid));
+        return activity != null && packageName.equals(activity.getPackageName());
+    }
+
+    boolean shouldAbortBackgroundActivityStart(
+            int callingUid,
+            int callingPid,
+            final String callingPackage,
+            int realCallingUid,
+            int realCallingPid,
+            WindowProcessController callerApp,
+            PendingIntentRecord originatingPendingIntent,
+            boolean allowBackgroundActivityStart,
+            Intent intent,
+            ActivityOptions checkedOptions) {
+        return checkBackgroundActivityStart(callingUid, callingPid, callingPackage,
+                realCallingUid, realCallingPid, callerApp, originatingPendingIntent,
+                allowBackgroundActivityStart, intent, checkedOptions) == BAL_BLOCK;
+    }
+
+    /**
+     * @return A code denoting which BAL rule allows an activity to be started,
+     * or {@link BAL_BLOCK} if the launch should be blocked
+     */
+    @BalCode
+    int checkBackgroundActivityStart(
+            int callingUid,
+            int callingPid,
+            final String callingPackage,
+            int realCallingUid,
+            int realCallingPid,
+            WindowProcessController callerApp,
+            PendingIntentRecord originatingPendingIntent,
+            boolean allowBackgroundActivityStart,
+            Intent intent,
+            ActivityOptions checkedOptions) {
+        // don't abort for the most important UIDs
+        final int callingAppId = UserHandle.getAppId(callingUid);
+        final boolean useCallingUidState =
+                originatingPendingIntent == null
+                        || checkedOptions == null
+                        || !checkedOptions.getIgnorePendingIntentCreatorForegroundState();
+        if (useCallingUidState) {
+            if (callingUid == Process.ROOT_UID
+                    || callingAppId == Process.SYSTEM_UID
+                    || callingAppId == Process.NFC_UID) {
+                return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_UID, /*background*/ false,
+                        callingUid, realCallingUid, intent, "Important callingUid");
+            }
+
+            // Always allow home application to start activities.
+            if (isHomeApp(callingUid, callingPackage)) {
+                return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT,
+                        /*background*/ false, callingUid, realCallingUid, intent,
+                        "Home app");
+            }
+
+            // IME should always be allowed to start activity, like IME settings.
+            final WindowState imeWindow =
+                    mService.mRootWindowContainer.getCurrentInputMethodWindow();
+            if (imeWindow != null && callingAppId == imeWindow.mOwnerUid) {
+                return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT,
+                        /*background*/ false, callingUid, realCallingUid, intent,
+                        "Active ime");
+            }
+        }
+
+        // This is used to block background activity launch even if the app is still
+        // visible to user after user clicking home button.
+        final int appSwitchState = mService.getBalAppSwitchesState();
+
+        // don't abort if the callingUid has a visible window or is a persistent system process
+        final int callingUidProcState = mService.mActiveUids.getUidState(callingUid);
+        final boolean callingUidHasAnyVisibleWindow = mService.hasActiveVisibleWindow(callingUid);
+        final boolean isCallingUidForeground =
+                callingUidHasAnyVisibleWindow
+                        || callingUidProcState == ActivityManager.PROCESS_STATE_TOP
+                        || callingUidProcState == ActivityManager.PROCESS_STATE_BOUND_TOP;
+        final boolean isCallingUidPersistentSystemProcess =
+                callingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI;
+
+        // Normal apps with visible app window will be allowed to start activity if app switching
+        // is allowed, or apps like live wallpaper with non app visible window will be allowed.
+        final boolean appSwitchAllowedOrFg =
+                appSwitchState == APP_SWITCH_ALLOW || appSwitchState == APP_SWITCH_FG_ONLY;
+        final boolean allowCallingUidStartActivity =
+                ((appSwitchAllowedOrFg || mService.mActiveUids.hasNonAppVisibleWindow(callingUid))
+                                && callingUidHasAnyVisibleWindow)
+                        || isCallingUidPersistentSystemProcess;
+        if (useCallingUidState && allowCallingUidStartActivity) {
+            return logStartAllowedAndReturnCode(BAL_ALLOW_VISIBLE_WINDOW,
+                    /*background*/ false, callingUid, realCallingUid, intent,
+                    "callingUidHasAnyVisibleWindow = "
+                            + callingUid
+                            + ", isCallingUidPersistentSystemProcess = "
+                            + isCallingUidPersistentSystemProcess);
+        }
+        // take realCallingUid into consideration
+        final int realCallingUidProcState =
+                (callingUid == realCallingUid)
+                        ? callingUidProcState
+                        : mService.mActiveUids.getUidState(realCallingUid);
+        final boolean realCallingUidHasAnyVisibleWindow =
+                (callingUid == realCallingUid)
+                        ? callingUidHasAnyVisibleWindow
+                        : mService.hasActiveVisibleWindow(realCallingUid);
+        final boolean isRealCallingUidForeground =
+                (callingUid == realCallingUid)
+                        ? isCallingUidForeground
+                        : realCallingUidHasAnyVisibleWindow
+                                || realCallingUidProcState == ActivityManager.PROCESS_STATE_TOP;
+        final int realCallingAppId = UserHandle.getAppId(realCallingUid);
+        final boolean isRealCallingUidPersistentSystemProcess =
+                (callingUid == realCallingUid)
+                        ? isCallingUidPersistentSystemProcess
+                        : (realCallingAppId == Process.SYSTEM_UID)
+                                || realCallingUidProcState
+                                        <= ActivityManager.PROCESS_STATE_PERSISTENT_UI;
+
+        // In the case of an SDK sandbox calling uid, check if the corresponding app uid has a
+        // visible window.
+        if (Process.isSdkSandboxUid(realCallingUid)) {
+            int realCallingSdkSandboxUidToAppUid =
+                    Process.getAppUidForSdkSandboxUid(UserHandle.getAppId(realCallingUid));
+
+            if (mService.hasActiveVisibleWindow(realCallingSdkSandboxUidToAppUid)) {
+                return logStartAllowedAndReturnCode(BAL_ALLOW_SDK_SANDBOX,
+                        /*background*/ false, callingUid, realCallingUid, intent,
+                        "uid in SDK sandbox has visible (non-toast) window");
+            }
+        }
+
+        // Legacy behavior allows to use caller foreground state to bypass BAL restriction.
+        final boolean balAllowedByPiSender =
+                PendingIntentRecord.isPendingIntentBalAllowedByCaller(checkedOptions);
+
+        if (balAllowedByPiSender && realCallingUid != callingUid) {
+            final boolean useCallerPermission =
+                    PendingIntentRecord.isPendingIntentBalAllowedByPermission(checkedOptions);
+            if (useCallerPermission
+                    && ActivityManager.checkComponentPermission(
+                                    android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND,
+                                    realCallingUid,
+                                    -1,
+                                    true)
+                            == PackageManager.PERMISSION_GRANTED) {
+                return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT,
+                        /*background*/ false, callingUid, realCallingUid, intent,
+                        "realCallingUid has BAL permission. realCallingUid: " + realCallingUid);
+            }
+
+            // don't abort if the realCallingUid has a visible window
+            // TODO(b/171459802): We should check appSwitchAllowed also
+            if (realCallingUidHasAnyVisibleWindow) {
+                return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT,
+                        /*background*/ false, callingUid, realCallingUid, intent,
+                        "realCallingUid has visible (non-toast) window. realCallingUid: "
+                                + realCallingUid);
+            }
+            // if the realCallingUid is a persistent system process, abort if the IntentSender
+            // wasn't allowed to start an activity
+            if (isRealCallingUidPersistentSystemProcess && allowBackgroundActivityStart) {
+                return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT,
+                        /*background*/ false, callingUid, realCallingUid, intent,
+                        "realCallingUid is persistent system process AND intent "
+                                + "sender allowed (allowBackgroundActivityStart = true). "
+                                + "realCallingUid: " + realCallingUid);
+            }
+            // don't abort if the realCallingUid is an associated companion app
+            if (mService.isAssociatedCompanionApp(
+                    UserHandle.getUserId(realCallingUid), realCallingUid)) {
+                return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT,
+                        /*background*/ false, callingUid, realCallingUid, intent,
+                        "realCallingUid is a companion app. "
+                                + "realCallingUid: " + realCallingUid);
+            }
+        }
+        if (useCallingUidState) {
+            // don't abort if the callingUid has START_ACTIVITIES_FROM_BACKGROUND permission
+            if (ActivityTaskManagerService.checkPermission(START_ACTIVITIES_FROM_BACKGROUND,
+                    callingPid, callingUid) == PERMISSION_GRANTED) {
+                return logStartAllowedAndReturnCode(BAL_ALLOW_BAL_PERMISSION,
+                        /*background*/ true, callingUid, realCallingUid, intent,
+                        "START_ACTIVITIES_FROM_BACKGROUND permission granted");
+            }
+            // don't abort if the caller has the same uid as the recents component
+            if (mSupervisor.mRecentTasks.isCallerRecents(callingUid)) {
+                return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT,
+                        /*background*/ true, callingUid, realCallingUid,
+                        intent, "Recents Component");
+            }
+            // don't abort if the callingUid is the device owner
+            if (mService.isDeviceOwner(callingUid)) {
+                return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT,
+                        /*background*/ true, callingUid, realCallingUid,
+                        intent, "Device Owner");
+            }
+            // don't abort if the callingUid has companion device
+            final int callingUserId = UserHandle.getUserId(callingUid);
+            if (mService.isAssociatedCompanionApp(callingUserId, callingUid)) {
+                return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT,
+                        /*background*/ true, callingUid, realCallingUid,
+                        intent, "Companion App");
+            }
+            // don't abort if the callingUid has SYSTEM_ALERT_WINDOW permission
+            if (mService.hasSystemAlertWindowPermission(callingUid, callingPid, callingPackage)) {
+                Slog.w(
+                        TAG,
+                        "Background activity start for "
+                                + callingPackage
+                                + " allowed because SYSTEM_ALERT_WINDOW permission is granted.");
+                return logStartAllowedAndReturnCode(BAL_ALLOW_SAW_PERMISSION,
+                        /*background*/ true, callingUid, realCallingUid,
+                        intent, "SYSTEM_ALERT_WINDOW permission is granted");
+            }
+        }
+        // If we don't have callerApp at this point, no caller was provided to startActivity().
+        // That's the case for PendingIntent-based starts, since the creator's process might not be
+        // up and alive. If that's the case, we retrieve the WindowProcessController for the send()
+        // caller if caller allows, so that we can make the decision based on its state.
+        int callerAppUid = callingUid;
+        if (callerApp == null && balAllowedByPiSender) {
+            callerApp = mService.getProcessController(realCallingPid, realCallingUid);
+            callerAppUid = realCallingUid;
+        }
+        // don't abort if the callerApp or other processes of that uid are allowed in any way
+        if (callerApp != null && useCallingUidState) {
+            // first check the original calling process
+            @BalCode int balAllowedForCaller = callerApp
+                    .areBackgroundActivityStartsAllowed(appSwitchState);
+            if (balAllowedForCaller != BAL_BLOCK) {
+                return logStartAllowedAndReturnCode(balAllowedForCaller,
+                        /*background*/ true, callingUid, realCallingUid, intent,
+                        "callerApp process (pid = " + callerApp.getPid()
+                                + ", uid = " + callerAppUid + ") is allowed");
+            }
+            // only if that one wasn't allowed, check the other ones
+            final ArraySet<WindowProcessController> uidProcesses =
+                    mService.mProcessMap.getProcesses(callerAppUid);
+            if (uidProcesses != null) {
+                for (int i = uidProcesses.size() - 1; i >= 0; i--) {
+                    final WindowProcessController proc = uidProcesses.valueAt(i);
+                    int balAllowedForUid = proc.areBackgroundActivityStartsAllowed(appSwitchState);
+                    if (proc != callerApp
+                            && balAllowedForUid != BAL_BLOCK) {
+                        return logStartAllowedAndReturnCode(balAllowedForUid,
+                                /*background*/ true, callingUid, realCallingUid, intent,
+                                "process" + proc.getPid()
+                                        + " from uid " + callerAppUid + " is allowed");
+                    }
+                }
+            }
+        }
+        // anything that has fallen through would currently be aborted
+        Slog.w(
+                TAG,
+                "Background activity start [callingPackage: "
+                        + callingPackage
+                        + "; callingUid: "
+                        + callingUid
+                        + "; appSwitchState: "
+                        + appSwitchState
+                        + "; isCallingUidForeground: "
+                        + isCallingUidForeground
+                        + "; callingUidHasAnyVisibleWindow: "
+                        + callingUidHasAnyVisibleWindow
+                        + "; callingUidProcState: "
+                        + DebugUtils.valueToString(
+                                ActivityManager.class, "PROCESS_STATE_", callingUidProcState)
+                        + "; isCallingUidPersistentSystemProcess: "
+                        + isCallingUidPersistentSystemProcess
+                        + "; realCallingUid: "
+                        + realCallingUid
+                        + "; isRealCallingUidForeground: "
+                        + isRealCallingUidForeground
+                        + "; realCallingUidHasAnyVisibleWindow: "
+                        + realCallingUidHasAnyVisibleWindow
+                        + "; realCallingUidProcState: "
+                        + DebugUtils.valueToString(
+                                ActivityManager.class, "PROCESS_STATE_", realCallingUidProcState)
+                        + "; isRealCallingUidPersistentSystemProcess: "
+                        + isRealCallingUidPersistentSystemProcess
+                        + "; originatingPendingIntent: "
+                        + originatingPendingIntent
+                        + "; allowBackgroundActivityStart: "
+                        + allowBackgroundActivityStart
+                        + "; intent: "
+                        + intent
+                        + "; callerApp: "
+                        + callerApp
+                        + "; inVisibleTask: "
+                        + (callerApp != null && callerApp.hasActivityInVisibleTask())
+                        + "]");
+        // log aborted activity start to TRON
+        if (mService.isActivityStartsLoggingEnabled()) {
+            mSupervisor
+                    .getActivityMetricsLogger()
+                    .logAbortedBgActivityStart(
+                            intent,
+                            callerApp,
+                            callingUid,
+                            callingPackage,
+                            callingUidProcState,
+                            callingUidHasAnyVisibleWindow,
+                            realCallingUid,
+                            realCallingUidProcState,
+                            realCallingUidHasAnyVisibleWindow,
+                            (originatingPendingIntent != null));
+        }
+        return BAL_BLOCK;
+    }
+
+    static @BalCode int logStartAllowedAndReturnCode(@BalCode int code, boolean background,
+            int callingUid, int realCallingUid, Intent intent, int pid, String msg) {
+        return logStartAllowedAndReturnCode(code, background, callingUid, realCallingUid, intent,
+                DEBUG_ACTIVITY_STARTS ?  ("[Process(" + pid + ")]" + msg) : "");
+    }
+
+    static @BalCode int logStartAllowedAndReturnCode(@BalCode int code, boolean background,
+            int callingUid, int realCallingUid, Intent intent, String msg) {
+        statsLogBalAllowed(code, callingUid, realCallingUid, intent);
+        if (DEBUG_ACTIVITY_STARTS) {
+            StringBuilder builder = new StringBuilder();
+            if (background) {
+                builder.append("Background ");
+            }
+            builder.append("Activity start allowed: " + msg + ". callingUid: " + callingUid + ". ");
+            builder.append("BAL Code: ");
+            builder.append(code);
+            Slog.d(TAG,  builder.toString());
+        }
+        return code;
+    }
+
+    private static void statsLogBalAllowed(
+            @BalCode int code, int callingUid, int realCallingUid, Intent intent) {
+        if (code == BAL_ALLOW_PENDING_INTENT
+                && (callingUid == Process.SYSTEM_UID || realCallingUid == Process.SYSTEM_UID)) {
+            String activityName =
+                    intent != null ? intent.getComponent().flattenToShortString() : "";
+            FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED,
+                    activityName,
+                    code,
+                    callingUid,
+                    realCallingUid);
+        }
+        if (code == BAL_ALLOW_BAL_PERMISSION || code == BAL_ALLOW_FOREGROUND
+                    || code == BAL_ALLOW_SAW_PERMISSION) {
+            // We don't need to know which activity in this case.
+            FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED,
+                    /*activityName*/ "",
+                    code,
+                    callingUid,
+                    realCallingUid);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java b/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java
index 0afd872..cc47528 100644
--- a/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java
+++ b/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java
@@ -22,6 +22,10 @@
 import static com.android.server.wm.ActivityTaskManagerService.ACTIVITY_BG_START_GRACE_PERIOD_MS;
 import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_ALLOW;
 import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_FG_ONLY;
+import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_BAL_PERMISSION;
+import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_FOREGROUND;
+import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_GRACE_PERIOD;
+import static com.android.server.wm.BackgroundActivityStartController.BAL_BLOCK;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -71,7 +75,8 @@
         mBackgroundActivityStartCallback = callback;
     }
 
-    boolean areBackgroundActivityStartsAllowed(int pid, int uid, String packageName,
+    @BackgroundActivityStartController.BalCode
+    int areBackgroundActivityStartsAllowed(int pid, int uid, String packageName,
             int appSwitchState, boolean isCheckingForFgsStart,
             boolean hasActivityInVisibleTask, boolean hasBackgroundActivityStartPrivileges,
             long lastStopAppSwitchesTime, long lastActivityLaunchTime,
@@ -88,12 +93,10 @@
                 // let app to be able to start background activity even it's in grace period.
                 if (lastActivityLaunchTime > lastStopAppSwitchesTime
                         || lastActivityFinishTime > lastStopAppSwitchesTime) {
-                    if (DEBUG_ACTIVITY_STARTS) {
-                        Slog.d(TAG, "[Process(" + pid
-                                + ")] Activity start allowed: within "
-                                + ACTIVITY_BG_START_GRACE_PERIOD_MS + "ms grace period");
-                    }
-                    return true;
+                    return BackgroundActivityStartController.logStartAllowedAndReturnCode(
+                            BAL_ALLOW_GRACE_PERIOD, /*background*/ true, uid, uid, /*intent*/ null,
+                            pid, "Activity start allowed: within "
+                                    + ACTIVITY_BG_START_GRACE_PERIOD_MS + "ms grace period");
                 }
                 if (DEBUG_ACTIVITY_STARTS) {
                     Slog.d(TAG, "[Process(" + pid + ")] Activity start within "
@@ -105,39 +108,31 @@
         }
         // Allow if the proc is instrumenting with background activity starts privs.
         if (hasBackgroundActivityStartPrivileges) {
-            if (DEBUG_ACTIVITY_STARTS) {
-                Slog.d(TAG, "[Process(" + pid
-                        + ")] Activity start allowed: process instrumenting with background "
+            return BackgroundActivityStartController.logStartAllowedAndReturnCode(
+                    BAL_ALLOW_BAL_PERMISSION, /*background*/ true, uid, uid, /*intent*/ null,
+                    pid, "Activity start allowed: process instrumenting with background "
                         + "activity starts privileges");
-            }
-            return true;
         }
         // Allow if the caller has an activity in any foreground task.
         if (hasActivityInVisibleTask
                 && (appSwitchState == APP_SWITCH_ALLOW || appSwitchState == APP_SWITCH_FG_ONLY)) {
-            if (DEBUG_ACTIVITY_STARTS) {
-                Slog.d(TAG, "[Process(" + pid
-                        + ")] Activity start allowed: process has activity in foreground task");
-            }
-            return true;
+            return BackgroundActivityStartController.logStartAllowedAndReturnCode(
+                    BAL_ALLOW_FOREGROUND, /*background*/ false, uid, uid, /*intent*/ null,
+                    pid, "Activity start allowed: process has activity in foreground task");
         }
         // Allow if the caller is bound by a UID that's currently foreground.
         if (isBoundByForegroundUid()) {
-            if (DEBUG_ACTIVITY_STARTS) {
-                Slog.d(TAG, "[Process(" + pid
-                        + ")] Activity start allowed: process bound by foreground uid");
-            }
-            return true;
+            return BackgroundActivityStartController.logStartAllowedAndReturnCode(
+                    BAL_ALLOW_FOREGROUND, /*background*/ false, uid, uid, /*intent*/ null,
+                    pid, "Activity start allowed: process bound by foreground uid");
         }
         // Allow if the flag was explicitly set.
         if (isBackgroundStartAllowedByToken(uid, packageName, isCheckingForFgsStart)) {
-            if (DEBUG_ACTIVITY_STARTS) {
-                Slog.d(TAG, "[Process(" + pid
-                        + ")] Activity start allowed: process allowed by token");
-            }
-            return true;
+            return BackgroundActivityStartController.logStartAllowedAndReturnCode(
+                    BAL_ALLOW_BAL_PERMISSION, /*background*/ true, uid, uid, /*intent*/ null,
+                    pid, "Activity start allowed: process allowed by token");
         }
-        return false;
+        return BAL_BLOCK;
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java b/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java
index 5e44d6c..e91c9d4 100644
--- a/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java
@@ -41,7 +41,8 @@
 
     // Desktop mode feature flag.
     static final boolean DESKTOP_MODE_SUPPORTED = SystemProperties.getBoolean(
-            "persist.wm.debug.desktop_mode", false);
+            "persist.wm.debug.desktop_mode", false) || SystemProperties.getBoolean(
+            "persist.wm.debug.desktop_mode_2", false);
     // Override default freeform task width when desktop mode is enabled. In dips.
     private static final int DESKTOP_MODE_DEFAULT_WIDTH_DP = SystemProperties.getInt(
             "persist.wm.debug.desktop_mode.default_width", 840);
@@ -79,8 +80,8 @@
             appendLog("not in bounds phase, skipping");
             return RESULT_SKIP;
         }
-        if (!task.inFreeformWindowingMode()) {
-            appendLog("not a freeform task, skipping");
+        if (!task.isActivityTypeStandard()) {
+            appendLog("not standard activity type, skipping");
             return RESULT_SKIP;
         }
         if (!currentParams.mBounds.isEmpty()) {
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 4113081..aedd2c5 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -200,6 +200,7 @@
 
     private final boolean mCarDockEnablesAccelerometer;
     private final boolean mDeskDockEnablesAccelerometer;
+    private final boolean mDeskDockRespectsNoSensorAndLockedWithoutAccelerometer;
     private final AccessibilityManager mAccessibilityManager;
     private final ImmersiveModeConfirmation mImmersiveModeConfirmation;
     private final ScreenshotHelper mScreenshotHelper;
@@ -435,6 +436,8 @@
         final Resources r = mContext.getResources();
         mCarDockEnablesAccelerometer = r.getBoolean(R.bool.config_carDockEnablesAccelerometer);
         mDeskDockEnablesAccelerometer = r.getBoolean(R.bool.config_deskDockEnablesAccelerometer);
+        mDeskDockRespectsNoSensorAndLockedWithoutAccelerometer =
+                r.getBoolean(R.bool.config_deskRespectsNoSensorAndLockedWithoutAccelerometer);
         mCanSystemBarsBeShownByUser = !r.getBoolean(
                 R.bool.config_remoteInsetsControllerControlsSystemBars) || r.getBoolean(
                 R.bool.config_remoteInsetsControllerSystemBarsCanBeShownByUserAction);
@@ -755,6 +758,10 @@
         return mDeskDockEnablesAccelerometer;
     }
 
+    boolean isDeskDockRespectsNoSensorAndLockedWithoutAccelerometer() {
+        return mDeskDockRespectsNoSensorAndLockedWithoutAccelerometer;
+    }
+
     public void setPersistentVrModeEnabled(boolean persistentVrModeEnabled) {
         mPersistentVrModeEnabled = persistentVrModeEnabled;
     }
@@ -2662,6 +2669,8 @@
         pw.print("mCarDockEnablesAccelerometer="); pw.print(mCarDockEnablesAccelerometer);
         pw.print(" mDeskDockEnablesAccelerometer=");
         pw.println(mDeskDockEnablesAccelerometer);
+        pw.print(" mDeskDockRespectsNoSensorAndLockedWithoutAccelerometer=");
+        pw.println(mDeskDockRespectsNoSensorAndLockedWithoutAccelerometer);
         pw.print(prefix); pw.print("mDockMode="); pw.print(Intent.dockStateToString(mDockMode));
         pw.print(" mLidState="); pw.println(WindowManagerFuncs.lidStateToString(mLidState));
         pw.print(prefix); pw.print("mAwake="); pw.print(mAwake);
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 3404279..e9569d8 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -87,6 +87,12 @@
  */
 public class DisplayRotation {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayRotation" : TAG_WM;
+    // Delay to avoid race between fold update and orientation update.
+    private static final int ORIENTATION_UPDATE_DELAY_MS = 800;
+
+    // Delay in milliseconds when updating config due to folding events. This prevents
+    // config changes and unexpected jumps while folding the device to closed state.
+    private static final int FOLDING_RECOMPUTE_CONFIG_DELAY_MS = 800;
 
     private static class RotationAnimationPair {
         @AnimRes
@@ -1166,6 +1172,10 @@
                 mDisplayPolicy.isCarDockEnablesAccelerometer();
         final boolean deskDockEnablesAccelerometer =
                 mDisplayPolicy.isDeskDockEnablesAccelerometer();
+        final boolean deskDockRespectsNoSensorAndLockedWithoutAccelerometer =
+                mDisplayPolicy.isDeskDockRespectsNoSensorAndLockedWithoutAccelerometer()
+                        && (orientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED
+                                || orientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
 
         final int preferredRotation;
         if (!isDefaultDisplay) {
@@ -1184,7 +1194,8 @@
         } else if ((dockMode == Intent.EXTRA_DOCK_STATE_DESK
                 || dockMode == Intent.EXTRA_DOCK_STATE_LE_DESK
                 || dockMode == Intent.EXTRA_DOCK_STATE_HE_DESK)
-                && (deskDockEnablesAccelerometer || mDeskDockRotation >= 0)) {
+                && (deskDockEnablesAccelerometer || mDeskDockRotation >= 0)
+                && !deskDockRespectsNoSensorAndLockedWithoutAccelerometer) {
             // Ignore sensor when in desk dock unless explicitly enabled.
             // This case can override the behavior of NOSENSOR, and can also
             // enable 180 degree rotation while docked.
@@ -1618,6 +1629,7 @@
         private boolean mInHalfFoldTransition = false;
         private final boolean mIsDisplayAlwaysSeparatingHinge;
         private final Set<Integer> mTabletopRotations;
+        private final Runnable mActivityBoundsUpdateCallback;
 
         FoldController() {
             mTabletopRotations = new ArraySet<>();
@@ -1652,6 +1664,26 @@
             }
             mIsDisplayAlwaysSeparatingHinge = mContext.getResources().getBoolean(
                     R.bool.config_isDisplayHingeAlwaysSeparating);
+
+            mActivityBoundsUpdateCallback = new Runnable() {
+                public void run() {
+                    if (mDeviceState == DeviceStateController.DeviceState.OPEN
+                            || mDeviceState == DeviceStateController.DeviceState.HALF_FOLDED) {
+                        synchronized (mLock) {
+                            final Task topFullscreenTask =
+                                    mDisplayContent.getTask(
+                                            t -> t.getWindowingMode() == WINDOWING_MODE_FULLSCREEN);
+                            if (topFullscreenTask != null) {
+                                final ActivityRecord top =
+                                        topFullscreenTask.topRunningActivity();
+                                if (top != null) {
+                                    top.recomputeConfiguration();
+                                }
+                            }
+                        }
+                    }
+                }
+            };
         }
 
         boolean isDeviceInPosture(DeviceStateController.DeviceState state, boolean isTabletop) {
@@ -1713,24 +1745,19 @@
                 mDeviceState = newState;
                 // Now mFoldState is set to HALF_FOLDED, the overrideFrozenRotation function will
                 // return true, so rotation is unlocked.
-                mService.updateRotation(false /* alwaysSendConfiguration */,
-                        false /* forceRelayout */);
             } else {
                 mInHalfFoldTransition = true;
                 mDeviceState = newState;
-                // Tell the device to update its orientation.
-                mService.updateRotation(false /* alwaysSendConfiguration */,
-                        false /* forceRelayout */);
             }
+            UiThread.getHandler().postDelayed(
+                    () -> {
+                        mService.updateRotation(false /* alwaysSendConfiguration */,
+                                false /* forceRelayout */);
+                    }, ORIENTATION_UPDATE_DELAY_MS);
             // Alert the activity of possible new bounds.
-            final Task topFullscreenTask =
-                    mDisplayContent.getTask(t -> t.getWindowingMode() == WINDOWING_MODE_FULLSCREEN);
-            if (topFullscreenTask != null) {
-                final ActivityRecord top = topFullscreenTask.topRunningActivity();
-                if (top != null) {
-                    top.recomputeConfiguration();
-                }
-            }
+            UiThread.getHandler().removeCallbacks(mActivityBoundsUpdateCallback);
+            UiThread.getHandler().postDelayed(mActivityBoundsUpdateCallback,
+                    FOLDING_RECOMPUTE_CONFIG_DELAY_MS);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/EventLogTags.logtags b/services/core/java/com/android/server/wm/EventLogTags.logtags
index 1e5a219..385d914 100644
--- a/services/core/java/com/android/server/wm/EventLogTags.logtags
+++ b/services/core/java/com/android/server/wm/EventLogTags.logtags
@@ -1,4 +1,4 @@
-# See system/core/logcat/event.logtags for a description of the format of this file.
+# See system/logging/logcat/event.logtags for a description of the format of this file.
 
 option java_package com.android.server.wm
 
@@ -52,7 +52,7 @@
 30066 wm_add_to_stopping (User|1|5),(Token|1|5),(Component Name|3),(Reason|3)
 
 # Keyguard status changed
-30067 wm_set_keyguard_shown (Display Id|1|5),(keyguardShowing|1),(aodShowing|1),(keyguardGoingAway|1),(Reason|3)
+30067 wm_set_keyguard_shown (Display Id|1|5),(keyguardShowing|1),(aodShowing|1),(keyguardGoingAway|1),(occluded|1),(Reason|3)
 
 # Out of memory for surfaces.
 31000 wm_no_surface_memory (Window|3),(PID|1|5),(Operation|3)
@@ -62,8 +62,14 @@
 31002 wm_task_moved (TaskId|1|5),(ToTop|1),(Index|1)
 # Task removed with source explanation.
 31003 wm_task_removed (TaskId|1|5),(Reason|3)
+
+# Set the requested orientation of an activity.
+31006 wm_set_requested_orientation (Orientation|1|5),(Component Name|3)
+
 # bootanim finished:
 31007 wm_boot_animation_done (time|2|3)
+# Notify keyguard occlude statuc change to SysUI.
+31008 wm_set_keyguard_occluded (occluded|1),(animate|1),(transit|1),(Channel|3)
 
 # Request surface flinger to show / hide the wallpaper surface.
 33001 wm_wallpaper_surface (Display Id|1|5),(Visible|1),(Target|3)
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 1d21b9d..574ab83 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -188,6 +188,7 @@
                 keyguardShowing ? 1 : 0,
                 aodShowing ? 1 : 0,
                 state.mKeyguardGoingAway ? 1 : 0,
+                state.mOccluded ? 1 : 0,
                 "setKeyguardShown");
 
         // Update the task snapshot if the screen will not be turned off. To make sure that the
@@ -255,9 +256,10 @@
         try {
             EventLogTags.writeWmSetKeyguardShown(
                     displayId,
-                    1 /* keyguardShowing */,
+                    state.mKeyguardShowing ? 1 : 0,
                     state.mAodShowing ? 1 : 0,
                     1 /* keyguardGoingAway */,
+                    state.mOccluded ? 1 : 0,
                     "keyguardGoingAway");
             final int transitFlags = convertTransitFlags(flags);
             final DisplayContent dc = mRootWindowContainer.getDefaultDisplay();
@@ -671,6 +673,15 @@
 
             boolean hasChange = false;
             if (lastOccluded != mOccluded) {
+                if (mDisplayId == DEFAULT_DISPLAY) {
+                    EventLogTags.writeWmSetKeyguardShown(
+                            mDisplayId,
+                            mKeyguardShowing ? 1 : 0,
+                            mAodShowing ? 1 : 0,
+                            mKeyguardGoingAway ? 1 : 0,
+                            mOccluded ? 1 : 0,
+                            "updateVisibility");
+                }
                 controller.handleOccludedChanged(mDisplayId, mTopOccludesActivity);
                 hasChange = true;
             } else if (!lastKeyguardGoingAway && mKeyguardGoingAway) {
diff --git a/services/core/java/com/android/server/wm/LetterboxConfiguration.java b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
index fa49a6ba..ec04894 100644
--- a/services/core/java/com/android/server/wm/LetterboxConfiguration.java
+++ b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
@@ -19,6 +19,7 @@
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.LetterboxConfigurationDeviceConfig.KEY_ALLOW_IGNORE_ORIENTATION_REQUEST;
+import static com.android.server.wm.LetterboxConfigurationDeviceConfig.KEY_DISABLE_SIZE_COMPAT_MODE_AFTER_ORIENTATION_CHANGE_FROM_APP;
 import static com.android.server.wm.LetterboxConfigurationDeviceConfig.KEY_ENABLE_CAMERA_COMPAT_TREATMENT;
 import static com.android.server.wm.LetterboxConfigurationDeviceConfig.KEY_ENABLE_COMPAT_FAKE_FOCUS;
 import static com.android.server.wm.LetterboxConfigurationDeviceConfig.KEY_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY;
@@ -183,6 +184,10 @@
     // portrait device orientation.
     private boolean mIsVerticalReachabilityEnabled;
 
+    // Whether book mode automatic horizontal reachability positioning is allowed for letterboxed
+    // fullscreen apps in landscape device orientation.
+    private boolean mIsAutomaticReachabilityInBookModeEnabled;
+
     // Whether education is allowed for letterboxed fullscreen apps.
     private boolean mIsEducationEnabled;
 
@@ -276,6 +281,8 @@
                 R.bool.config_letterboxIsHorizontalReachabilityEnabled);
         mIsVerticalReachabilityEnabled = mContext.getResources().getBoolean(
                 R.bool.config_letterboxIsVerticalReachabilityEnabled);
+        mIsAutomaticReachabilityInBookModeEnabled = mContext.getResources().getBoolean(
+                R.bool.config_letterboxIsAutomaticReachabilityInBookModeEnabled);
         mDefaultPositionForHorizontalReachability =
                 readLetterboxHorizontalReachabilityPositionFromConfig(mContext, false);
         mDefaultPositionForVerticalReachability =
@@ -314,6 +321,10 @@
         mDeviceConfig.updateFlagActiveStatus(
                 /* isActive */ mTranslucentLetterboxingEnabled,
                 /* key */ KEY_ENABLE_LETTERBOX_TRANSLUCENT_ACTIVITY);
+        mDeviceConfig.updateFlagActiveStatus(
+                /* isActive */ true,
+                /* key */ KEY_DISABLE_SIZE_COMPAT_MODE_AFTER_ORIENTATION_CHANGE_FROM_APP);
+
         mLetterboxConfigurationPersister = letterboxConfigurationPersister;
         mLetterboxConfigurationPersister.start();
     }
@@ -327,6 +338,16 @@
     }
 
     /**
+     * Whether size compat mode is disabled after an orientation change request comes from the app.
+     * This value is controlled via {@link android.provider.DeviceConfig}.
+     */
+    // TODO(b/270356567) Clean up this flag
+    boolean isSizeCompatModeDisabledAfterOrientationChangeFromApp() {
+        return mDeviceConfig.getFlag(
+                KEY_DISABLE_SIZE_COMPAT_MODE_AFTER_ORIENTATION_CHANGE_FROM_APP);
+    }
+
+    /**
      * Overrides the aspect ratio of letterbox for fixed orientation. If given value is <= {@link
      * #MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO}, both it and a value of {@link
      * com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio} will be ignored and
@@ -666,6 +687,14 @@
         return mIsVerticalReachabilityEnabled;
     }
 
+    /*
+     * Whether automatic horizontal reachability repositioning in book mode is allowed for
+     * letterboxed fullscreen apps in landscape device orientation.
+     */
+    boolean getIsAutomaticReachabilityInBookModeEnabled() {
+        return mIsAutomaticReachabilityInBookModeEnabled;
+    }
+
     /**
      * Overrides whether horizontal reachability repositioning is allowed for letterboxed fullscreen
      * apps in landscape device orientation.
@@ -683,6 +712,14 @@
     }
 
     /**
+     * Overrides whether automatic horizontal reachability repositioning in book mode is allowed for
+     * letterboxed fullscreen apps in landscape device orientation.
+     */
+    void setIsAutomaticReachabilityInBookModeEnabled(boolean enabled) {
+        mIsAutomaticReachabilityInBookModeEnabled = enabled;
+    }
+
+    /**
      * Resets whether horizontal reachability repositioning is allowed for letterboxed fullscreen
      * apps in landscape device orientation to
      * {@link R.bool.config_letterboxIsHorizontalReachabilityEnabled}.
@@ -702,6 +739,16 @@
                 R.bool.config_letterboxIsVerticalReachabilityEnabled);
     }
 
+    /**
+     * Resets whether automatic horizontal reachability repositioning in book mode is
+     * allowed for letterboxed fullscreen apps in landscape device orientation to
+     * {@link R.bool.config_letterboxIsAutomaticReachabilityInBookModeEnabled}.
+     */
+    void resetEnabledAutomaticReachabilityInBookMode() {
+        mIsAutomaticReachabilityInBookModeEnabled = mContext.getResources().getBoolean(
+                R.bool.config_letterboxIsAutomaticReachabilityInBookModeEnabled);
+    }
+
     /*
      * Gets default horizontal position of the letterboxed app window when horizontal reachability
      * is enabled.
diff --git a/services/core/java/com/android/server/wm/LetterboxConfigurationDeviceConfig.java b/services/core/java/com/android/server/wm/LetterboxConfigurationDeviceConfig.java
index df3c8f0..1651af3 100644
--- a/services/core/java/com/android/server/wm/LetterboxConfigurationDeviceConfig.java
+++ b/services/core/java/com/android/server/wm/LetterboxConfigurationDeviceConfig.java
@@ -20,7 +20,6 @@
 import android.provider.DeviceConfig;
 import android.util.ArraySet;
 
-
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.util.Map;
@@ -53,6 +52,11 @@
 
     private static final boolean DEFAULT_VALUE_ENABLE_LETTERBOX_TRANSLUCENT_ACTIVITY = true;
 
+    static final String KEY_DISABLE_SIZE_COMPAT_MODE_AFTER_ORIENTATION_CHANGE_FROM_APP =
+            "disable_size_compat_mode_after_orientation_change_from_app";
+    private static final boolean
+            DEFAULT_VALUE_DISABLE_SIZE_COMPAT_MODE_AFTER_ORIENTATION_CHANGE_FROM_APP = true;
+
     @VisibleForTesting
     static final Map<String, Boolean> sKeyToDefaultValueMap = Map.of(
             KEY_ENABLE_CAMERA_COMPAT_TREATMENT,
@@ -64,7 +68,9 @@
             KEY_ENABLE_COMPAT_FAKE_FOCUS,
             DEFAULT_VALUE_ENABLE_COMPAT_FAKE_FOCUS,
             KEY_ENABLE_LETTERBOX_TRANSLUCENT_ACTIVITY,
-            DEFAULT_VALUE_ENABLE_LETTERBOX_TRANSLUCENT_ACTIVITY
+            DEFAULT_VALUE_ENABLE_LETTERBOX_TRANSLUCENT_ACTIVITY,
+            KEY_DISABLE_SIZE_COMPAT_MODE_AFTER_ORIENTATION_CHANGE_FROM_APP,
+            DEFAULT_VALUE_DISABLE_SIZE_COMPAT_MODE_AFTER_ORIENTATION_CHANGE_FROM_APP
     );
 
     // Whether camera compatibility treatment is enabled.
@@ -93,6 +99,10 @@
     private boolean mIsTranslucentLetterboxingAllowed =
             DEFAULT_VALUE_ENABLE_LETTERBOX_TRANSLUCENT_ACTIVITY;
 
+    // Whether size compat mode is disabled after an orientation change request comes from the app
+    private boolean mIsSizeCompatModeDisabledAfterOrientationChangeFromApp =
+            DEFAULT_VALUE_DISABLE_SIZE_COMPAT_MODE_AFTER_ORIENTATION_CHANGE_FROM_APP;
+
     // Set of active device configs that need to be updated in
     // DeviceConfig.OnPropertiesChangedListener#onPropertiesChanged.
     private final ArraySet<String> mActiveDeviceConfigsSet = new ArraySet<>();
@@ -142,6 +152,8 @@
                 return mIsCompatFakeFocusAllowed;
             case KEY_ENABLE_LETTERBOX_TRANSLUCENT_ACTIVITY:
                 return mIsTranslucentLetterboxingAllowed;
+            case KEY_DISABLE_SIZE_COMPAT_MODE_AFTER_ORIENTATION_CHANGE_FROM_APP:
+                return mIsSizeCompatModeDisabledAfterOrientationChangeFromApp;
             default:
                 throw new AssertionError("Unexpected flag name: " + key);
         }
@@ -169,6 +181,10 @@
             case KEY_ENABLE_LETTERBOX_TRANSLUCENT_ACTIVITY:
                 mIsTranslucentLetterboxingAllowed = getDeviceConfig(key, defaultValue);
                 break;
+            case KEY_DISABLE_SIZE_COMPAT_MODE_AFTER_ORIENTATION_CHANGE_FROM_APP:
+                mIsSizeCompatModeDisabledAfterOrientationChangeFromApp =
+                        getDeviceConfig(key, defaultValue);
+                break;
             default:
                 throw new AssertionError("Unexpected flag name: " + key);
         }
diff --git a/services/core/java/com/android/server/wm/LetterboxConfigurationPersister.java b/services/core/java/com/android/server/wm/LetterboxConfigurationPersister.java
index 4a99db5..3b10deb 100644
--- a/services/core/java/com/android/server/wm/LetterboxConfigurationPersister.java
+++ b/services/core/java/com/android/server/wm/LetterboxConfigurationPersister.java
@@ -216,6 +216,10 @@
     }
 
     private void readCurrentConfiguration() {
+        if (!mConfigurationFile.exists()) {
+            useDefaultValue();
+            return;
+        }
         FileInputStream fis = null;
         try {
             fis = mConfigurationFile.openRead();
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index c20a513..4d0c768 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -22,6 +22,7 @@
 import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH;
 import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
 import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS;
+import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED;
 import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION;
 import static android.content.pm.ActivityInfo.OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE;
 import static android.content.pm.ActivityInfo.OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA;
@@ -38,6 +39,10 @@
 import static android.content.pm.ActivityInfo.screenOrientationToString;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
+import static android.content.res.Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
+import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED;
+import static android.content.res.Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
 import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION;
 import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH;
@@ -125,6 +130,14 @@
 
     private static final float UNDEFINED_ASPECT_RATIO = 0f;
 
+    // Minimum value of mSetOrientationRequestCounter before qualifying as orientation request loop
+    @VisibleForTesting
+    static final int MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP = 2;
+    // Used to determine reset of mSetOrientationRequestCounter if next app requested
+    // orientation is after timeout value
+    @VisibleForTesting
+    static final int SET_ORIENTATION_REQUEST_COUNTER_TIMEOUT_MS = 1000;
+
     private final Point mTmpPoint = new Point();
 
     private final LetterboxConfiguration mLetterboxConfiguration;
@@ -163,6 +176,8 @@
 
     // Corresponds to OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION
     private final boolean mIsOverrideEnableCompatIgnoreRequestedOrientationEnabled;
+    // Corresponds to OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED
+    private final boolean mIsOverrideEnableCompatIgnoreOrientationRequestWhenLoopDetectedEnabled;
 
     // Corresponds to OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS
     private final boolean mIsOverrideEnableCompatFakeFocusEnabled;
@@ -187,12 +202,18 @@
     private float mInheritedMinAspectRatio = UNDEFINED_ASPECT_RATIO;
     private float mInheritedMaxAspectRatio = UNDEFINED_ASPECT_RATIO;
 
+    // Updated when ActivityRecord#setRequestedOrientation is called
+    private long mTimeMsLastSetOrientationRequest = 0;
+
     @Configuration.Orientation
-    private int mInheritedOrientation = Configuration.ORIENTATION_UNDEFINED;
+    private int mInheritedOrientation = ORIENTATION_UNDEFINED;
 
     // The app compat state for the opaque activity if any
     private int mInheritedAppCompatState = APP_COMPAT_STATE_CHANGED__STATE__UNKNOWN;
 
+    // Counter for ActivityRecord#setRequestedOrientation
+    private int mSetOrientationRequestCounter = 0;
+
     // The CompatDisplayInsets of the opaque activity beneath the translucent one.
     private ActivityRecord.CompatDisplayInsets mInheritedCompatDisplayInsets;
 
@@ -288,6 +309,9 @@
 
         mIsOverrideEnableCompatIgnoreRequestedOrientationEnabled =
                 isCompatChangeEnabled(OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION);
+        mIsOverrideEnableCompatIgnoreOrientationRequestWhenLoopDetectedEnabled =
+                isCompatChangeEnabled(
+                        OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED);
 
         mIsOverrideEnableCompatFakeFocusEnabled =
                 isCompatChangeEnabled(OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS);
@@ -323,6 +347,10 @@
             mLetterbox.destroy();
             mLetterbox = null;
         }
+        if (mLetterboxConfigListener != null) {
+            mLetterboxConfigListener.onRemoved();
+            mLetterboxConfigListener = null;
+        }
     }
 
     void onMovedToDisplay(int displayId) {
@@ -354,38 +382,88 @@
      *     <li>Opt-in component property or per-app override are enabled
      *     <li>Activity is relaunched after {@link android.app.Activity#setRequestedOrientation}
      *     call from an app or camera compat force rotation treatment is active for the activity.
+     *     <li>Orientation request loop detected and is not letterboxed for fixed orientation
      * </ul>
      */
     boolean shouldIgnoreRequestedOrientation(@ScreenOrientation int requestedOrientation) {
-        if (!shouldEnableWithOverrideAndProperty(
+        if (shouldEnableWithOverrideAndProperty(
                 /* gatingCondition */ mLetterboxConfiguration
                         ::isPolicyForIgnoringRequestedOrientationEnabled,
                 mIsOverrideEnableCompatIgnoreRequestedOrientationEnabled,
                 mBooleanPropertyIgnoreRequestedOrientation)) {
-            return false;
+            if (mIsRelauchingAfterRequestedOrientationChanged) {
+                Slog.w(TAG, "Ignoring orientation update to "
+                        + screenOrientationToString(requestedOrientation)
+                        + " due to relaunching after setRequestedOrientation for "
+                        + mActivityRecord);
+                return true;
+            }
+            DisplayContent displayContent = mActivityRecord.mDisplayContent;
+            if (displayContent == null) {
+                return false;
+            }
+            if (displayContent.mDisplayRotationCompatPolicy != null
+                    && displayContent.mDisplayRotationCompatPolicy
+                    .isTreatmentEnabledForActivity(mActivityRecord)) {
+                Slog.w(TAG, "Ignoring orientation update to "
+                        + screenOrientationToString(requestedOrientation)
+                        + " due to camera compat treatment for " + mActivityRecord);
+                return true;
+            }
         }
-        if (mIsRelauchingAfterRequestedOrientationChanged) {
+
+        if (shouldIgnoreOrientationRequestLoop()) {
             Slog.w(TAG, "Ignoring orientation update to "
                     + screenOrientationToString(requestedOrientation)
-                    + " due to relaunching after setRequestedOrientation for " + mActivityRecord);
-            return true;
-        }
-        DisplayContent displayContent = mActivityRecord.mDisplayContent;
-        if (displayContent == null) {
-            return false;
-        }
-        if (displayContent.mDisplayRotationCompatPolicy != null
-                && displayContent.mDisplayRotationCompatPolicy
-                        .isTreatmentEnabledForActivity(mActivityRecord)) {
-            Slog.w(TAG, "Ignoring orientation update to "
-                    + screenOrientationToString(requestedOrientation)
-                    + " due to camera compat treatment for " + mActivityRecord);
+                    + " as orientation request loop was detected for "
+                    + mActivityRecord);
             return true;
         }
         return false;
     }
 
     /**
+     * Whether an app is calling {@link android.app.Activity#setRequestedOrientation}
+     * in a loop and orientation request should be ignored.
+     *
+     * <p>This should only be called once in response to
+     * {@link android.app.Activity#setRequestedOrientation}. See
+     * {@link #shouldIgnoreRequestedOrientation} for more details.
+     *
+     * <p>This treatment is enabled when the following conditions are met:
+     * <ul>
+     *     <li>Per-app override is enabled
+     *     <li>App has requested orientation more than 2 times within 1-second
+     *     timer and activity is not letterboxed for fixed orientation
+     * </ul>
+     */
+    @VisibleForTesting
+    boolean shouldIgnoreOrientationRequestLoop() {
+        if (!mIsOverrideEnableCompatIgnoreOrientationRequestWhenLoopDetectedEnabled) {
+            return false;
+        }
+
+        final long currTimeMs = System.currentTimeMillis();
+        if (currTimeMs - mTimeMsLastSetOrientationRequest
+                < SET_ORIENTATION_REQUEST_COUNTER_TIMEOUT_MS) {
+            mSetOrientationRequestCounter += 1;
+        } else {
+            // Resets app setOrientationRequest counter if timed out
+            mSetOrientationRequestCounter = 0;
+        }
+        // Update time last called
+        mTimeMsLastSetOrientationRequest = currTimeMs;
+
+        return mSetOrientationRequestCounter >= MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP
+                && !mActivityRecord.isLetterboxedForFixedOrientationAndAspectRatio();
+    }
+
+    @VisibleForTesting
+    int getSetOrientationRequestCounter() {
+        return mSetOrientationRequestCounter;
+    }
+
+    /**
      * Whether sending compat fake focus for split screen resumed activities is enabled. Needed
      * because some game engines wait to get focus before drawing the content of the app which isn't
      * guaranteed by default in multi-window modes.
@@ -455,6 +533,10 @@
 
     @ScreenOrientation
     int overrideOrientationIfNeeded(@ScreenOrientation int candidate) {
+        // In some cases (e.g. Kids app) we need to map the candidate orientation to some other
+        // orientation.
+        candidate = mActivityRecord.mWmService.mapOrientationRequest(candidate);
+
         if (FALSE.equals(mBooleanPropertyAllowOrientationOverride)) {
             return candidate;
         }
@@ -745,6 +827,8 @@
             final Rect innerFrame = hasInheritedLetterboxBehavior()
                     ? mActivityRecord.getBounds() : w.getFrame();
             mLetterbox.layout(spaceToFill, innerFrame, mTmpPoint);
+            // We need to notify Shell that letterbox position has changed.
+            mActivityRecord.getTask().dispatchTaskInfoChangedIfNeeded(true /* force */);
         } else if (mLetterbox != null) {
             mLetterbox.hide();
         }
@@ -793,13 +877,18 @@
     float getHorizontalPositionMultiplier(Configuration parentConfiguration) {
         // Don't check resolved configuration because it may not be updated yet during
         // configuration change.
-        boolean bookMode = isDisplayFullScreenAndInPosture(
-                DeviceStateController.DeviceState.HALF_FOLDED, false /* isTabletop */);
+        boolean bookModeEnabled = isFullScreenAndBookModeEnabled();
         return isHorizontalReachabilityEnabled(parentConfiguration)
                 // Using the last global dynamic position to avoid "jumps" when moving
                 // between apps or activities.
-                ? mLetterboxConfiguration.getHorizontalMultiplierForReachability(bookMode)
-                : mLetterboxConfiguration.getLetterboxHorizontalPositionMultiplier(bookMode);
+                ? mLetterboxConfiguration.getHorizontalMultiplierForReachability(bookModeEnabled)
+                : mLetterboxConfiguration.getLetterboxHorizontalPositionMultiplier(bookModeEnabled);
+    }
+
+    private boolean isFullScreenAndBookModeEnabled() {
+        return isDisplayFullScreenAndInPosture(
+                DeviceStateController.DeviceState.HALF_FOLDED, false /* isTabletop */)
+                && mLetterboxConfiguration.getIsAutomaticReachabilityInBookModeEnabled();
     }
 
     float getVerticalPositionMultiplier(Configuration parentConfiguration) {
@@ -814,12 +903,14 @@
                 : mLetterboxConfiguration.getLetterboxVerticalPositionMultiplier(tabletopMode);
     }
 
-    float getFixedOrientationLetterboxAspectRatio() {
+    float getFixedOrientationLetterboxAspectRatio(@NonNull Configuration parentConfiguration) {
+        // Don't resize to split screen size when half folded if letterbox position is centered
         return isDisplayFullScreenAndSeparatingHinge()
-                ? getSplitScreenAspectRatio()
-                : mActivityRecord.shouldCreateCompatDisplayInsets()
-                    ? getDefaultMinAspectRatioForUnresizableApps()
-                    : getDefaultMinAspectRatio();
+                    && getHorizontalPositionMultiplier(parentConfiguration) != 0.5f
+                        ? getSplitScreenAspectRatio()
+                        : mActivityRecord.shouldCreateCompatDisplayInsets()
+                            ? getDefaultMinAspectRatioForUnresizableApps()
+                            : getDefaultMinAspectRatio();
     }
 
     private float getDefaultMinAspectRatioForUnresizableApps() {
@@ -845,7 +936,7 @@
         int dividerInsets =
                 getResources().getDimensionPixelSize(R.dimen.docked_stack_divider_insets);
         int dividerSize = dividerWindowWidth - dividerInsets * 2;
-        final Rect bounds = new Rect(displayContent.getBounds());
+        final Rect bounds = new Rect(displayContent.getWindowConfiguration().getAppBounds());
         if (bounds.width() >= bounds.height()) {
             bounds.inset(/* dx */ dividerSize / 2, /* dy */ 0);
             bounds.right = bounds.centerX();
@@ -870,6 +961,20 @@
         return mActivityRecord.mWmService.mContext.getResources();
     }
 
+    @LetterboxConfiguration.LetterboxVerticalReachabilityPosition
+    int getLetterboxPositionForVerticalReachability() {
+        final boolean isInFullScreenTabletopMode = isDisplayFullScreenAndSeparatingHinge();
+        return mLetterboxConfiguration.getLetterboxPositionForVerticalReachability(
+                isInFullScreenTabletopMode);
+    }
+
+    @LetterboxConfiguration.LetterboxHorizontalReachabilityPosition
+    int getLetterboxPositionForHorizontalReachability() {
+        final boolean isInFullScreenBookMode = isDisplayFullScreenAndSeparatingHinge();
+        return mLetterboxConfiguration.getLetterboxPositionForHorizontalReachability(
+                isInFullScreenBookMode);
+    }
+
     @VisibleForTesting
     void handleHorizontalDoubleTap(int x) {
         if (!isHorizontalReachabilityEnabled() || mActivityRecord.isInTransition()) {
@@ -881,7 +986,8 @@
             return;
         }
 
-        boolean isInFullScreenBookMode = isDisplayFullScreenAndSeparatingHinge();
+        boolean isInFullScreenBookMode = isDisplayFullScreenAndSeparatingHinge()
+                && mLetterboxConfiguration.getIsAutomaticReachabilityInBookModeEnabled();
         int letterboxPositionForHorizontalReachability = mLetterboxConfiguration
                 .getLetterboxPositionForHorizontalReachability(isInFullScreenBookMode);
         if (mLetterbox.getInnerFrame().left > x) {
@@ -961,6 +1067,8 @@
      * </ul>
      */
     private boolean isHorizontalReachabilityEnabled(Configuration parentConfiguration) {
+        // Use screen resolved bounds which uses resolved bounds or size compat bounds
+        // as activity bounds can sometimes be empty
         return mLetterboxConfiguration.getIsHorizontalReachabilityEnabled()
                 && parentConfiguration.windowConfiguration.getWindowingMode()
                         == WINDOWING_MODE_FULLSCREEN
@@ -968,7 +1076,7 @@
                         && mActivityRecord.getOrientationForReachability() == ORIENTATION_PORTRAIT)
                 // Check whether the activity fills the parent vertically.
                 && parentConfiguration.windowConfiguration.getAppBounds().height()
-                        <= mActivityRecord.getBounds().height();
+                        <= mActivityRecord.getScreenResolvedBounds().height();
     }
 
     @VisibleForTesting
@@ -976,6 +1084,10 @@
         return isHorizontalReachabilityEnabled(mActivityRecord.getParent().getConfiguration());
     }
 
+    boolean isLetterboxDoubleTapEducationEnabled() {
+        return isHorizontalReachabilityEnabled() || isVerticalReachabilityEnabled();
+    }
+
     /**
      * Whether vertical reachability is enabled for an activity in the current configuration.
      *
@@ -988,6 +1100,8 @@
      * </ul>
      */
     private boolean isVerticalReachabilityEnabled(Configuration parentConfiguration) {
+        // Use screen resolved bounds which uses resolved bounds or size compat bounds
+        // as activity bounds can sometimes be empty
         return mLetterboxConfiguration.getIsVerticalReachabilityEnabled()
                 && parentConfiguration.windowConfiguration.getWindowingMode()
                         == WINDOWING_MODE_FULLSCREEN
@@ -995,7 +1109,7 @@
                         && mActivityRecord.getOrientationForReachability() == ORIENTATION_LANDSCAPE)
                 // Check whether the activity fills the parent horizontally.
                 && parentConfiguration.windowConfiguration.getBounds().width()
-                        == mActivityRecord.getBounds().width();
+                        == mActivityRecord.getScreenResolvedBounds().width();
     }
 
     @VisibleForTesting
@@ -1005,7 +1119,8 @@
 
     @VisibleForTesting
     boolean shouldShowLetterboxUi(WindowState mainWindow) {
-        return isSurfaceVisible(mainWindow) && mainWindow.areAppWindowBoundsLetterboxed()
+        return (mActivityRecord.isInLetterboxAnimation() || isSurfaceVisible(mainWindow))
+                && mainWindow.areAppWindowBoundsLetterboxed()
                 // Check for FLAG_SHOW_WALLPAPER explicitly instead of using
                 // WindowContainer#showWallpaper because the later will return true when this
                 // activity is using blurred wallpaper for letterbox background.
@@ -1112,7 +1227,7 @@
     // for all corners for consistency and pick a minimal bottom one for consistency with a
     // taskbar rounded corners.
     int getRoundedCornersRadius(final WindowState mainWindow) {
-        if (!requiresRoundedCorners(mainWindow) || mActivityRecord.isInLetterboxAnimation()) {
+        if (!requiresRoundedCorners(mainWindow)) {
             return 0;
         }
 
@@ -1410,7 +1525,8 @@
         mLetterboxConfigListener = WindowContainer.overrideConfigurationPropagation(
                 mActivityRecord, firstOpaqueActivityBeneath,
                 (opaqueConfig, transparentConfig) -> {
-                    final Configuration mutatedConfiguration = new Configuration();
+                    final Configuration mutatedConfiguration =
+                            fromOriginalTranslucentConfig(transparentConfig);
                     final Rect parentBounds = parent.getWindowConfiguration().getBounds();
                     final Rect bounds = mutatedConfiguration.windowConfiguration.getBounds();
                     final Rect letterboxBounds = opaqueConfig.windowConfiguration.getBounds();
@@ -1433,7 +1549,7 @@
      * the first opaque activity beneath.
      */
     boolean hasInheritedLetterboxBehavior() {
-        return mLetterboxConfigListener != null && !mActivityRecord.matchParentBounds();
+        return mLetterboxConfigListener != null;
     }
 
     /**
@@ -1472,6 +1588,10 @@
         return mInheritedCompatDisplayInsets;
     }
 
+    void clearInheritedCompatDisplayInsets() {
+        mInheritedCompatDisplayInsets = null;
+    }
+
     /**
      * In case of translucent activities, it consumes the {@link ActivityRecord} of the first opaque
      * activity beneath using the given consumer and returns {@code true}.
@@ -1498,8 +1618,24 @@
                 true /* traverseTopToBottom */));
     }
 
+    // When overriding translucent activities configuration we need to keep some of the
+    // original properties
+    private Configuration fromOriginalTranslucentConfig(Configuration translucentConfig) {
+        final Configuration configuration = new Configuration(translucentConfig);
+        // The values for the following properties will be defined during the configuration
+        // resolution in {@link ActivityRecord#resolveOverrideConfiguration} using the
+        // properties inherited from the first not finishing opaque activity beneath.
+        configuration.orientation = ORIENTATION_UNDEFINED;
+        configuration.screenWidthDp = configuration.compatScreenWidthDp = SCREEN_WIDTH_DP_UNDEFINED;
+        configuration.screenHeightDp =
+                configuration.compatScreenHeightDp = SCREEN_HEIGHT_DP_UNDEFINED;
+        configuration.smallestScreenWidthDp =
+                configuration.compatSmallestScreenWidthDp = SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
+        return configuration;
+    }
+
     private void inheritConfiguration(ActivityRecord firstOpaque) {
-        // To avoid wrong behaviour, we're not forcing a specific aspet ratio to activities
+        // To avoid wrong behaviour, we're not forcing a specific aspect ratio to activities
         // which are not already providing one (e.g. permission dialogs) and presumably also
         // not resizable.
         if (mActivityRecord.getMinAspectRatio() != UNDEFINED_ASPECT_RATIO) {
@@ -1517,7 +1653,7 @@
         mLetterboxConfigListener = null;
         mInheritedMinAspectRatio = UNDEFINED_ASPECT_RATIO;
         mInheritedMaxAspectRatio = UNDEFINED_ASPECT_RATIO;
-        mInheritedOrientation = Configuration.ORIENTATION_UNDEFINED;
+        mInheritedOrientation = ORIENTATION_UNDEFINED;
         mInheritedAppCompatState = APP_COMPAT_STATE_CHANGED__STATE__UNKNOWN;
         mInheritedCompatDisplayInsets = null;
     }
diff --git a/services/core/java/com/android/server/wm/OWNERS b/services/core/java/com/android/server/wm/OWNERS
index 6602d29..4f506a5 100644
--- a/services/core/java/com/android/server/wm/OWNERS
+++ b/services/core/java/com/android/server/wm/OWNERS
@@ -14,3 +14,6 @@
 tigerhuang@google.com
 lihongyu@google.com
 mariiasand@google.com
+
+per-file BackgroundActivityStartController.java = set noparent
+per-file BackgroundActivityStartController.java = brufino@google.com, ogunwale@google.com, louischang@google.com, lus@google.com, rickywai@google.com
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index 4c5d607..0239b98 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -16,6 +16,8 @@
 
 package com.android.server.wm;
 
+import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
+
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_REMOTE_ANIMATIONS;
 import static com.android.server.wm.AnimationAdapterProto.REMOTE;
 import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
@@ -194,6 +196,13 @@
                                 + " transit=%s, apps=%d, wallpapers=%d, nonApps=%d",
                         AppTransition.appTransitionOldToString(transit), appTargets.length,
                         wallpaperTargets.length, nonAppTargets.length);
+                if (AppTransition.isKeyguardOccludeTransitOld(transit)) {
+                    EventLogTags.writeWmSetKeyguardOccluded(
+                            transit == TRANSIT_OLD_KEYGUARD_UNOCCLUDE ? 0 : 1,
+                            1 /* animate */,
+                            transit,
+                            "onAnimationStart");
+                }
                 mRemoteAnimationAdapter.getRunner().onAnimationStart(transit, appTargets,
                         wallpaperTargets, nonAppTargets, mFinishedCallback);
             } catch (RemoteException e) {
@@ -353,6 +362,11 @@
         final boolean isKeyguardOccluded = mDisplayContent.isKeyguardOccluded();
 
         try {
+            EventLogTags.writeWmSetKeyguardOccluded(
+                    isKeyguardOccluded ? 1 : 0,
+                    0 /* animate */,
+                    0 /* transit */,
+                    "onAnimationCancelled");
             mRemoteAnimationAdapter.getRunner().onAnimationCancelled(isKeyguardOccluded);
         } catch (RemoteException e) {
             Slog.e(TAG, "Failed to notify cancel", e);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index adaaa25..aed876d 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3448,13 +3448,17 @@
                 && info.pictureInPictureParams.isLaunchIntoPip()
                 && top.getLastParentBeforePip() != null)
                         ? top.getLastParentBeforePip().mTaskId : INVALID_TASK_ID;
+        info.lastParentTaskIdBeforePip = top != null && top.getLastParentBeforePip() != null
+                ? top.getLastParentBeforePip().mTaskId : INVALID_TASK_ID;
         info.shouldDockBigOverlays = top != null && top.shouldDockBigOverlays;
         info.mTopActivityLocusId = top != null ? top.getLocusId() : null;
 
         final boolean isTopActivityResumed = top != null
                 && top.getOrganizedTask() == this && top.isState(RESUMED);
-        // Whether the direct top activity is in size compat mode on foreground.
-        info.topActivityInSizeCompat = isTopActivityResumed && top.inSizeCompatMode();
+        final boolean isTopActivityVisible = top != null
+                && top.getOrganizedTask() == this && top.isVisible();
+        // Whether the direct top activity is in size compat mode
+        info.topActivityInSizeCompat = isTopActivityVisible && top.inSizeCompatMode();
         if (info.topActivityInSizeCompat
                 && mWmService.mLetterboxConfiguration.isTranslucentLetterboxingEnabled()) {
             // We hide the restart button in case of transparent activities.
@@ -3475,6 +3479,25 @@
         info.isFocused = isFocused();
         info.isVisible = hasVisibleChildren();
         info.isSleeping = shouldSleepActivities();
+        info.isLetterboxDoubleTapEnabled = top != null
+                && top.mLetterboxUiController.isLetterboxDoubleTapEducationEnabled();
+        info.topActivityLetterboxVerticalPosition = TaskInfo.PROPERTY_VALUE_UNSET;
+        info.topActivityLetterboxHorizontalPosition = TaskInfo.PROPERTY_VALUE_UNSET;
+        info.topActivityLetterboxWidth = TaskInfo.PROPERTY_VALUE_UNSET;
+        info.topActivityLetterboxHeight = TaskInfo.PROPERTY_VALUE_UNSET;
+        if (info.isLetterboxDoubleTapEnabled) {
+            info.topActivityLetterboxWidth = top.getBounds().width();
+            info.topActivityLetterboxHeight = top.getBounds().height();
+            if (info.topActivityLetterboxWidth < info.topActivityLetterboxHeight) {
+                // Pillarboxed
+                info.topActivityLetterboxHorizontalPosition =
+                        top.mLetterboxUiController.getLetterboxPositionForHorizontalReachability();
+            } else {
+                // Letterboxed
+                info.topActivityLetterboxVerticalPosition =
+                        top.mLetterboxUiController.getLetterboxPositionForVerticalReachability();
+            }
+        }
     }
 
     /**
@@ -5884,8 +5907,11 @@
             final int taskId = activity != null
                     ? mTaskSupervisor.getNextTaskIdForUser(activity.mUserId)
                     : mTaskSupervisor.getNextTaskIdForUser();
+            final int activityType = getActivityType();
             task = new Task.Builder(mAtmService)
                     .setTaskId(taskId)
+                    .setActivityType(activityType != ACTIVITY_TYPE_UNDEFINED ? activityType
+                            : ACTIVITY_TYPE_STANDARD)
                     .setActivityInfo(info)
                     .setActivityOptions(options)
                     .setIntent(intent)
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index a2d3e84..f428d3e 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -2243,8 +2243,8 @@
                     // task, because they should not be affected by insets.
                     inOutConfig.smallestScreenWidthDp = (int) (0.5f
                             + Math.min(mTmpFullBounds.width(), mTmpFullBounds.height()) / density);
-                } else if (windowingMode == WINDOWING_MODE_MULTI_WINDOW
-                        && isEmbeddedWithBoundsOverride()) {
+                } else if (windowingMode == WINDOWING_MODE_MULTI_WINDOW && mIsEmbedded
+                        && insideParentBounds && !resolvedBounds.equals(parentBounds)) {
                     // For embedded TFs, the smallest width should be updated. Otherwise, inherit
                     // from the parent task would result in applications loaded wrong resource.
                     inOutConfig.smallestScreenWidthDp =
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index d780cae..267f1c9 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -1106,12 +1106,15 @@
     }
 
     @Override
-    public void setIsIgnoreOrientationRequestDisabled(boolean isDisabled) {
-        enforceTaskPermission("setIsIgnoreOrientationRequestDisabled()");
+    public void setOrientationRequestPolicy(boolean isIgnoreOrientationRequestDisabled,
+            @Nullable int[] fromOrientations, @Nullable int[] toOrientations) {
+        enforceTaskPermission("setOrientationRequestPolicy()");
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
-                mService.mWindowManager.setIsIgnoreOrientationRequestDisabled(isDisabled);
+                mService.mWindowManager
+                        .setOrientationRequestPolicy(isIgnoreOrientationRequestDisabled,
+                                fromOrientations, toOrientations);
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index d18d502..02d3af6 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1440,7 +1440,7 @@
      *         {@link Configuration#ORIENTATION_PORTRAIT},
      *         {@link Configuration#ORIENTATION_UNDEFINED}).
      */
-    @ScreenOrientation
+    @Configuration.Orientation
     int getRequestedConfigurationOrientation() {
         return getRequestedConfigurationOrientation(false /* forDisplay */);
     }
@@ -1458,9 +1458,28 @@
      *         {@link Configuration#ORIENTATION_PORTRAIT},
      *         {@link Configuration#ORIENTATION_UNDEFINED}).
      */
-    @ScreenOrientation
+    @Configuration.Orientation
     int getRequestedConfigurationOrientation(boolean forDisplay) {
-        int requestedOrientation = getOverrideOrientation();
+        return getRequestedConfigurationOrientation(forDisplay, getOverrideOrientation());
+    }
+
+    /**
+     * Gets the configuration orientation by the requested screen orientation
+     *
+     * @param forDisplay whether it is the requested config orientation for display.
+     *                   If {@code true}, we may reverse the requested orientation if the root is
+     *                   different from the display, so that when the display rotates to the
+     *                   reversed orientation, the requested app will be in the requested
+     *                   orientation.
+     * @param requestedOrientation the screen orientation({@link ScreenOrientation}) that is
+     *                   requested
+     * @return orientation in ({@link Configuration#ORIENTATION_LANDSCAPE},
+     *         {@link Configuration#ORIENTATION_PORTRAIT},
+     *         {@link Configuration#ORIENTATION_UNDEFINED}).
+     */
+    @Configuration.Orientation
+    int getRequestedConfigurationOrientation(boolean forDisplay,
+            @ScreenOrientation int requestedOrientation) {
         final RootDisplayArea root = getRootDisplayArea();
         if (forDisplay && root != null && root.isOrientationDifferentFromDisplay()) {
             // Reverse the requested orientation if the orientation of its root is different from
@@ -1470,7 +1489,7 @@
             // (portrait).
             // When an app below the DAG is requesting landscape, it should actually request the
             // display to be portrait, so that the DAG and the app will be in landscape.
-            requestedOrientation = reverseOrientation(getOverrideOrientation());
+            requestedOrientation = reverseOrientation(requestedOrientation);
         }
 
         if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8931d80..ccce558 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -234,6 +234,7 @@
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
 import android.util.TimeUtils;
 import android.util.TypedValue;
 import android.util.proto.ProtoOutputStream;
@@ -624,6 +625,13 @@
     /** List of window currently causing non-system overlay windows to be hidden. */
     private ArrayList<WindowState> mHidingNonSystemOverlayWindows = new ArrayList<>();
 
+    /**
+     * In some cases (e.g. when {@link R.bool.config_reverseDefaultRotation} has value
+     * {@value true}) we need to map some orientation to others. This {@link SparseIntArray}
+     * contains the relation between the source orientation and the one to use.
+     */
+    private final SparseIntArray mOrientationMapping = new SparseIntArray();
+
     final AccessibilityController mAccessibilityController;
     private RecentsAnimationController mRecentsAnimationController;
 
@@ -4147,25 +4155,52 @@
 
     /**
      * Controls whether ignore orientation request logic in {@link DisplayArea} is disabled
-     * at runtime.
+     * at runtime and how to optionally map some requested orientations to others.
      *
      * <p>Note: this assumes that {@link #mGlobalLock} is held by the caller.
      *
-     * @param isDisabled when {@code true}, the system always ignores the value of {@link
-     *                   DisplayArea#getIgnoreOrientationRequest} and app requested orientation is
-     *                   respected.
+     * @param isIgnoreOrientationRequestDisabled when {@code true}, the system always ignores the
+     *                   value of {@link DisplayArea#getIgnoreOrientationRequest} and app requested
+     *                   orientation is respected.
+     * @param fromOrientations The orientations we want to map to the correspondent orientations
+     *                        in toOrientation.
+     * @param toOrientations The orientations we map to the ones in fromOrientations at  the same
+     *                       index
      */
-    void setIsIgnoreOrientationRequestDisabled(boolean isDisabled) {
-        if (isDisabled == mIsIgnoreOrientationRequestDisabled) {
+    void setOrientationRequestPolicy(boolean isIgnoreOrientationRequestDisabled,
+            @Nullable int[] fromOrientations, @Nullable int[] toOrientations) {
+        mOrientationMapping.clear();
+        if (fromOrientations != null && toOrientations != null
+                && fromOrientations.length == toOrientations.length) {
+            for (int i = 0; i < fromOrientations.length; i++) {
+                mOrientationMapping.put(fromOrientations[i], toOrientations[i]);
+            }
+        }
+        if (isIgnoreOrientationRequestDisabled == mIsIgnoreOrientationRequestDisabled) {
             return;
         }
-        mIsIgnoreOrientationRequestDisabled = isDisabled;
+        mIsIgnoreOrientationRequestDisabled = isIgnoreOrientationRequestDisabled;
         for (int i = mRoot.getChildCount() - 1; i >= 0; i--) {
             mRoot.getChildAt(i).onIsIgnoreOrientationRequestDisabledChanged();
         }
     }
 
     /**
+     * When {@link mIsIgnoreOrientationRequestDisabled} is {@value true} this method returns the
+     * orientation to use in place of the one in input. It returns the same requestedOrientation in
+     * input otherwise.
+     *
+     * @param requestedOrientation The orientation that can be mapped.
+     * @return The orientation to use in place of requestedOrientation.
+     */
+    int mapOrientationRequest(int requestedOrientation) {
+        if (!mIsIgnoreOrientationRequestDisabled) {
+            return requestedOrientation;
+        }
+        return mOrientationMapping.get(requestedOrientation, requestedOrientation);
+    }
+
+    /**
      * Whether the system ignores the value of {@link DisplayArea#getIgnoreOrientationRequest} and
      * app requested orientation is respected.
      *
@@ -6198,9 +6233,10 @@
             waitingForConfig = waitingForRemoteDisplayChange = false;
             numOpeningApps = 0;
         }
-        if (waitingForConfig || waitingForRemoteDisplayChange || mAppsFreezingScreen > 0
-                || mWindowsFreezingScreen == WINDOWS_FREEZING_SCREENS_ACTIVE
-                || mClientFreezingScreen || numOpeningApps > 0) {
+        final boolean waitingForApps = mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT
+                && (mAppsFreezingScreen > 0 || numOpeningApps > 0);
+        if (waitingForConfig || waitingForRemoteDisplayChange || waitingForApps
+                || mClientFreezingScreen) {
             ProtoLog.d(WM_DEBUG_ORIENTATION, "stopFreezingDisplayLocked: Returning "
                     + "waitingForConfig=%b, waitingForRemoteDisplayChange=%b, "
                     + "mAppsFreezingScreen=%d, mWindowsFreezingScreen=%d, "
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index a06d84c..adf5310 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -942,6 +942,10 @@
                     runSetBooleanFlag(pw, mLetterboxConfiguration
                             ::setIsVerticalReachabilityEnabled);
                     break;
+                case "--isAutomaticReachabilityInBookModeEnabled":
+                    runSetBooleanFlag(pw, mLetterboxConfiguration
+                            ::setIsAutomaticReachabilityInBookModeEnabled);
+                    break;
                 case "--defaultPositionForHorizontalReachability":
                     runSetLetterboxDefaultPositionForHorizontalReachability(pw);
                     break;
@@ -1144,6 +1148,7 @@
             mLetterboxConfiguration.resetLetterboxHorizontalPositionMultiplier();
             mLetterboxConfiguration.resetIsHorizontalReachabilityEnabled();
             mLetterboxConfiguration.resetIsVerticalReachabilityEnabled();
+            mLetterboxConfiguration.resetEnabledAutomaticReachabilityInBookMode();
             mLetterboxConfiguration.resetDefaultPositionForHorizontalReachability();
             mLetterboxConfiguration.resetDefaultPositionForVerticalReachability();
             mLetterboxConfiguration.resetIsEducationEnabled();
@@ -1179,6 +1184,8 @@
                     + mLetterboxConfiguration.getIsHorizontalReachabilityEnabled());
             pw.println("Is vertical reachability enabled: "
                     + mLetterboxConfiguration.getIsVerticalReachabilityEnabled());
+            pw.println("Is automatic reachability in book mode enabled: "
+                    + mLetterboxConfiguration.getIsAutomaticReachabilityInBookModeEnabled());
             pw.println("Default position for horizontal reachability: "
                     + LetterboxConfiguration.letterboxHorizontalReachabilityPositionToString(
                             mLetterboxConfiguration.getDefaultPositionForHorizontalReachability()));
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index fd47753..6228050 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -131,7 +131,7 @@
      */
     static final int CONTROLLABLE_CONFIGS = ActivityInfo.CONFIG_WINDOW_CONFIGURATION
             | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE | ActivityInfo.CONFIG_SCREEN_SIZE
-            | ActivityInfo.CONFIG_LAYOUT_DIRECTION;
+            | ActivityInfo.CONFIG_LAYOUT_DIRECTION | ActivityInfo.CONFIG_DENSITY;
     static final int CONTROLLABLE_WINDOW_CONFIGS = WINDOW_CONFIG_BOUNDS
             | WindowConfiguration.WINDOW_CONFIG_APP_BOUNDS;
 
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 682918b..0479920 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -40,6 +40,7 @@
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.ActivityTaskManagerService.INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MILLIS;
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
+import static com.android.server.wm.BackgroundActivityStartController.BAL_BLOCK;
 import static com.android.server.wm.WindowManagerService.MY_PID;
 
 import android.Manifest;
@@ -544,15 +545,17 @@
     @HotPath(caller = HotPath.START_SERVICE)
     public boolean areBackgroundFgsStartsAllowed() {
         return areBackgroundActivityStartsAllowed(mAtm.getBalAppSwitchesState(),
-                true /* isCheckingForFgsStart */);
+                true /* isCheckingForFgsStart */) != BAL_BLOCK;
     }
 
-    boolean areBackgroundActivityStartsAllowed(int appSwitchState) {
+    @BackgroundActivityStartController.BalCode
+    int areBackgroundActivityStartsAllowed(int appSwitchState) {
         return areBackgroundActivityStartsAllowed(appSwitchState,
                 false /* isCheckingForFgsStart */);
     }
 
-    private boolean areBackgroundActivityStartsAllowed(int appSwitchState,
+    @BackgroundActivityStartController.BalCode
+    private int areBackgroundActivityStartsAllowed(int appSwitchState,
             boolean isCheckingForFgsStart) {
         return mBgLaunchController.areBackgroundActivityStartsAllowed(mPid, mUid, mInfo.packageName,
                 appSwitchState, isCheckingForFgsStart, hasActivityInVisibleTask(),
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 52f2b63..2d849b3 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2049,16 +2049,19 @@
 
     /**
      * Like isOnScreen(), but we don't return true if the window is part
-     * of a transition that has not yet been started.
+     * of a transition but has not yet started animating.
      */
     boolean isReadyForDisplay() {
-        if (mToken.waitingToShow && getDisplayContent().mAppTransition.isTransitionSet()) {
+        if (!mHasSurface || mDestroying || !isVisibleByPolicy()) {
+            return false;
+        }
+        if (mToken.waitingToShow && getDisplayContent().mAppTransition.isTransitionSet()
+                && !isAnimating(TRANSITION | PARENTS, ANIMATION_TYPE_APP_TRANSITION)) {
             return false;
         }
         final boolean parentAndClientVisible = !isParentWindowHidden()
                 && mViewVisibility == View.VISIBLE && mToken.isVisible();
-        return mHasSurface && isVisibleByPolicy() && !mDestroying
-                && (parentAndClientVisible || isAnimating(TRANSITION | PARENTS));
+        return parentAndClientVisible || isAnimating(TRANSITION | PARENTS, ANIMATION_TYPE_ALL);
     }
 
     boolean isFullyTransparent() {
@@ -4577,7 +4580,7 @@
 
     void requestUpdateWallpaperIfNeeded() {
         final DisplayContent dc = getDisplayContent();
-        if (dc != null && hasWallpaper()) {
+        if (dc != null && ((mIsWallpaper && !mLastConfigReportedToClient) || hasWallpaper())) {
             dc.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
             dc.setLayoutNeeded();
             mWmService.mWindowPlacerLocked.requestTraversal();
diff --git a/services/people/java/com/android/server/people/data/ContactsQueryHelper.java b/services/people/java/com/android/server/people/data/ContactsQueryHelper.java
index 0993295..2505abf2 100644
--- a/services/people/java/com/android/server/people/data/ContactsQueryHelper.java
+++ b/services/people/java/com/android/server/people/data/ContactsQueryHelper.java
@@ -152,6 +152,8 @@
             }
         } catch (SQLiteException exception) {
             Slog.w("SQLite exception when querying contacts.", exception);
+        } catch (IllegalArgumentException exception) {
+            Slog.w("Illegal Argument exception when querying contacts.", exception);
         }
         if (found && lookupKey != null && hasPhoneNumber) {
             return queryPhoneNumber(lookupKey);
diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java
index eff9e8d..872734f 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -129,7 +129,6 @@
     private final List<PeopleService.ConversationsListener> mConversationsListeners =
             new ArrayList<>(1);
     private final Handler mHandler;
-
     private ContentObserver mCallLogContentObserver;
     private ContentObserver mMmsSmsContentObserver;
 
@@ -1106,6 +1105,7 @@
                 @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
             mInjector.getBackgroundExecutor().execute(() -> {
                 PackageData packageData = getPackage(packageName, user.getIdentifier());
+                boolean hasCachedShortcut = false;
                 for (ShortcutInfo shortcut : shortcuts) {
                     if (ShortcutHelper.isConversationShortcut(
                             shortcut, mShortcutServiceInternal, user.getIdentifier())) {
@@ -1114,15 +1114,18 @@
                                     ? packageData.getConversationInfo(shortcut.getId()) : null;
                             if (conversationInfo == null
                                     || !conversationInfo.isShortcutCachedForNotification()) {
-                                // This is a newly cached shortcut. Clean up the existing cached
-                                // shortcuts to ensure the cache size is under the limit.
-                                cleanupCachedShortcuts(user.getIdentifier(),
-                                        MAX_CACHED_RECENT_SHORTCUTS - 1);
+                                hasCachedShortcut = true;
                             }
                         }
                         addOrUpdateConversationInfo(shortcut);
                     }
                 }
+                // Added at least one new conversation. Uncache older existing cached
+                // shortcuts to ensure the cache size is under the limit.
+                if (hasCachedShortcut) {
+                    cleanupCachedShortcuts(user.getIdentifier(),
+                            MAX_CACHED_RECENT_SHORTCUTS);
+                }
             });
         }
 
diff --git a/services/tests/mockingservicestests/src/android/service/dreams/DreamOverlayConnectionHandlerTest.java b/services/tests/mockingservicestests/src/android/service/dreams/DreamOverlayConnectionHandlerTest.java
new file mode 100644
index 0000000..22d7e73
--- /dev/null
+++ b/services/tests/mockingservicestests/src/android/service/dreams/DreamOverlayConnectionHandlerTest.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.dreams;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.test.TestLooper;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.util.ObservableServiceConnection;
+import com.android.internal.util.PersistentServiceConnection;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DreamOverlayConnectionHandlerTest {
+    private static final int MIN_CONNECTION_DURATION_MS = 100;
+    private static final int MAX_RECONNECT_ATTEMPTS = 3;
+    private static final int BASE_RECONNECT_DELAY_MS = 50;
+
+    @Mock
+    private Context mContext;
+    @Mock
+    private PersistentServiceConnection<IDreamOverlay> mConnection;
+    @Mock
+    private Intent mServiceIntent;
+    @Mock
+    private IDreamOverlay mOverlayService;
+    @Mock
+    private IDreamOverlayClient mOverlayClient;
+
+    private TestLooper mTestLooper;
+    private DreamOverlayConnectionHandler mDreamOverlayConnectionHandler;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mTestLooper = new TestLooper();
+        mDreamOverlayConnectionHandler = new DreamOverlayConnectionHandler(
+                mContext,
+                mTestLooper.getLooper(),
+                mServiceIntent,
+                MIN_CONNECTION_DURATION_MS,
+                MAX_RECONNECT_ATTEMPTS,
+                BASE_RECONNECT_DELAY_MS,
+                new TestInjector(mConnection));
+    }
+
+    @Test
+    public void consumerShouldRunImmediatelyWhenClientAvailable() throws RemoteException {
+        mDreamOverlayConnectionHandler.bind();
+        connectService();
+        provideClient();
+
+        final Consumer<IDreamOverlayClient> consumer = Mockito.mock(Consumer.class);
+        mDreamOverlayConnectionHandler.addConsumer(consumer);
+        mTestLooper.dispatchAll();
+        verify(consumer).accept(mOverlayClient);
+    }
+
+    @Test
+    public void consumerShouldRunAfterClientAvailable() throws RemoteException {
+        mDreamOverlayConnectionHandler.bind();
+        connectService();
+
+        final Consumer<IDreamOverlayClient> consumer = Mockito.mock(Consumer.class);
+        mDreamOverlayConnectionHandler.addConsumer(consumer);
+        mTestLooper.dispatchAll();
+        // No client yet, so we shouldn't have executed
+        verify(consumer, never()).accept(mOverlayClient);
+
+        provideClient();
+        mTestLooper.dispatchAll();
+        verify(consumer).accept(mOverlayClient);
+    }
+
+    @Test
+    public void consumerShouldNeverRunIfClientConnectsAndDisconnects() throws RemoteException {
+        mDreamOverlayConnectionHandler.bind();
+        connectService();
+
+        final Consumer<IDreamOverlayClient> consumer = Mockito.mock(Consumer.class);
+        mDreamOverlayConnectionHandler.addConsumer(consumer);
+        mTestLooper.dispatchAll();
+        // No client yet, so we shouldn't have executed
+        verify(consumer, never()).accept(mOverlayClient);
+
+        provideClient();
+        // Service disconnected before looper could handle the message.
+        disconnectService();
+        mTestLooper.dispatchAll();
+        verify(consumer, never()).accept(mOverlayClient);
+    }
+
+    @Test
+    public void consumerShouldNeverRunIfUnbindCalled() throws RemoteException {
+        mDreamOverlayConnectionHandler.bind();
+        connectService();
+        provideClient();
+
+        final Consumer<IDreamOverlayClient> consumer = Mockito.mock(Consumer.class);
+        mDreamOverlayConnectionHandler.addConsumer(consumer);
+        mDreamOverlayConnectionHandler.unbind();
+        mTestLooper.dispatchAll();
+        // We unbinded immediately after adding consumer, so should never have run.
+        verify(consumer, never()).accept(mOverlayClient);
+    }
+
+    @Test
+    public void consumersOnlyRunOnceIfUnbound() throws RemoteException {
+        mDreamOverlayConnectionHandler.bind();
+        connectService();
+        provideClient();
+
+        AtomicInteger counter = new AtomicInteger();
+        // Add 10 consumers in a row which call unbind within the consumer.
+        for (int i = 0; i < 10; i++) {
+            mDreamOverlayConnectionHandler.addConsumer(client -> {
+                counter.getAndIncrement();
+                mDreamOverlayConnectionHandler.unbind();
+            });
+        }
+        mTestLooper.dispatchAll();
+        // Only the first consumer should have run, since we unbinded.
+        assertThat(counter.get()).isEqualTo(1);
+    }
+
+    @Test
+    public void consumerShouldRunAgainAfterReconnect() throws RemoteException {
+        mDreamOverlayConnectionHandler.bind();
+        connectService();
+        provideClient();
+
+        final Consumer<IDreamOverlayClient> consumer = Mockito.mock(Consumer.class);
+        mDreamOverlayConnectionHandler.addConsumer(consumer);
+        mTestLooper.dispatchAll();
+        verify(consumer, times(1)).accept(mOverlayClient);
+
+        disconnectService();
+        mTestLooper.dispatchAll();
+        // No new calls should happen when service disconnected.
+        verify(consumer, times(1)).accept(mOverlayClient);
+
+        connectService();
+        provideClient();
+        mTestLooper.dispatchAll();
+        // We should trigger the consumer again once the server reconnects.
+        verify(consumer, times(2)).accept(mOverlayClient);
+    }
+
+    @Test
+    public void consumerShouldNeverRunIfRemovedImmediately() throws RemoteException {
+        mDreamOverlayConnectionHandler.bind();
+        connectService();
+        provideClient();
+
+        final Consumer<IDreamOverlayClient> consumer = Mockito.mock(Consumer.class);
+        mDreamOverlayConnectionHandler.addConsumer(consumer);
+        mDreamOverlayConnectionHandler.removeConsumer(consumer);
+        mTestLooper.dispatchAll();
+        verify(consumer, never()).accept(mOverlayClient);
+    }
+
+    private void connectService() {
+        final ObservableServiceConnection.Callback<IDreamOverlay> callback =
+                captureConnectionCallback();
+        callback.onConnected(mConnection, mOverlayService);
+    }
+
+    private void disconnectService() {
+        final ObservableServiceConnection.Callback<IDreamOverlay> callback =
+                captureConnectionCallback();
+        callback.onDisconnected(mConnection, /* reason= */ 0);
+    }
+
+    private void provideClient() throws RemoteException {
+        final IDreamOverlayClientCallback callback = captureClientCallback();
+        callback.onDreamOverlayClient(mOverlayClient);
+    }
+
+    private ObservableServiceConnection.Callback<IDreamOverlay> captureConnectionCallback() {
+        ArgumentCaptor<ObservableServiceConnection.Callback<IDreamOverlay>>
+                callbackCaptor =
+                ArgumentCaptor.forClass(ObservableServiceConnection.Callback.class);
+        verify(mConnection).addCallback(callbackCaptor.capture());
+        return callbackCaptor.getValue();
+    }
+
+    private IDreamOverlayClientCallback captureClientCallback() throws RemoteException {
+        ArgumentCaptor<IDreamOverlayClientCallback> callbackCaptor =
+                ArgumentCaptor.forClass(IDreamOverlayClientCallback.class);
+        verify(mOverlayService, atLeastOnce()).getClient(callbackCaptor.capture());
+        return callbackCaptor.getValue();
+    }
+
+    static class TestInjector extends DreamOverlayConnectionHandler.Injector {
+        private final PersistentServiceConnection<IDreamOverlay> mConnection;
+
+        TestInjector(PersistentServiceConnection<IDreamOverlay> connection) {
+            mConnection = connection;
+        }
+
+        @Override
+        public PersistentServiceConnection<IDreamOverlay> buildConnection(Context context,
+                Handler handler, Intent serviceIntent, int minConnectionDurationMs,
+                int maxReconnectAttempts, int baseReconnectDelayMs) {
+            return mConnection;
+        }
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
index 2baa1ec..8d9c592 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
@@ -1079,14 +1079,16 @@
 
         mCachedAppOptimizerUnderTest.mLastCompactionStats.clear();
 
-        // We force a some compaction
-        mCachedAppOptimizerUnderTest.compactAppSome(processRecord, true);
-        waitForHandler();
-        // then process is compacted.
-        String executedCompactAction =
+        if (CachedAppOptimizer.ENABLE_FILE_COMPACT) {
+            // We force a some compaction
+            mCachedAppOptimizerUnderTest.compactAppSome(processRecord, true);
+            waitForHandler();
+            // then process is compacted.
+            String executedCompactAction =
                 compactActionIntToString(processRecord.mOptRecord.getLastCompactAction());
-        assertThat(executedCompactAction)
+            assertThat(executedCompactAction)
                 .isEqualTo(mCachedAppOptimizerUnderTest.mCompactActionSome);
+        }
     }
 
     private void setFlag(String key, String value, boolean defaultValue) throws Exception {
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
index 82236bf..5f67b6e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -576,6 +576,40 @@
     }
 
     @Test
+    public void testAfterDisplayStateChanges_committedSetAfterState() throws Exception {
+        FakeDisplay display = new FakeDisplay(PORT_A);
+        setUpDisplay(display);
+        updateAvailableDisplays();
+        mAdapter.registerLocked();
+        waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+        assertThat(mListener.addedDisplays.size()).isEqualTo(1);
+        DisplayDevice displayDevice = mListener.addedDisplays.get(0);
+
+        // Turn off.
+        Runnable changeStateRunnable = displayDevice.requestDisplayStateLocked(Display.STATE_OFF, 0,
+                0);
+        waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+        assertThat(mListener.changedDisplays.size()).isEqualTo(1);
+        mListener.changedDisplays.clear();
+        assertThat(displayDevice.getDisplayDeviceInfoLocked().state).isEqualTo(Display.STATE_OFF);
+        assertThat(displayDevice.getDisplayDeviceInfoLocked().committedState).isNotEqualTo(
+                Display.STATE_OFF);
+        verify(mSurfaceControlProxy, never()).setDisplayPowerMode(display.token, Display.STATE_OFF);
+
+        // Execute powerstate change.
+        changeStateRunnable.run();
+        waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+
+
+        // Verify that committed triggered a new change event and is set correctly.
+        verify(mSurfaceControlProxy, never()).setDisplayPowerMode(display.token, Display.STATE_OFF);
+        assertThat(mListener.changedDisplays.size()).isEqualTo(1);
+        assertThat(displayDevice.getDisplayDeviceInfoLocked().state).isEqualTo(Display.STATE_OFF);
+        assertThat(displayDevice.getDisplayDeviceInfoLocked().committedState).isEqualTo(
+                Display.STATE_OFF);
+    }
+
+    @Test
     public void testAfterDisplayChange_GameContentTypeSupportIsUpdated() throws Exception {
         FakeDisplay display = new FakeDisplay(PORT_A);
         display.dynamicInfo.gameContentTypeSupported = true;
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
index 30ec163..881d1b3 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
@@ -18,6 +18,7 @@
 
 import static android.database.sqlite.SQLiteDatabase.deleteDatabase;
 
+import static org.mockito.ArgumentMatchers.contains;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Matchers.anyInt;
@@ -708,6 +709,41 @@
     }
 
     @SmallTest
+    public void testStartAddAccountSessionWhereAuthenticatorReturnsIntentWithProhibitedFlags()
+            throws Exception {
+        unlockSystemUser();
+        ResolveInfo resolveInfo = new ResolveInfo();
+        resolveInfo.activityInfo = new ActivityInfo();
+        resolveInfo.activityInfo.applicationInfo = new ApplicationInfo();
+        when(mMockPackageManager.resolveActivityAsUser(
+                any(Intent.class), anyInt(), anyInt())).thenReturn(resolveInfo);
+        when(mMockPackageManager.checkSignatures(
+                anyInt(), anyInt())).thenReturn(PackageManager.SIGNATURE_MATCH);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        Response response = new Response(latch, mMockAccountManagerResponse);
+        Bundle options = createOptionsWithAccountName(
+                AccountManagerServiceTestFixtures.ACCOUNT_NAME_INTERVENE);
+        int prohibitedFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION
+                | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+                | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
+                | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION;
+        options.putInt(AccountManagerServiceTestFixtures.KEY_INTENT_FLAGS, prohibitedFlags);
+
+        mAms.startAddAccountSession(
+                response, // response
+                AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType
+                "authTokenType",
+                null, // requiredFeatures
+                true, // expectActivityLaunch
+                options); // optionsIn
+        waitForLatch(latch);
+
+        verify(mMockAccountManagerResponse).onError(
+                eq(AccountManager.ERROR_CODE_INVALID_RESPONSE), contains("invalid intent"));
+    }
+
+    @SmallTest
     public void testStartAddAccountSessionError() throws Exception {
         unlockSystemUser();
         Bundle options = createOptionsWithAccountName(
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java
index 73f30d9..b98a6a8 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java
@@ -17,9 +17,6 @@
 
 import android.accounts.Account;
 
-import java.util.ArrayList;
-import java.util.List;
-
 /**
  * Constants shared between test AccountAuthenticators and AccountManagerServiceTest.
  */
@@ -31,6 +28,8 @@
             "account_manager_service_test:account_status_token_key";
     public static final String KEY_ACCOUNT_PASSWORD =
             "account_manager_service_test:account_password_key";
+    public static final String KEY_INTENT_FLAGS =
+            "account_manager_service_test:intent_flags_key";
     public static final String KEY_OPTIONS_BUNDLE =
             "account_manager_service_test:option_bundle_key";
     public static final String ACCOUNT_NAME_SUCCESS = "success_on_return@fixture.com";
diff --git a/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java b/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java
index 8106364..924443e 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java
@@ -24,8 +24,6 @@
 import android.content.Intent;
 import android.os.Bundle;
 
-import com.android.frameworks.servicestests.R;
-
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
@@ -270,11 +268,13 @@
         String accountName = null;
         Bundle sessionBundle = null;
         String password = null;
+        int intentFlags = 0;
         if (options != null) {
             accountName = options.getString(AccountManagerServiceTestFixtures.KEY_ACCOUNT_NAME);
             sessionBundle = options.getBundle(
                     AccountManagerServiceTestFixtures.KEY_ACCOUNT_SESSION_BUNDLE);
             password = options.getString(AccountManagerServiceTestFixtures.KEY_ACCOUNT_PASSWORD);
+            intentFlags = options.getInt(AccountManagerServiceTestFixtures.KEY_INTENT_FLAGS, 0);
         }
 
         Bundle result = new Bundle();
@@ -302,6 +302,7 @@
             intent.putExtra(AccountManagerServiceTestFixtures.KEY_RESULT,
                     eventualActivityResultData);
             intent.putExtra(AccountManagerServiceTestFixtures.KEY_CALLBACK, response);
+            intent.setFlags(intentFlags);
 
             result.putParcelable(AccountManager.KEY_INTENT, intent);
         } else {
diff --git a/services/tests/servicestests/src/com/android/server/audio/SpatializerHelperTest.java b/services/tests/servicestests/src/com/android/server/audio/SpatializerHelperTest.java
index 428eaff..dea31d7 100644
--- a/services/tests/servicestests/src/com/android/server/audio/SpatializerHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/SpatializerHelperTest.java
@@ -56,7 +56,9 @@
         mSpyAudioSystem = spy(new NoOpAudioSystemAdapter());
 
         mSpatHelper = new SpatializerHelper(mMockAudioService, mSpyAudioSystem,
-                false /*headTrackingEnabledByDefault*/);
+                true /*binauralEnabledDefault*/,
+                true /*transauralEnabledDefault*/,
+                false /*headTrackingEnabledDefault*/);
     }
 
     /**
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
index ff37564..58f3db9 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -1905,7 +1905,7 @@
         // We don't expect any interaction with DeviceConfig when the director is initialized
         // because we explicitly avoid doing this as this can lead to a latency spike in the
         // startup of DisplayManagerService
-        // Verify all the loaded values are from DisplayDeviceConfig
+        // Verify all the loaded values are from config.xml
         assertEquals(director.getSettingsObserver().getDefaultRefreshRate(), 45, 0.0);
         assertEquals(director.getSettingsObserver().getDefaultPeakRefreshRate(), 75,
                 0.0);
@@ -1937,6 +1937,7 @@
         when(displayDeviceConfig.getDefaultRefreshRateInHbmSunlight()).thenReturn(75);
         director.defaultDisplayDeviceUpdated(displayDeviceConfig);
 
+        // Verify the new values are from the freshly loaded DisplayDeviceConfig.
         assertEquals(director.getSettingsObserver().getDefaultRefreshRate(), 60, 0.0);
         assertEquals(director.getSettingsObserver().getDefaultPeakRefreshRate(), 65,
                 0.0);
@@ -1966,6 +1967,7 @@
         config.setRefreshRateInHbmSunlight(80);
         director.defaultDisplayDeviceUpdated(displayDeviceConfig);
 
+        // Verify the values are loaded from the DeviceConfig.
         assertEquals(director.getSettingsObserver().getDefaultRefreshRate(), 60, 0.0);
         assertEquals(director.getSettingsObserver().getDefaultPeakRefreshRate(), 60,
                 0.0);
@@ -1981,6 +1983,35 @@
                 new int[]{20});
         assertEquals(director.getHbmObserver().getRefreshRateInHbmHdr(), 70);
         assertEquals(director.getHbmObserver().getRefreshRateInHbmSunlight(), 80);
+
+        // Reset the DeviceConfig
+        config.setDefaultPeakRefreshRate(null);
+        config.setRefreshRateInHighZone(null);
+        config.setRefreshRateInLowZone(null);
+        config.setLowAmbientBrightnessThresholds(new int[]{});
+        config.setLowDisplayBrightnessThresholds(new int[]{});
+        config.setHighDisplayBrightnessThresholds(new int[]{});
+        config.setHighAmbientBrightnessThresholds(new int[]{});
+        config.setRefreshRateInHbmHdr(null);
+        config.setRefreshRateInHbmSunlight(null);
+        waitForIdleSync();
+
+        // verify the new values now fallback to DisplayDeviceConfig
+        assertEquals(director.getSettingsObserver().getDefaultRefreshRate(), 60, 0.0);
+        assertEquals(director.getSettingsObserver().getDefaultPeakRefreshRate(), 65,
+                0.0);
+        assertEquals(director.getBrightnessObserver().getRefreshRateInHighZone(), 55);
+        assertEquals(director.getBrightnessObserver().getRefreshRateInLowZone(), 50);
+        assertArrayEquals(director.getBrightnessObserver().getHighDisplayBrightnessThreshold(),
+                new int[]{210});
+        assertArrayEquals(director.getBrightnessObserver().getHighAmbientBrightnessThreshold(),
+                new int[]{2100});
+        assertArrayEquals(director.getBrightnessObserver().getLowDisplayBrightnessThreshold(),
+                new int[]{25});
+        assertArrayEquals(director.getBrightnessObserver().getLowAmbientBrightnessThreshold(),
+                new int[]{30});
+        assertEquals(director.getHbmObserver().getRefreshRateInHbmHdr(), 65);
+        assertEquals(director.getHbmObserver().getRefreshRateInHbmSunlight(), 75);
     }
 
     @Test
@@ -2140,18 +2171,18 @@
             super.addOnPropertiesChangedListener(namespace, executor, listener);
         }
 
-        void setRefreshRateInLowZone(int fps) {
+        void setRefreshRateInLowZone(Integer fps) {
             putPropertyAndNotify(
                     DeviceConfig.NAMESPACE_DISPLAY_MANAGER, KEY_REFRESH_RATE_IN_LOW_ZONE,
                     String.valueOf(fps));
         }
 
-        void setRefreshRateInHbmSunlight(int fps) {
+        void setRefreshRateInHbmSunlight(Integer fps) {
             putPropertyAndNotify(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
                     KEY_REFRESH_RATE_IN_HBM_SUNLIGHT, String.valueOf(fps));
         }
 
-        void setRefreshRateInHbmHdr(int fps) {
+        void setRefreshRateInHbmHdr(Integer fps) {
             putPropertyAndNotify(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
                     KEY_REFRESH_RATE_IN_HBM_HDR, String.valueOf(fps));
         }
@@ -2187,13 +2218,13 @@
                     thresholds);
         }
 
-        void setRefreshRateInHighZone(int fps) {
+        void setRefreshRateInHighZone(Integer fps) {
             putPropertyAndNotify(
                     DeviceConfig.NAMESPACE_DISPLAY_MANAGER, KEY_REFRESH_RATE_IN_HIGH_ZONE,
                     String.valueOf(fps));
         }
 
-        void setDefaultPeakRefreshRate(int fps) {
+        void setDefaultPeakRefreshRate(Integer fps) {
             putPropertyAndNotify(
                     DeviceConfig.NAMESPACE_DISPLAY_MANAGER, KEY_PEAK_REFRESH_RATE_DEFAULT,
                     String.valueOf(fps));
diff --git a/services/tests/servicestests/src/com/android/server/display/PersistentDataStoreTest.java b/services/tests/servicestests/src/com/android/server/display/PersistentDataStoreTest.java
index 35a677e..817b245 100644
--- a/services/tests/servicestests/src/com/android/server/display/PersistentDataStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/PersistentDataStoreTest.java
@@ -377,6 +377,33 @@
         assertTrue(Float.isNaN(mDataStore.getBrightness(testDisplayDevice)));
     }
 
+    @Test
+    public void testStoreAndRestoreBrightnessNitsForDefaultDisplay() {
+        float brightnessNitsForDefaultDisplay = 190;
+        mDataStore.loadIfNeeded();
+        mDataStore.setBrightnessNitsForDefaultDisplay(brightnessNitsForDefaultDisplay);
+
+        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        mInjector.setWriteStream(baos);
+        mDataStore.saveIfNeeded();
+        mTestLooper.dispatchAll();
+        assertTrue(mInjector.wasWriteSuccessful());
+        TestInjector newInjector = new TestInjector();
+        PersistentDataStore newDataStore = new PersistentDataStore(newInjector);
+        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+        newInjector.setReadStream(bais);
+        newDataStore.loadIfNeeded();
+        assertEquals(brightnessNitsForDefaultDisplay,
+                mDataStore.getBrightnessNitsForDefaultDisplay(), 0);
+        assertEquals(brightnessNitsForDefaultDisplay,
+                newDataStore.getBrightnessNitsForDefaultDisplay(), 0);
+    }
+
+    @Test
+    public void testInitialBrightnessNitsForDefaultDisplay() {
+        mDataStore.loadIfNeeded();
+        assertEquals(-1, mDataStore.getBrightnessNitsForDefaultDisplay(), 0);
+    }
 
     public class TestInjector extends PersistentDataStore.Injector {
         private InputStream mReadStream;
diff --git a/services/tests/servicestests/src/com/android/server/dreams/DreamOverlayServiceTest.java b/services/tests/servicestests/src/com/android/server/dreams/DreamOverlayServiceTest.java
index 6c73f71..851d8f9 100644
--- a/services/tests/servicestests/src/com/android/server/dreams/DreamOverlayServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/dreams/DreamOverlayServiceTest.java
@@ -18,6 +18,8 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 
@@ -39,10 +41,13 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
+import java.util.concurrent.Executor;
+
 /**
  * A collection of tests to exercise {@link DreamOverlayService}.
  */
@@ -60,6 +65,9 @@
     @Mock
     IDreamOverlayCallback mOverlayCallback;
 
+    @Mock
+    Executor mExecutor;
+
     /**
      * {@link TestDreamOverlayService} is a simple {@link DreamOverlayService} implementation for
      * tracking interactions across {@link IDreamOverlay} binder interface. The service reports
@@ -78,8 +86,8 @@
 
         private final Monitor mMonitor;
 
-        TestDreamOverlayService(Monitor monitor) {
-            super();
+        TestDreamOverlayService(Monitor monitor, Executor executor) {
+            super(executor);
             mMonitor = monitor;
         }
 
@@ -118,13 +126,63 @@
     }
 
     /**
+     * Verifies that callbacks for subclasses are run on the provided executor.
+     */
+    @Test
+    public void testCallbacksRunOnExecutor() throws RemoteException {
+        final TestDreamOverlayService.Monitor monitor = Mockito.mock(
+                TestDreamOverlayService.Monitor.class);
+        final TestDreamOverlayService service = new TestDreamOverlayService(monitor, mExecutor);
+        final IBinder binder = service.onBind(new Intent());
+        final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(binder);
+
+        final IDreamOverlayClient client = getClient(overlay);
+
+        // Start the dream.
+        client.startDream(mLayoutParams, mOverlayCallback,
+                FIRST_DREAM_COMPONENT.flattenToString(), false);
+
+        // The callback should not have run yet.
+        verify(monitor, never()).onStartDream();
+
+        // Run the Runnable sent to the executor.
+        ArgumentCaptor<Runnable> mRunnableCaptor = ArgumentCaptor.forClass(Runnable.class);
+        verify(mExecutor).execute(mRunnableCaptor.capture());
+        mRunnableCaptor.getValue().run();
+
+        // Callback is run.
+        verify(monitor).onStartDream();
+
+        // Verify onWakeUp is run on the executor.
+        client.wakeUp();
+        verify(monitor, never()).onWakeUp();
+        mRunnableCaptor = ArgumentCaptor.forClass(Runnable.class);
+        verify(mExecutor).execute(mRunnableCaptor.capture());
+        mRunnableCaptor.getValue().run();
+        verify(monitor).onWakeUp();
+
+        // Verify onEndDream is run on the executor.
+        client.endDream();
+        verify(monitor, never()).onEndDream();
+        mRunnableCaptor = ArgumentCaptor.forClass(Runnable.class);
+        verify(mExecutor).execute(mRunnableCaptor.capture());
+        mRunnableCaptor.getValue().run();
+        verify(monitor).onEndDream();
+    }
+
+    /**
      * Verifies that only the currently started dream is able to affect the overlay.
      */
     @Test
     public void testOverlayClientInteraction() throws RemoteException {
+        doAnswer(invocation -> {
+            ((Runnable) invocation.getArgument(0)).run();
+            return null;
+        }).when(mExecutor).execute(any());
+
         final TestDreamOverlayService.Monitor monitor = Mockito.mock(
                 TestDreamOverlayService.Monitor.class);
-        final TestDreamOverlayService service = new TestDreamOverlayService(monitor);
+        final TestDreamOverlayService service = new TestDreamOverlayService(monitor, mExecutor);
         final IBinder binder = service.onBind(new Intent());
         final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(binder);
 
diff --git a/services/tests/servicestests/src/com/android/server/dreams/OWNERS b/services/tests/servicestests/src/com/android/server/dreams/OWNERS
new file mode 100644
index 0000000..2f19cf5
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/dreams/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/service/dreams/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/media/projection/OWNERS b/services/tests/servicestests/src/com/android/server/media/projection/OWNERS
new file mode 100644
index 0000000..832bcd9
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/media/projection/OWNERS
@@ -0,0 +1 @@
+include /media/java/android/media/projection/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/people/data/ContactsQueryHelperTest.java b/services/tests/servicestests/src/com/android/server/people/data/ContactsQueryHelperTest.java
index 299f153..16a02b6 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/ContactsQueryHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/ContactsQueryHelperTest.java
@@ -91,8 +91,16 @@
     }
 
     @Test
-    public void testQueryException_returnsFalse() {
-        contentProvider.setThrowException(true);
+    public void testQuerySQLiteException_returnsFalse() {
+        contentProvider.setThrowSQLiteException(true);
+
+        Uri contactUri = Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, CONTACT_LOOKUP_KEY);
+        assertFalse(mHelper.query(contactUri.toString()));
+    }
+
+    @Test
+    public void testQueryIllegalArgumentException_returnsFalse() {
+        contentProvider.setThrowIllegalArgumentException(true);
 
         Uri contactUri = Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, CONTACT_LOOKUP_KEY);
         assertFalse(mHelper.query(contactUri.toString()));
@@ -178,14 +186,18 @@
     private class ContactsContentProvider extends MockContentProvider {
 
         private Map<Uri, Cursor> mUriPrefixToCursorMap = new ArrayMap<>();
-        private boolean throwException = false;
+        private boolean mThrowSQLiteException = false;
+        private boolean mThrowIllegalArgumentException = false;
 
         @Override
         public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
                 String sortOrder) {
-            if (throwException) {
+            if (mThrowSQLiteException) {
                 throw new SQLiteException();
             }
+            if (mThrowIllegalArgumentException) {
+                throw new IllegalArgumentException();
+            }
 
             for (Uri prefixUri : mUriPrefixToCursorMap.keySet()) {
                 if (uri.isPathPrefixMatch(prefixUri)) {
@@ -195,8 +207,12 @@
             return mUriPrefixToCursorMap.get(uri);
         }
 
-        public void setThrowException(boolean throwException) {
-            this.throwException = throwException;
+        public void setThrowSQLiteException(boolean throwException) {
+            this.mThrowSQLiteException = throwException;
+        }
+
+        public void setThrowIllegalArgumentException(boolean throwException) {
+            this.mThrowIllegalArgumentException = throwException;
         }
 
         private void registerCursor(Uri uriPrefix, Cursor cursor) {
diff --git a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
index b921838..4c0361d 100644
--- a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
+++ b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
@@ -263,7 +263,7 @@
                 + instrumentation.getContext().getUserId() + " " + RoleManager.ROLE_HOME + " "
                 + packageName + " 0");
         waitUntil("Failed to get shortcut access",
-                () -> hasShortcutAccess(instrumentation, packageName), 20);
+                () -> hasShortcutAccess(instrumentation, packageName), 60);
     }
 
     public static void setDefaultLauncher(Instrumentation instrumentation, Context packageContext) {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 96e2a09..874846d 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -18,6 +18,8 @@
 
 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
+import static android.app.ActivityManagerInternal.ServiceNotificationPolicy.NOT_FOREGROUND_SERVICE;
+import static android.app.ActivityManagerInternal.ServiceNotificationPolicy.SHOW_IMMEDIATELY;
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.app.Notification.FLAG_AUTO_CANCEL;
 import static android.app.Notification.FLAG_BUBBLE;
@@ -1160,6 +1162,8 @@
     public void testEnqueuedBlockedNotifications_appBlockedChannelForegroundService()
             throws Exception {
         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
+        when(mAmi.applyForegroundServiceNotification(
+                any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY);
 
         NotificationChannel channel = new NotificationChannel("blocked", "name",
                 NotificationManager.IMPORTANCE_NONE);
@@ -1182,6 +1186,8 @@
     public void testEnqueuedBlockedNotifications_userBlockedChannelForegroundService()
             throws Exception {
         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
+        when(mAmi.applyForegroundServiceNotification(
+                any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY);
 
         NotificationChannel channel =
                 new NotificationChannel("blockedbyuser", "name", IMPORTANCE_HIGH);
@@ -1261,6 +1267,8 @@
     public void testEnqueuedBlockedNotifications_blockedAppForegroundService() throws Exception {
         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
         when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
+        when(mAmi.applyForegroundServiceNotification(
+                any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY);
 
         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
@@ -1590,6 +1598,10 @@
 
     @Test
     public void testEnqueueNotificationWithTag_FgsAddsFlags_dismissalAllowed() throws Exception {
+        when(mAmi.applyForegroundServiceNotification(
+                any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY);
+        mContext.getTestablePermissions().setPermission(
+                android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED);
         DeviceConfig.setProperty(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 SystemUiDeviceConfigFlags.TASK_MANAGER_ENABLED,
@@ -1618,6 +1630,10 @@
 
     @Test
     public void testEnqueueNotificationWithTag_FGSaddsFlags_dismissalNotAllowed() throws Exception {
+        when(mAmi.applyForegroundServiceNotification(
+                any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY);
+        mContext.getTestablePermissions().setPermission(
+                android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED);
         DeviceConfig.setProperty(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 SystemUiDeviceConfigFlags.TASK_MANAGER_ENABLED,
@@ -1904,6 +1920,8 @@
 
     @Test
     public void testCancelAllNotifications_IgnoreForegroundService() throws Exception {
+        when(mAmi.applyForegroundServiceNotification(
+                any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY);
         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
         mBinderService.enqueueNotificationWithTag(PKG, PKG,
@@ -1918,7 +1936,27 @@
     }
 
     @Test
+    public void testCancelAllNotifications_FgsFlag_NoFgs_Allowed() throws Exception {
+        when(mAmi.applyForegroundServiceNotification(
+                any(), anyString(), anyInt(), anyString(), anyInt()))
+                .thenReturn(NOT_FOREGROUND_SERVICE);
+        final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
+        sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
+        mBinderService.enqueueNotificationWithTag(PKG, PKG,
+                "testCancelAllNotifications_IgnoreForegroundService",
+                sbn.getId(), sbn.getNotification(), sbn.getUserId());
+        mBinderService.cancelAllNotifications(PKG, sbn.getUserId());
+        waitForIdle();
+        StatusBarNotification[] notifs =
+                mBinderService.getActiveNotifications(sbn.getPackageName());
+        assertEquals(0, notifs.length);
+    }
+
+    @Test
     public void testCancelAllNotifications_IgnoreOtherPackages() throws Exception {
+        when(mAmi.applyForegroundServiceNotification(
+                any(), anyString(), anyInt(), anyString(), anyInt()))
+                .thenReturn(SHOW_IMMEDIATELY);
         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
         mBinderService.enqueueNotificationWithTag(PKG, PKG,
@@ -2006,6 +2044,9 @@
 
     @Test
     public void testRemoveForegroundServiceFlag_ImmediatelyAfterEnqueue() throws Exception {
+        when(mAmi.applyForegroundServiceNotification(
+                any(), anyString(), anyInt(), anyString(), anyInt()))
+                .thenReturn(SHOW_IMMEDIATELY);
         Notification n =
                 new Notification.Builder(mContext, mTestNotificationChannel.getId())
                         .setSmallIcon(android.R.drawable.sym_def_app_icon)
@@ -2043,6 +2084,9 @@
     @Test
     public void testCancelNotificationWithTag_fromApp_cannotCancelFgsChild()
             throws Exception {
+        when(mAmi.applyForegroundServiceNotification(
+                any(), anyString(), anyInt(), anyString(), anyInt()))
+                .thenReturn(SHOW_IMMEDIATELY);
         mService.isSystemUid = false;
         final NotificationRecord parent = generateNotificationRecord(
                 mTestNotificationChannel, 1, "group", true);
@@ -2066,6 +2110,9 @@
     @Test
     public void testCancelNotificationWithTag_fromApp_cannotCancelFgsParent()
             throws Exception {
+        when(mAmi.applyForegroundServiceNotification(
+                any(), anyString(), anyInt(), anyString(), anyInt()))
+                .thenReturn(SHOW_IMMEDIATELY);
         mService.isSystemUid = false;
         final NotificationRecord parent = generateNotificationRecord(
                 mTestNotificationChannel, 1, "group", true);
@@ -2135,6 +2182,9 @@
     @Test
     public void testCancelAllNotificationsFromApp_cannotCancelFgsChild()
             throws Exception {
+        when(mAmi.applyForegroundServiceNotification(
+                any(), anyString(), anyInt(), anyString(), anyInt()))
+                .thenReturn(SHOW_IMMEDIATELY);
         mService.isSystemUid = false;
         final NotificationRecord parent = generateNotificationRecord(
                 mTestNotificationChannel, 1, "group", true);
@@ -2160,6 +2210,9 @@
     @Test
     public void testCancelAllNotifications_fromApp_cannotCancelFgsParent()
             throws Exception {
+        when(mAmi.applyForegroundServiceNotification(
+                any(), anyString(), anyInt(), anyString(), anyInt()))
+                .thenReturn(SHOW_IMMEDIATELY);
         mService.isSystemUid = false;
         final NotificationRecord parent = generateNotificationRecord(
                 mTestNotificationChannel, 1, "group", true);
@@ -2281,6 +2334,9 @@
     @Test
     public void testCancelNotificationsFromListener_clearAll_GroupWithFgsParent()
             throws Exception {
+        when(mAmi.applyForegroundServiceNotification(
+                any(), anyString(), anyInt(), anyString(), anyInt()))
+                .thenReturn(SHOW_IMMEDIATELY);
         final NotificationRecord parent = generateNotificationRecord(
                 mTestNotificationChannel, 1, "group", true);
         parent.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
@@ -2304,6 +2360,9 @@
     @Test
     public void testCancelNotificationsFromListener_clearAll_GroupWithFgsChild()
             throws Exception {
+        when(mAmi.applyForegroundServiceNotification(
+                any(), anyString(), anyInt(), anyString(), anyInt()))
+                .thenReturn(SHOW_IMMEDIATELY);
         final NotificationRecord parent = generateNotificationRecord(
                 mTestNotificationChannel, 1, "group", true);
         final NotificationRecord child = generateNotificationRecord(
@@ -2402,6 +2461,9 @@
     @Test
     public void testCancelNotificationsFromListener_clearAll_Fgs()
             throws Exception {
+        when(mAmi.applyForegroundServiceNotification(
+                any(), anyString(), anyInt(), anyString(), anyInt()))
+                .thenReturn(SHOW_IMMEDIATELY);
         final NotificationRecord child2 = generateNotificationRecord(
                 mTestNotificationChannel, 3, null, false);
         child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
@@ -2466,6 +2528,9 @@
     @Test
     public void testCancelNotificationsFromListener_byKey_GroupWithFgsParent()
             throws Exception {
+        when(mAmi.applyForegroundServiceNotification(
+                any(), anyString(), anyInt(), anyString(), anyInt()))
+                .thenReturn(SHOW_IMMEDIATELY);
         final NotificationRecord parent = generateNotificationRecord(
                 mTestNotificationChannel, 1, "group", true);
         parent.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
@@ -2491,6 +2556,9 @@
     @Test
     public void testCancelNotificationsFromListener_byKey_GroupWithFgsChild()
             throws Exception {
+        when(mAmi.applyForegroundServiceNotification(
+                any(), anyString(), anyInt(), anyString(), anyInt()))
+                .thenReturn(SHOW_IMMEDIATELY);
         final NotificationRecord parent = generateNotificationRecord(
                 mTestNotificationChannel, 1, "group", true);
         final NotificationRecord child = generateNotificationRecord(
@@ -2596,6 +2664,9 @@
     @Test
     public void testCancelNotificationsFromListener_byKey_Fgs()
             throws Exception {
+        when(mAmi.applyForegroundServiceNotification(
+                any(), anyString(), anyInt(), anyString(), anyInt()))
+                .thenReturn(SHOW_IMMEDIATELY);
         final NotificationRecord child2 = generateNotificationRecord(
                 mTestNotificationChannel, 3, null, false);
         child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
@@ -2762,6 +2833,9 @@
 
     @Test
     public void testUserInitiatedCancelAllWithGroup_ForegroundServiceFlag() throws Exception {
+        when(mAmi.applyForegroundServiceNotification(
+                any(), anyString(), anyInt(), anyString(), anyInt()))
+                .thenReturn(SHOW_IMMEDIATELY);
         final NotificationRecord parent = generateNotificationRecord(
                 mTestNotificationChannel, 1, "group", true);
         final NotificationRecord child = generateNotificationRecord(
@@ -4285,6 +4359,43 @@
 
         assertFalse(posted.getNotification().extras
                 .containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE));
+        assertFalse(posted.getNotification().extras
+                .containsKey(Notification.EXTRA_MEDIA_REMOTE_ICON));
+        assertFalse(posted.getNotification().extras
+                .containsKey(Notification.EXTRA_MEDIA_REMOTE_INTENT));
+    }
+
+    @Test
+    public void testCustomMediaStyleRemote_noPermission() throws RemoteException {
+        String deviceName = "device";
+        when(mPackageManager.checkPermission(
+                eq(android.Manifest.permission.MEDIA_CONTENT_CONTROL), any(), anyInt()))
+                .thenReturn(PERMISSION_DENIED);
+        Notification.DecoratedMediaCustomViewStyle style =
+                new Notification.DecoratedMediaCustomViewStyle();
+        style.setRemotePlaybackInfo(deviceName, 0, null);
+        Notification.Builder nb = new Notification.Builder(mContext,
+                mTestNotificationChannel.getId())
+                .setStyle(style);
+
+        StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
+                "testCustomMediaStyleRemoteNoPermission", mUid, 0,
+                nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
+        NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+        mBinderService.enqueueNotificationWithTag(PKG, PKG, sbn.getTag(),
+                nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+        waitForIdle();
+
+        NotificationRecord posted = mService.findNotificationLocked(
+                PKG, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId());
+
+        assertFalse(posted.getNotification().extras
+                .containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE));
+        assertFalse(posted.getNotification().extras
+                .containsKey(Notification.EXTRA_MEDIA_REMOTE_ICON));
+        assertFalse(posted.getNotification().extras
+                .containsKey(Notification.EXTRA_MEDIA_REMOTE_INTENT));
     }
 
     @Test
@@ -6199,6 +6310,9 @@
 
     @Test
     public void testRemoveForegroundServiceFlagFromNotification_enqueued() {
+        when(mAmi.applyForegroundServiceNotification(
+                any(), anyString(), anyInt(), anyString(), anyInt()))
+                .thenReturn(SHOW_IMMEDIATELY);
         Notification n = new Notification.Builder(mContext, "").build();
         n.flags |= FLAG_FOREGROUND_SERVICE;
 
@@ -6218,6 +6332,9 @@
 
     @Test
     public void testRemoveForegroundServiceFlagFromNotification_posted() {
+        when(mAmi.applyForegroundServiceNotification(
+                any(), anyString(), anyInt(), anyString(), anyInt()))
+                .thenReturn(SHOW_IMMEDIATELY);
         Notification n = new Notification.Builder(mContext, "").build();
         n.flags |= FLAG_FOREGROUND_SERVICE;
 
@@ -6240,6 +6357,68 @@
     }
 
     @Test
+    public void testCannotRemoveForegroundFlagWhenOverLimit_enqueued() {
+        when(mAmi.applyForegroundServiceNotification(
+                any(), anyString(), anyInt(), anyString(), anyInt()))
+                .thenReturn(SHOW_IMMEDIATELY);
+        for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
+            Notification n = new Notification.Builder(mContext, "").build();
+            StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, i, null, mUid, 0,
+                    n, UserHandle.getUserHandleForUid(mUid), null, 0);
+            NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+            mService.addEnqueuedNotification(r);
+        }
+        Notification n = new Notification.Builder(mContext, "").build();
+        n.flags |= FLAG_FOREGROUND_SERVICE;
+
+        StatusBarNotification sbn = new StatusBarNotification(PKG, PKG,
+                NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, null, mUid, 0,
+                n, UserHandle.getUserHandleForUid(mUid), null, 0);
+        NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+        mService.addEnqueuedNotification(r);
+
+        mInternalService.removeForegroundServiceFlagFromNotification(
+                PKG, r.getSbn().getId(), r.getSbn().getUserId());
+
+        waitForIdle();
+
+        assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS,
+                mService.getNotificationRecordCount());
+    }
+
+    @Test
+    public void testCannotRemoveForegroundFlagWhenOverLimit_posted() {
+        when(mAmi.applyForegroundServiceNotification(
+                any(), anyString(), anyInt(), anyString(), anyInt()))
+                .thenReturn(SHOW_IMMEDIATELY);
+        for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
+            Notification n = new Notification.Builder(mContext, "").build();
+            StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, i, null, mUid, 0,
+                    n, UserHandle.getUserHandleForUid(mUid), null, 0);
+            NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+            mService.addNotification(r);
+        }
+        Notification n = new Notification.Builder(mContext, "").build();
+        n.flags |= FLAG_FOREGROUND_SERVICE;
+
+        StatusBarNotification sbn = new StatusBarNotification(PKG, PKG,
+                NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, null, mUid, 0,
+                n, UserHandle.getUserHandleForUid(mUid), null, 0);
+        NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+        mService.addNotification(r);
+
+        mInternalService.removeForegroundServiceFlagFromNotification(
+                PKG, r.getSbn().getId(), r.getSbn().getUserId());
+
+        waitForIdle();
+
+        assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS,
+                mService.getNotificationRecordCount());
+    }
+
+    @Test
     public void testAllowForegroundCustomToasts() throws Exception {
         final String testPackage = "testPackageName";
         assertEquals(0, mService.mToastQueue.size());
@@ -8230,7 +8409,7 @@
         assertNotNull(n.publicVersion.bigContentView);
         assertNotNull(n.publicVersion.headsUpContentView);
 
-        mService.fixNotification(n, PKG, "tag", 9, 0);
+        mService.fixNotification(n, PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE);
 
         assertNull(n.contentView);
         assertNull(n.bigContentView);
@@ -8921,6 +9100,9 @@
 
     @Test
     public void testCanPostFgsWhenOverLimit() throws RemoteException {
+        when(mAmi.applyForegroundServiceNotification(
+                any(), anyString(), anyInt(), anyString(), anyInt()))
+                .thenReturn(SHOW_IMMEDIATELY);
         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
             StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel,
                     i, null, false).getSbn();
@@ -8946,6 +9128,9 @@
 
     @Test
     public void testCannotPostNonFgsWhenOverLimit() throws RemoteException {
+        when(mAmi.applyForegroundServiceNotification(
+                any(), anyString(), anyInt(), anyString(), anyInt()))
+                .thenReturn(SHOW_IMMEDIATELY);
         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
             StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel,
                     i, null, false).getSbn();
@@ -8968,6 +9153,17 @@
                 "testCanPostFgsWhenOverLimit - non fgs over limit!",
                 sbn2.getId(), sbn2.getNotification(), sbn2.getUserId());
 
+
+        when(mAmi.applyForegroundServiceNotification(
+                any(), anyString(), anyInt(), anyString(), anyInt()))
+                .thenReturn(NOT_FOREGROUND_SERVICE);
+        final StatusBarNotification sbn3 = generateNotificationRecord(mTestNotificationChannel,
+                101, null, false).getSbn();
+        sbn3.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
+        mBinderService.enqueueNotificationWithTag(PKG, PKG,
+                "testCanPostFgsWhenOverLimit - fake fgs over limit!",
+                sbn3.getId(), sbn3.getNotification(), sbn3.getUserId());
+
         waitForIdle();
 
         StatusBarNotification[] notifs =
@@ -10025,4 +10221,21 @@
         mInternalService.sendReviewPermissionsNotification();
         verify(mMockNm, never()).notify(anyString(), anyInt(), any(Notification.class));
     }
+
+    @Test
+    public void fixNotification_withFgsFlag_butIsNotFgs() throws Exception {
+        final ApplicationInfo applicationInfo = new ApplicationInfo();
+        when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
+                .thenReturn(applicationInfo);
+
+        Notification n = new Notification.Builder(mContext, "test")
+                .setFlag(FLAG_FOREGROUND_SERVICE, true)
+                .setFlag(FLAG_CAN_COLORIZE, true)
+                .build();
+
+        mService.fixNotification(n, PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE);
+
+        assertFalse(n.isForegroundService());
+        assertFalse(n.hasColorizedPermission());
+    }
 }
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 ea50179..0300eb0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -2377,7 +2377,7 @@
                 .setScreenOrientation(SCREEN_ORIENTATION_BEHIND)
                 .build();
         final int topOrientation = activityTop.getRequestedConfigurationOrientation();
-        assertEquals(SCREEN_ORIENTATION_PORTRAIT, topOrientation);
+        assertEquals(ORIENTATION_PORTRAIT, topOrientation);
     }
 
     private void verifyProcessInfoUpdate(ActivityRecord activity, State state,
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index b4ffc2a..0a6cb37 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -16,7 +16,9 @@
 
 package com.android.server.wm;
 
+import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
 import static android.app.Activity.RESULT_CANCELED;
+import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP;
 import static android.app.ActivityManager.PROCESS_STATE_TOP;
 import static android.app.ActivityManager.START_ABORTED;
 import static android.app.ActivityManager.START_CANCELED;
@@ -42,6 +44,7 @@
 import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.os.Process.SYSTEM_UID;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.clearInvocations;
@@ -49,6 +52,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
@@ -73,6 +77,7 @@
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyObject;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.notNull;
@@ -103,6 +108,8 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.am.PendingIntentRecord;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.wm.LaunchParamsController.LaunchParamsModifier;
 import com.android.server.wm.utils.MockTracker;
@@ -110,6 +117,8 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
 
 import java.util.Arrays;
 import java.util.HashSet;
@@ -150,6 +159,9 @@
     @Before
     public void setUp() throws Exception {
         mController = mock(ActivityStartController.class);
+        BackgroundActivityStartController balController =
+                new BackgroundActivityStartController(mAtm, mSupervisor);
+        doReturn(balController).when(mController).getBackgroundActivityLaunchController();
         mActivityMetricsLogger = mock(ActivityMetricsLogger.class);
         clearInvocations(mActivityMetricsLogger);
     }
@@ -211,10 +223,13 @@
             int expectedResult) {
         final ActivityTaskManagerService service = mAtm;
         final IPackageManager packageManager = mock(IPackageManager.class);
-        final ActivityStartController controller = mock(ActivityStartController.class);
 
-        final ActivityStarter starter = new ActivityStarter(controller, service,
-                service.mTaskSupervisor, mock(ActivityStartInterceptor.class));
+        final ActivityStarter starter =
+                new ActivityStarter(
+                        mController,
+                        service,
+                        service.mTaskSupervisor,
+                        mock(ActivityStartInterceptor.class));
         prepareStarter(launchFlags);
         final IApplicationThread caller = mock(IApplicationThread.class);
         final WindowProcessListener listener = mock(WindowProcessListener.class);
@@ -723,6 +738,63 @@
                 isCallingUidDeviceOwner, false /* isPinnedSingleInstance */);
     }
 
+    /**
+     * This test ensures proper logging for BAL_ALLOW_PERMISSION.
+     */
+    @Test
+    public void testBackgroundActivityStartsAllowed_logging() {
+        doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
+        MockitoSession mockingSession = mockitoSession()
+                .mockStatic(ActivityTaskManagerService.class)
+                .mockStatic(FrameworkStatsLog.class)
+                .strictness(Strictness.LENIENT)
+                .startMocking();
+        doReturn(PERMISSION_GRANTED).when(() -> ActivityTaskManagerService.checkPermission(
+                eq(START_ACTIVITIES_FROM_BACKGROUND),
+                anyInt(), anyInt()));
+        runAndVerifyBackgroundActivityStartsSubtest(
+                "allowed_notAborted", false,
+                UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP,
+                UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP,
+                false, true, false, false, false);
+        verify(() -> FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED,
+                "",  // activity name
+                BackgroundActivityStartController.BAL_ALLOW_BAL_PERMISSION,
+                UNIMPORTANT_UID,
+                UNIMPORTANT_UID2));
+        mockingSession.finishMocking();
+    }
+
+    /**
+     * This test ensures proper logging for BAL_ALLOW_PENDING_INTENT.
+     */
+    @Test
+    public void testBackgroundActivityStartsAllowed_loggingPendingIntentAllowed() {
+        doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
+        MockitoSession mockingSession = mockitoSession()
+                .mockStatic(ActivityTaskManagerService.class)
+                .mockStatic(FrameworkStatsLog.class)
+                .mockStatic(PendingIntentRecord.class)
+                .strictness(Strictness.LENIENT)
+                .startMocking();
+        doReturn(PERMISSION_GRANTED).when(() -> ActivityTaskManagerService.checkPermission(
+                eq(START_ACTIVITIES_FROM_BACKGROUND),
+                anyInt(), anyInt()));
+        doReturn(true).when(
+                () -> PendingIntentRecord.isPendingIntentBalAllowedByCaller(anyObject()));
+        runAndVerifyBackgroundActivityStartsSubtest(
+                "allowed_notAborted", false,
+                UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP,
+                Process.SYSTEM_UID, true, PROCESS_STATE_BOUND_TOP,
+                false, true, false, false, false);
+        verify(() -> FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED,
+                DEFAULT_COMPONENT_PACKAGE_NAME + "/" + DEFAULT_COMPONENT_PACKAGE_NAME,
+                BackgroundActivityStartController.BAL_ALLOW_PENDING_INTENT,
+                UNIMPORTANT_UID,
+                Process.SYSTEM_UID));
+        mockingSession.finishMocking();
+    }
+
     private void runAndVerifyBackgroundActivityStartsSubtest(String name, boolean shouldHaveAborted,
             int callingUid, boolean callingUidHasVisibleWindow, int callingUidProcState,
             int realCallingUid, boolean realCallingUidHasVisibleWindow, int realCallingUidProcState,
@@ -1491,7 +1563,7 @@
             TaskFragment inTaskFragment) {
         starter.startActivityInner(target, source, null /* voiceSession */,
                 null /* voiceInteractor */, 0 /* startFlags */, true /* doResume */,
-                options, inTask, inTaskFragment, false /* restrictedBgActivity */,
-                null /* intentGrants */);
+                options, inTask, inTaskFragment,
+                BackgroundActivityStartController.BAL_ALLOW_DEFAULT, null /* intentGrants */);
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java
index 7830e90..3a456fb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java
@@ -16,8 +16,9 @@
 
 package com.android.server.wm;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.util.DisplayMetrics.DENSITY_DEFAULT;
 
 import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS;
@@ -79,24 +80,24 @@
     }
 
     @Test
-    public void testReturnsSkipIfTaskNotInFreeform() {
-        final Task task = new TaskBuilder(mSupervisor).setWindowingMode(
-                WINDOWING_MODE_FULLSCREEN).build();
+    public void testReturnsSkipIfTaskNotUsingActivityTypeStandard() {
+        final Task task = new TaskBuilder(mSupervisor).setActivityType(
+                ACTIVITY_TYPE_ASSISTANT).build();
         assertEquals(RESULT_SKIP, new CalculateRequestBuilder().setTask(task).calculate());
     }
 
     @Test
     public void testReturnsSkipIfCurrentParamsHasBounds() {
-        final Task task = new TaskBuilder(mSupervisor).setWindowingMode(
-                WINDOWING_MODE_FREEFORM).build();
+        final Task task = new TaskBuilder(mSupervisor).setActivityType(
+                ACTIVITY_TYPE_STANDARD).build();
         mCurrent.mBounds.set(/* left */ 0, /* top */ 0, /* right */ 100, /* bottom */ 100);
         assertEquals(RESULT_SKIP, new CalculateRequestBuilder().setTask(task).calculate());
     }
 
     @Test
     public void testUsesDefaultBounds() {
-        final Task task = new TaskBuilder(mSupervisor).setWindowingMode(
-                WINDOWING_MODE_FREEFORM).build();
+        final Task task = new TaskBuilder(mSupervisor).setActivityType(
+                ACTIVITY_TYPE_STANDARD).build();
         assertEquals(RESULT_DONE, new CalculateRequestBuilder().setTask(task).calculate());
         assertEquals(dpiToPx(task, 840), mResult.mBounds.width());
         assertEquals(dpiToPx(task, 630), mResult.mBounds.height());
@@ -104,8 +105,8 @@
 
     @Test
     public void testUsesDisplayAreaAndWindowingModeFromSource() {
-        final Task task = new TaskBuilder(mSupervisor).setWindowingMode(
-                WINDOWING_MODE_FREEFORM).build();
+        final Task task = new TaskBuilder(mSupervisor).setActivityType(
+                ACTIVITY_TYPE_STANDARD).build();
         TaskDisplayArea mockTaskDisplayArea = mock(TaskDisplayArea.class);
         mCurrent.mPreferredTaskDisplayArea = mockTaskDisplayArea;
         mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
index ed2b0a3..26d2a46 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
@@ -17,6 +17,8 @@
 package com.android.server.wm;
 
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -748,7 +750,7 @@
         // ... until half-fold
         mTarget.foldStateChanged(DeviceStateController.DeviceState.HALF_FOLDED);
         assertTrue(waitForUiHandler());
-        verify(sMockWm).updateRotation(false, false);
+        verify(sMockWm).updateRotation(anyBoolean(), anyBoolean());
         assertTrue(waitForUiHandler());
         assertEquals(Surface.ROTATION_0, mTarget.rotationForOrientation(
                 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
@@ -756,7 +758,7 @@
         // ... then transition back to flat
         mTarget.foldStateChanged(DeviceStateController.DeviceState.OPEN);
         assertTrue(waitForUiHandler());
-        verify(sMockWm, atLeast(1)).updateRotation(false, false);
+        verify(sMockWm, atLeast(1)).updateRotation(anyBoolean(), anyBoolean());
         assertTrue(waitForUiHandler());
         assertEquals(Surface.ROTATION_270, mTarget.rotationForOrientation(
                 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
@@ -824,6 +826,23 @@
     }
 
     @Test
+    public void testIgnoresDeskDockRotation_whenNoSensorAndLockedRespected() throws Exception {
+        mBuilder.setDeskDockRotation(Surface.ROTATION_270).build();
+        when(mMockDisplayPolicy.isDeskDockRespectsNoSensorAndLockedWithoutAccelerometer())
+                .thenReturn(true);
+        configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false);
+
+        when(mMockDisplayPolicy.getDockMode()).thenReturn(Intent.EXTRA_DOCK_STATE_DESK);
+
+        freezeRotation(Surface.ROTATION_90);
+
+        assertEquals(Surface.ROTATION_90, mTarget.rotationForOrientation(
+                SCREEN_ORIENTATION_LOCKED, Surface.ROTATION_90));
+        assertEquals(Surface.ROTATION_0, mTarget.rotationForOrientation(
+                SCREEN_ORIENTATION_NOSENSOR, Surface.ROTATION_90));
+    }
+
+    @Test
     public void testReturnsUserRotation_FixedToUserRotation_IgnoreIncompatibleAppRequest()
             throws Exception {
         mBuilder.build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
index 47c2176..b7f8564 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
@@ -188,7 +188,7 @@
                 /* options */null,
                 /* inTask */null,
                 /* inTaskFragment */ null,
-                /* restrictedBgActivity */false,
+                /* balCode */ BackgroundActivityStartController.BAL_ALLOW_DEFAULT,
                 /* intentGrants */null);
 
         assertEquals(result, START_ABORTED);
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
index 656c07b..23a3d52 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
@@ -21,6 +21,7 @@
 import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH;
 import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
 import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS;
+import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED;
 import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION;
 import static android.content.pm.ActivityInfo.OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE;
 import static android.content.pm.ActivityInfo.OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA;
@@ -46,6 +47,8 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.server.wm.LetterboxUiController.MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP;
+import static com.android.server.wm.LetterboxUiController.SET_ORIENTATION_REQUEST_COUNTER_TIMEOUT_MS;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -55,6 +58,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.verify;
 
 import android.annotation.Nullable;
 import android.compat.testing.PlatformCompatChangeRule;
@@ -184,6 +188,69 @@
     }
 
     @Test
+    public void testShouldIgnoreOrientationRequestLoop_overrideDisabled_returnsFalse() {
+        doReturn(false).when(mActivity).isLetterboxedForFixedOrientationAndAspectRatio();
+        // Request 3 times to simulate orientation request loop
+        for (int i = 0; i <= MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP; i++) {
+            assertShouldIgnoreOrientationRequestLoop(/* shouldIgnore */ false,
+                    /* expectedCount */ 0);
+        }
+    }
+
+    @Test
+    @EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED})
+    public void testShouldIgnoreOrientationRequestLoop_isLetterboxed_returnsFalse() {
+        doReturn(true).when(mActivity).isLetterboxedForFixedOrientationAndAspectRatio();
+        // Request 3 times to simulate orientation request loop
+        for (int i = 0; i <= MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP; i++) {
+            assertShouldIgnoreOrientationRequestLoop(/* shouldIgnore */ false,
+                    /* expectedCount */ i);
+        }
+    }
+
+    @Test
+    @EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED})
+    public void testShouldIgnoreOrientationRequestLoop_noLoop_returnsFalse() {
+        doReturn(false).when(mActivity).isLetterboxedForFixedOrientationAndAspectRatio();
+        // No orientation request loop
+        assertShouldIgnoreOrientationRequestLoop(/* shouldIgnore */ false,
+                /* expectedCount */ 0);
+    }
+
+    @Test
+    @EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED})
+    public void testShouldIgnoreOrientationRequestLoop_timeout_returnsFalse()
+            throws InterruptedException {
+        doReturn(false).when(mActivity).isLetterboxedForFixedOrientationAndAspectRatio();
+        for (int i = MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP; i > 0; i--) {
+            assertShouldIgnoreOrientationRequestLoop(/* shouldIgnore */ false,
+                    /* expectedCount */ 0);
+            Thread.sleep(SET_ORIENTATION_REQUEST_COUNTER_TIMEOUT_MS);
+        }
+    }
+
+    @Test
+    @EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED})
+    public void testShouldIgnoreOrientationRequestLoop_returnsTrue() {
+        doReturn(false).when(mActivity).isLetterboxedForFixedOrientationAndAspectRatio();
+        for (int i = 0; i < MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP; i++) {
+            assertShouldIgnoreOrientationRequestLoop(/* shouldIgnore */ false,
+                    /* expectedCount */ i);
+        }
+        assertShouldIgnoreOrientationRequestLoop(/* shouldIgnore */ true,
+                /* expectedCount */ MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP);
+    }
+
+    private void assertShouldIgnoreOrientationRequestLoop(boolean shouldIgnore, int expectedCount) {
+        if (shouldIgnore) {
+            assertTrue(mController.shouldIgnoreOrientationRequestLoop());
+        } else {
+            assertFalse(mController.shouldIgnoreOrientationRequestLoop());
+        }
+        assertEquals(expectedCount, mController.getSetOrientationRequestCounter());
+    }
+
+    @Test
     @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH})
     public void testShouldIgnoreRequestedOrientation_flagIsDisabled_returnsFalse() {
         prepareActivityThatShouldIgnoreRequestedOrientationDuringRelaunch();
@@ -453,8 +520,17 @@
         mainWindow.mInvGlobalScale = invGlobalScale;
         mLetterboxConfiguration.setLetterboxActivityCornersRadius(configurationRadius);
 
+        doReturn(true).when(mActivity).isInLetterboxAnimation();
         assertEquals(expectedRadius, mController.getRoundedCornersRadius(mainWindow));
 
+        doReturn(false).when(mActivity).isInLetterboxAnimation();
+        assertEquals(expectedRadius, mController.getRoundedCornersRadius(mainWindow));
+
+        doReturn(false).when(mainWindow).isOnScreen();
+        assertEquals(0, mController.getRoundedCornersRadius(mainWindow));
+
+        doReturn(true).when(mActivity).isInLetterboxAnimation();
+        assertEquals(expectedRadius, mController.getRoundedCornersRadius(mainWindow));
     }
 
     @Test
@@ -489,6 +565,7 @@
             doReturn(taskbar).when(insets).peekSource(taskbar.getType());
         }
         doReturn(mLetterboxedPortraitTaskBounds).when(mActivity).getBounds();
+        doReturn(false).when(mActivity).isInLetterboxAnimation();
         doReturn(true).when(mActivity).isVisible();
         doReturn(true).when(mActivity).isLetterboxedForFixedOrientationAndAspectRatio();
         doReturn(insets).when(mainWindow).getInsetsState();
@@ -510,6 +587,16 @@
     // overrideOrientationIfNeeded
 
     @Test
+    public void testOverrideOrientationIfNeeded_mapInvokedOnRequest() throws Exception {
+        mController = new LetterboxUiController(mWm, mActivity);
+        spyOn(mWm);
+
+        mController.overrideOrientationIfNeeded(SCREEN_ORIENTATION_PORTRAIT);
+
+        verify(mWm).mapOrientationRequest(SCREEN_ORIENTATION_PORTRAIT);
+    }
+
+    @Test
     @EnableCompatChanges({OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT})
     public void testOverrideOrientationIfNeeded_portraitOverrideEnabled_returnsPortrait()
             throws Exception {
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 117805b..4a3f46a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
@@ -51,6 +52,8 @@
 import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_SIZE_COMPAT_MODE;
 import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED;
 import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
+import static com.android.server.wm.ActivityRecord.State.DESTROYED;
+import static com.android.server.wm.ActivityRecord.State.PAUSED;
 import static com.android.server.wm.ActivityRecord.State.RESTARTING_PROCESS;
 import static com.android.server.wm.ActivityRecord.State.RESUMED;
 import static com.android.server.wm.ActivityRecord.State.STOPPED;
@@ -62,6 +65,8 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -104,7 +109,6 @@
 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;
@@ -170,6 +174,26 @@
     }
 
     @Test
+    public void testCleanLetterboxConfigListenerWhenTranslucentIsDestroyed() {
+        mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true);
+        setUpDisplaySizeWithApp(2000, 1000);
+        prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
+        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+        // Translucent Activity
+        final ActivityRecord translucentActivity = new ActivityBuilder(mAtm)
+                .setLaunchedFromUid(mActivity.getUid())
+                .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
+                .build();
+        doReturn(false).when(translucentActivity).fillsParent();
+        mTask.addChild(translucentActivity);
+
+        translucentActivity.setState(DESTROYED, "testing");
+        translucentActivity.removeImmediately();
+
+        assertFalse(translucentActivity.mLetterboxUiController.hasInheritedLetterboxBehavior());
+    }
+
+    @Test
     public void testHorizontalReachabilityEnabledForTranslucentActivities() {
         setUpDisplaySizeWithApp(2500, 1000);
         mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
@@ -349,6 +373,33 @@
     }
 
     @Test
+    public void testApplyStrategyToTranslucentActivitiesRetainsWindowConfigurationProperties() {
+        mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true);
+        setUpDisplaySizeWithApp(2000, 1000);
+        prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
+        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+        // Translucent Activity
+        final ActivityRecord translucentActivity = new ActivityBuilder(mAtm)
+                .setLaunchedFromUid(mActivity.getUid())
+                .build();
+        doReturn(false).when(translucentActivity).fillsParent();
+        WindowConfiguration translucentWinConf = translucentActivity.getWindowConfiguration();
+        translucentActivity.setActivityType(ACTIVITY_TYPE_STANDARD);
+        translucentActivity.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+        translucentActivity.setDisplayWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+        translucentActivity.setAlwaysOnTop(true);
+
+        mTask.addChild(translucentActivity);
+
+        // We check the WIndowConfiguration properties
+        translucentWinConf = translucentActivity.getWindowConfiguration();
+        assertEquals(ACTIVITY_TYPE_STANDARD, translucentActivity.getActivityType());
+        assertEquals(WINDOWING_MODE_MULTI_WINDOW, translucentWinConf.getWindowingMode());
+        assertEquals(WINDOWING_MODE_MULTI_WINDOW, translucentWinConf.getDisplayWindowingMode());
+        assertTrue(translucentWinConf.isAlwaysOnTop());
+    }
+
+    @Test
     public void testApplyStrategyToMultipleTranslucentActivities() {
         mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true);
         setUpDisplaySizeWithApp(2000, 1000);
@@ -381,7 +432,7 @@
     }
 
     @Test
-    public void testTranslucentActivitiesDontGoInSizeCompactMode() {
+    public void testTranslucentActivitiesDontGoInSizeCompatMode() {
         mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true);
         setUpDisplaySizeWithApp(2800, 1400);
         mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
@@ -397,7 +448,7 @@
                 .setLaunchedFromUid(mActivity.getUid())
                 .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
                 .build();
-        doReturn(true).when(translucentActivity).fillsParent();
+        doReturn(false).when(translucentActivity).fillsParent();
         mTask.addChild(translucentActivity);
         // It should not be in SCM
         assertFalse(translucentActivity.inSizeCompatMode());
@@ -458,6 +509,33 @@
     }
 
     @Test
+    public void testTranslucentActivity_clearSizeCompatMode_inheritedCompatDisplayInsetsCleared() {
+        mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true);
+        setUpDisplaySizeWithApp(2800, 1400);
+        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+        prepareUnresizable(mActivity, -1f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
+        // Rotate to put activity in size compat mode.
+        rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
+        assertTrue(mActivity.inSizeCompatMode());
+
+        // We launch a transparent activity
+        final ActivityRecord translucentActivity = new ActivityBuilder(mAtm)
+                .setLaunchedFromUid(mActivity.getUid())
+                .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
+                .build();
+        doReturn(false).when(translucentActivity).fillsParent();
+        mTask.addChild(translucentActivity);
+
+        // The transparent activity inherits the compat display insets of the opaque activity
+        // beneath it
+        assertNotNull(translucentActivity.getCompatDisplayInsets());
+
+        // Clearing SCM should also clear the inherited compat display insets
+        translucentActivity.clearSizeCompatMode();
+        assertNull(translucentActivity.getCompatDisplayInsets());
+    }
+
+    @Test
     public void testRestartProcessIfVisible() {
         setUpDisplaySizeWithApp(1000, 2500);
         doNothing().when(mSupervisor).scheduleRestartTimeout(mActivity);
@@ -573,11 +651,11 @@
         // The scale is 2000/2500=0.8. The horizontal centered offset is (1000-(1000*0.8))/2=100.
         final float scale = (float) display.mBaseDisplayHeight / currentBounds.height();
         final int offsetX = (int) (display.mBaseDisplayWidth - (origBounds.width() * scale)) / 2;
-        assertEquals(offsetX, currentBounds.left);
+        final int screenX = mActivity.getBounds().left;
+        assertEquals(offsetX, screenX);
 
-        // The position of configuration bounds should be the same as compat bounds.
-        assertEquals(mActivity.getBounds().left, currentBounds.left);
-        assertEquals(mActivity.getBounds().top, currentBounds.top);
+        // The position of configuration bounds should be in app space.
+        assertEquals(screenX, (int) (currentBounds.left * scale + 0.5f));
         // Activity is sandboxed to the offset size compat bounds.
         assertActivityMaxBoundsSandboxed();
 
@@ -607,7 +685,7 @@
         // The size should still be in portrait [100, 0 - 1100, 2500] = 1000x2500.
         assertEquals(origBounds.width(), currentBounds.width());
         assertEquals(origBounds.height(), currentBounds.height());
-        assertEquals(offsetX, currentBounds.left);
+        assertEquals(offsetX, mActivity.getBounds().left);
         assertScaled();
         // Activity is sandboxed due to size compat mode.
         assertActivityMaxBoundsSandboxed();
@@ -770,9 +848,11 @@
         assertEquals(origAppBounds.height(), appBounds.height());
         // The activity is 1000x1400 and the display is 2500x1000.
         assertScaled();
-        // The position in configuration should be global coordinates.
-        assertEquals(mActivity.getBounds().left, currentBounds.left);
-        assertEquals(mActivity.getBounds().top, currentBounds.top);
+        final float scale = mActivity.getCompatScale();
+        // The position in configuration should be in app coordinates.
+        final Rect screenBounds = mActivity.getBounds();
+        assertEquals(screenBounds.left, (int) (currentBounds.left * scale + 0.5f));
+        assertEquals(screenBounds.top, (int) (currentBounds.top * scale + 0.5f));
 
         // Activity max bounds are sandboxed due to size compat mode.
         assertActivityMaxBoundsSandboxed();
@@ -1988,7 +2068,7 @@
         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);
+        assertEquals(expectedAspectRatio, afterAspectRatio, 0.001f);
     }
 
     @Test
@@ -2013,7 +2093,7 @@
         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);
+        assertEquals(expectedAspectRatio, afterAspectRatio, 0.001f);
     }
 
     @Test
@@ -2039,7 +2119,7 @@
         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);
+        assertEquals(expectedAspectRatio, afterAspectRatio, 0.001f);
     }
 
     @Test
@@ -2065,7 +2145,89 @@
         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);
+        assertEquals(expectedAspectRatio, afterAspectRatio, 0.001f);
+    }
+
+    @Test
+    @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
+            ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN})
+    public void testOverrideSplitScreenAspectRatio_splitScreenActivityInPortrait_notLetterboxed() {
+        mAtm.mDevEnableNonResizableMultiWindow = true;
+        final int screenWidth = 1800;
+        final int screenHeight = 1000;
+        setUpDisplaySizeWithApp(screenWidth, screenHeight);
+        final ActivityRecord activity = new ActivityBuilder(mAtm)
+                .setTask(mTask)
+                .setComponent(ComponentName.createRelative(mContext,
+                        SizeCompatTests.class.getName()))
+                .setUid(android.os.Process.myUid())
+                .build();
+
+        activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+        // Simulate real display with top insets.
+        final int topInset = 30;
+        activity.mDisplayContent.getWindowConfiguration()
+                .setAppBounds(0, topInset, screenWidth, screenHeight);
+
+        final TestSplitOrganizer organizer =
+                new TestSplitOrganizer(mAtm, activity.getDisplayContent());
+        // Move activity to split screen which takes half of the screen.
+        mTask.reparent(organizer.mPrimary, POSITION_TOP, /* moveParents= */ false , "test");
+        organizer.mPrimary.setBounds(0, 0, getExpectedSplitSize(screenWidth), screenHeight);
+        assertEquals(WINDOWING_MODE_MULTI_WINDOW, mTask.getWindowingMode());
+        assertEquals(WINDOWING_MODE_MULTI_WINDOW, activity.getWindowingMode());
+
+        // Unresizable portrait-only activity.
+        prepareUnresizable(activity, 3f, SCREEN_ORIENTATION_PORTRAIT);
+
+        // Activity should have the aspect ratio of a split screen activity and occupy exactly one
+        // half of the screen, so there is no letterbox
+        float expectedAspectRatio = 1f * screenHeight / getExpectedSplitSize(screenWidth);
+        final Rect afterBounds = activity.getBounds();
+        final float afterAspectRatio = (float) (afterBounds.height()) / afterBounds.width();
+        assertEquals(expectedAspectRatio, afterAspectRatio, 0.001f);
+        assertFalse(activity.areBoundsLetterboxed());
+    }
+
+    @Test
+    @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
+            ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN})
+    public void testOverrideSplitScreenAspectRatio_splitScreenActivityInLandscape_notLetterboxed() {
+        mAtm.mDevEnableNonResizableMultiWindow = true;
+        final int screenWidth = 1000;
+        final int screenHeight = 1800;
+        setUpDisplaySizeWithApp(screenWidth, screenHeight);
+        final ActivityRecord activity = new ActivityBuilder(mAtm)
+                .setTask(mTask)
+                .setComponent(ComponentName.createRelative(mContext,
+                        SizeCompatTests.class.getName()))
+                .setUid(android.os.Process.myUid())
+                .build();
+
+        activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+        // Simulate real display with top insets.
+        final int leftInset = 30;
+        activity.mDisplayContent.getWindowConfiguration()
+                .setAppBounds(leftInset, 0, screenWidth, screenHeight);
+
+        final TestSplitOrganizer organizer =
+                new TestSplitOrganizer(mAtm, activity.getDisplayContent());
+        // Move activity to split screen which takes half of the screen.
+        mTask.reparent(organizer.mPrimary, POSITION_TOP, /* moveParents= */ false , "test");
+        organizer.mPrimary.setBounds(0, 0, screenWidth, getExpectedSplitSize(screenHeight));
+        assertEquals(WINDOWING_MODE_MULTI_WINDOW, mTask.getWindowingMode());
+        assertEquals(WINDOWING_MODE_MULTI_WINDOW, activity.getWindowingMode());
+
+        // Unresizable landscape-only activity.
+        prepareUnresizable(activity, 3f, SCREEN_ORIENTATION_LANDSCAPE);
+
+        // Activity should have the aspect ratio of a split screen activity and occupy exactly one
+        // half of the screen, so there is no letterbox
+        float expectedAspectRatio = 1f * screenWidth / getExpectedSplitSize(screenHeight);
+        final Rect afterBounds = activity.getBounds();
+        final float afterAspectRatio = (float) (afterBounds.width()) / afterBounds.height();
+        assertEquals(expectedAspectRatio, afterAspectRatio, 0.001f);
+        assertFalse(activity.areBoundsLetterboxed());
     }
 
     @Test
@@ -2454,11 +2616,11 @@
         assertFalse(mActivity.inSizeCompatMode());
 
         mActivity.setRequestedOrientation(SCREEN_ORIENTATION_UNSPECIFIED);
-
-        assertTrue(mActivity.inSizeCompatMode());
-        // We should remember the original orientation.
+        // Activity is not in size compat mode because the orientation change request came from the
+        // app itself
+        assertFalse(mActivity.inSizeCompatMode());
         assertEquals(mActivity.getResolvedOverrideConfiguration().orientation,
-                Configuration.ORIENTATION_PORTRAIT);
+                Configuration.ORIENTATION_UNDEFINED);
     }
 
     @Test
@@ -2965,12 +3127,44 @@
         assertTrue(mActivity.inSizeCompatMode());
 
         // Vertical reachability is disabled because the app does not match parent width
-        assertNotEquals(mActivity.getBounds().width(), mActivity.mDisplayContent.getBounds()
-                .width());
+        assertNotEquals(mActivity.getScreenResolvedBounds().width(),
+                mActivity.mDisplayContent.getBounds().width());
         assertFalse(mActivity.mLetterboxUiController.isVerticalReachabilityEnabled());
     }
 
     @Test
+    public void testIsVerticalReachabilityEnabled_emptyBounds_true() {
+        setUpDisplaySizeWithApp(/* dw */ 1000, /* dh */ 2800);
+        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+        mWm.mLetterboxConfiguration.setIsVerticalReachabilityEnabled(true);
+
+        prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE);
+
+        // Set up activity with empty bounds to mock loading of app
+        mActivity.getWindowConfiguration().setBounds(null);
+        assertEquals(new Rect(0, 0, 0, 0), mActivity.getBounds());
+
+        // Vertical reachability is still enabled as resolved bounds is not empty
+        assertTrue(mActivity.mLetterboxUiController.isVerticalReachabilityEnabled());
+    }
+
+    @Test
+    public void testIsHorizontalReachabilityEnabled_emptyBounds_true() {
+        setUpDisplaySizeWithApp(/* dw */ 2800, /* dh */ 1000);
+        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+        mWm.mLetterboxConfiguration.setIsHorizontalReachabilityEnabled(true);
+
+        prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
+
+        // Set up activity with empty bounds to mock loading of app
+        mActivity.getWindowConfiguration().setBounds(null);
+        assertEquals(new Rect(0, 0, 0, 0), mActivity.getBounds());
+
+        // Horizontal reachability is still enabled as resolved bounds is not empty
+        assertTrue(mActivity.mLetterboxUiController.isHorizontalReachabilityEnabled());
+    }
+
+    @Test
     public void testIsHorizontalReachabilityEnabled_doesNotMatchParentHeight_false() {
         setUpDisplaySizeWithApp(2800, 1000);
         mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
@@ -2986,8 +3180,8 @@
         assertTrue(mActivity.inSizeCompatMode());
 
         // Horizontal reachability is disabled because the app does not match parent height
-        assertNotEquals(mActivity.getBounds().height(), mActivity.mDisplayContent.getBounds()
-                .height());
+        assertNotEquals(mActivity.getScreenResolvedBounds().height(),
+                mActivity.mDisplayContent.getBounds().height());
         assertFalse(mActivity.mLetterboxUiController.isHorizontalReachabilityEnabled());
     }
 
@@ -3007,8 +3201,8 @@
         assertTrue(mActivity.inSizeCompatMode());
 
         // Horizontal reachability is enabled because the app matches parent height
-        assertEquals(mActivity.getBounds().height(), mActivity.mDisplayContent.getBounds()
-                .height());
+        assertEquals(mActivity.getScreenResolvedBounds().height(),
+                mActivity.mDisplayContent.getBounds().height());
         assertTrue(mActivity.mLetterboxUiController.isHorizontalReachabilityEnabled());
     }
 
@@ -3028,11 +3222,31 @@
         assertTrue(mActivity.inSizeCompatMode());
 
         // Vertical reachability is enabled because the app matches parent width
-        assertEquals(mActivity.getBounds().width(), mActivity.mDisplayContent.getBounds().width());
+        assertEquals(mActivity.getScreenResolvedBounds().width(),
+                mActivity.mDisplayContent.getBounds().width());
         assertTrue(mActivity.mLetterboxUiController.isVerticalReachabilityEnabled());
     }
 
     @Test
+    public void testAppRequestsOrientationChange_notInSizeCompat() {
+        setUpDisplaySizeWithApp(2200, 1800);
+        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+
+        prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE);
+
+        mActivity.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
+
+        // Activity is not in size compat mode because the orientation change request came from the
+        // app itself
+        assertFalse(mActivity.inSizeCompatMode());
+
+        rotateDisplay(mActivity.mDisplayContent, ROTATION_270);
+        // Activity should go into size compat mode now because the orientation change came from the
+        // system (device rotation)
+        assertTrue(mActivity.inSizeCompatMode());
+    }
+
+    @Test
     public void testLetterboxDetailsForStatusBar_noLetterbox() {
         setUpDisplaySizeWithApp(2800, 1000);
         addStatusBar(mActivity.mDisplayContent);
@@ -3533,7 +3747,6 @@
 
     @Test
     public void testUpdateResolvedBoundsVerticalPosition_tabletop() {
-
         // Set up a display in portrait with a fixed-orientation LANDSCAPE app
         setUpDisplaySizeWithApp(1400, 2800);
         mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
@@ -3555,16 +3768,15 @@
         setFoldablePosture(false /* isHalfFolded */, false /* isTabletop */);
 
         assertEquals(letterboxNoFold, mActivity.getBounds());
-
     }
 
     @Test
-    public void testUpdateResolvedBoundsHorizontalPosition_book() {
-
+    public void testUpdateResolvedBoundsHorizontalPosition_bookModeEnabled() {
         // Set up a display in landscape with a fixed-orientation PORTRAIT app
         setUpDisplaySizeWithApp(2800, 1400);
         mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
-        mActivity.mWmService.mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier(
+        mWm.mLetterboxConfiguration.setIsAutomaticReachabilityInBookModeEnabled(true);
+        mWm.mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier(
                 1.0f /*letterboxVerticalPositionMultiplier*/);
         prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
 
@@ -3582,7 +3794,28 @@
         setFoldablePosture(false /* isHalfFolded */, false /* isTabletop */);
 
         assertEquals(letterboxNoFold, mActivity.getBounds());
+    }
 
+    @Test
+    public void testUpdateResolvedBoundsHorizontalPosition_bookModeDisabled_centered() {
+        // Set up a display in landscape with a fixed-orientation PORTRAIT app
+        setUpDisplaySizeWithApp(2800, 1400);
+        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+        mWm.mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier(0.5f);
+        prepareUnresizable(mActivity, 1.75f, SCREEN_ORIENTATION_PORTRAIT);
+
+        Rect letterboxNoFold = new Rect(1000, 0, 1800, 1400);
+        assertEquals(letterboxNoFold, mActivity.getBounds());
+
+        // Make the activity full-screen
+        mTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+
+        // Stay centered and bounds don't change
+        setFoldablePosture(true /* isHalfFolded */, false /* isTabletop */);
+        assertEquals(letterboxNoFold, mActivity.getBounds());
+
+        setFoldablePosture(false /* isHalfFolded */, false /* isTabletop */);
+        assertEquals(letterboxNoFold, mActivity.getBounds());
     }
 
     private void setFoldablePosture(ActivityRecord activity, boolean isHalfFolded,
@@ -3865,6 +4098,24 @@
         assertTrue(mActivity.inSizeCompatMode());
     }
 
+    @Test
+    public void testTopActivityInSizeCompatMode_pausedAndInSizeCompatMode_returnsTrue() {
+        setUpDisplaySizeWithApp(1000, 2500);
+        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+
+        spyOn(mActivity);
+        doReturn(mTask).when(mActivity).getOrganizedTask();
+        prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
+
+        rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
+        mActivity.setState(PAUSED, "test");
+
+        assertTrue(mActivity.inSizeCompatMode());
+        assertEquals(mActivity.getState(), PAUSED);
+        assertTrue(mActivity.isVisible());
+        assertTrue(mTask.getTaskInfo().topActivityInSizeCompat);
+    }
+
     /**
      * Tests that all three paths in which aspect ratio logic can be applied yield the same
      * result, which is that aspect ratio is respected on app bounds. The three paths are
diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
index 1407cdd..65f31a0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -52,6 +52,7 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
+import android.util.MergedConfiguration;
 import android.view.DisplayCutout;
 import android.view.DisplayInfo;
 import android.view.Gravity;
@@ -61,6 +62,7 @@
 import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.WindowManager;
+import android.window.ClientWindowFrames;
 
 import androidx.test.filters.SmallTest;
 
@@ -338,6 +340,29 @@
     }
 
     @Test
+    public void testWallpaperReportConfigChange() {
+        final WindowState wallpaperWindow = createWallpaperWindow(mDisplayContent);
+        createWallpaperTargetWindow(mDisplayContent);
+        final WallpaperWindowToken wallpaperToken = wallpaperWindow.mToken.asWallpaperToken();
+        makeWindowVisible(wallpaperWindow);
+        wallpaperWindow.mLayoutSeq = mDisplayContent.mLayoutSeq;
+        // Assume the token was invisible and the latest config was reported.
+        wallpaperToken.commitVisibility(false);
+        wallpaperWindow.fillClientWindowFramesAndConfiguration(new ClientWindowFrames(),
+                new MergedConfiguration(), true /* useLatestConfig */, false /* relayoutVisible */);
+        assertTrue(wallpaperWindow.isLastConfigReportedToClient());
+
+        final Rect bounds = wallpaperToken.getBounds();
+        wallpaperToken.setBounds(new Rect(0, 0, bounds.width() / 2, bounds.height() / 2));
+        assertFalse(wallpaperWindow.isLastConfigReportedToClient());
+        // If there is a pending config change when changing to visible, it should tell the client
+        // to redraw by WindowState#reportResized.
+        wallpaperToken.commitVisibility(true);
+        waitUntilHandlersIdle();
+        assertTrue(wallpaperWindow.isLastConfigReportedToClient());
+    }
+
+    @Test
     public void testWallpaperTokenVisibility() {
         final DisplayContent dc = mWm.mRoot.getDefaultDisplay();
         final WindowState wallpaperWindow = createWallpaperWindow(dc);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index 7ca358a..e3d7e68 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -98,6 +98,20 @@
     }
 
     @Test
+    public void testIsRequestedOrientationMapped() {
+        mWm.setOrientationRequestPolicy(/* isIgnoreOrientationRequestDisabled*/ true,
+                /* fromOrientations */ new int[]{1}, /* toOrientations */ new int[]{2});
+        assertThat(mWm.mapOrientationRequest(1)).isEqualTo(2);
+        assertThat(mWm.mapOrientationRequest(3)).isEqualTo(3);
+
+        // Mapping disabled
+        mWm.setOrientationRequestPolicy(/* isIgnoreOrientationRequestDisabled*/ false,
+                /* fromOrientations */ null, /* toOrientations */ null);
+        assertThat(mWm.mapOrientationRequest(1)).isEqualTo(1);
+        assertThat(mWm.mapOrientationRequest(3)).isEqualTo(3);
+    }
+
+    @Test
     public void testAddWindowToken() {
         IBinder token = mock(IBinder.class);
         mWm.addWindowToken(token, TYPE_TOAST, mDisplayContent.getDisplayId(), null /* options */);
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 fa98537..87c2a9a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -1485,9 +1485,9 @@
         assertEquals(rootTask.mTaskId, info.taskId);
         assertTrue(info.topActivityInSizeCompat);
 
-        // Ensure task info show top activity that is not in foreground as not in size compat.
+        // Ensure task info show top activity that is not visible as not in size compat.
         clearInvocations(organizer);
-        doReturn(false).when(activity).isState(RESUMED);
+        doReturn(false).when(activity).isVisible();
         rootTask.onSizeCompatActivityChanged();
         mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
         verify(organizer).onTaskInfoChanged(infoCaptor.capture());
@@ -1497,7 +1497,7 @@
 
         // Ensure task info show non size compat top activity as not in size compat.
         clearInvocations(organizer);
-        doReturn(true).when(activity).isState(RESUMED);
+        doReturn(true).when(activity).isVisible();
         doReturn(false).when(activity).inSizeCompatMode();
         rootTask.onSizeCompatActivityChanged();
         mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
diff --git a/services/texttospeech/java/com/android/server/texttospeech/TextToSpeechManagerPerUserService.java b/services/texttospeech/java/com/android/server/texttospeech/TextToSpeechManagerPerUserService.java
index 55cbc72..4451cba 100644
--- a/services/texttospeech/java/com/android/server/texttospeech/TextToSpeechManagerPerUserService.java
+++ b/services/texttospeech/java/com/android/server/texttospeech/TextToSpeechManagerPerUserService.java
@@ -95,7 +95,7 @@
                 ITextToSpeechSessionCallback callback) {
             super(context,
                     new Intent(TextToSpeech.Engine.INTENT_ACTION_TTS_SERVICE).setPackage(engine),
-                    Context.BIND_AUTO_CREATE,
+                    Context.BIND_AUTO_CREATE | Context.BIND_SCHEDULE_LIKE_TOP_APP,
                     userId,
                     ITextToSpeechService.Stub::asInterface);
             mEngine = engine;
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordMetricsLogger.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordMetricsLogger.java
index c35d90f..f7b66a2 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordMetricsLogger.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordMetricsLogger.java
@@ -34,10 +34,13 @@
 import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__NORMAL_DETECTOR;
 import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
 import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE;
+import static com.android.internal.util.LatencyTracker.ACTION_SHOW_VOICE_INTERACTION;
 
+import android.content.Context;
 import android.service.voice.HotwordDetector;
 
 import com.android.internal.util.FrameworkStatsLog;
+import com.android.internal.util.LatencyTracker;
 
 /**
  * A utility class for logging hotword statistics event.
@@ -116,6 +119,46 @@
                 metricsDetectorType, event, uid, streamSizeBytes, bundleSizeBytes, streamCount);
     }
 
+    /**
+     * Starts a {@link LatencyTracker} log for the time it takes to show the
+     * {@link android.service.voice.VoiceInteractionSession} system UI after a voice trigger.
+     *
+     * @see LatencyTracker
+     *
+     * @param tag Extra tag to separate different sessions from each other.
+     */
+    public static void startHotwordTriggerToUiLatencySession(Context context, String tag) {
+        LatencyTracker.getInstance(context).onActionStart(ACTION_SHOW_VOICE_INTERACTION, tag);
+    }
+
+    /**
+     * Completes a {@link LatencyTracker} log for the time it takes to show the
+     * {@link android.service.voice.VoiceInteractionSession} system UI after a voice trigger.
+     *
+     * <p>Completing this session will result in logging metric data.</p>
+     *
+     * @see LatencyTracker
+     */
+    public static void stopHotwordTriggerToUiLatencySession(Context context) {
+        LatencyTracker.getInstance(context).onActionEnd(ACTION_SHOW_VOICE_INTERACTION);
+    }
+
+    /**
+     * Cancels a {@link LatencyTracker} log for the time it takes to show the
+     * {@link android.service.voice.VoiceInteractionSession} system UI after a voice trigger.
+     *
+     * <p>Cancels typically occur when the VoiceInteraction session UI is shown for reasons outside
+     * of a {@link android.hardware.soundtrigger.SoundTrigger.RecognitionEvent} such as an
+     * invocation from an external source or service.</p>
+     *
+     * <p>Canceling this session will not result in logging metric data.
+     *
+     * @see LatencyTracker
+     */
+    public static void cancelHotwordTriggerToUiLatencySession(Context context) {
+        LatencyTracker.getInstance(context).onActionCancel(ACTION_SHOW_VOICE_INTERACTION);
+    }
+
     private static int getCreateMetricsDetectorType(int detectorType) {
         switch (detectorType) {
             case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_SOFTWARE:
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index bc5c9ec..5635120 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -95,7 +95,6 @@
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.DumpUtils;
-import com.android.internal.util.LatencyTracker;
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
@@ -404,6 +403,10 @@
             final int callingUid = Binder.getCallingUid();
             final long caller = Binder.clearCallingIdentity();
             try {
+                // HotwordDetector trigger uses VoiceInteractionService#showSession
+                // We need to cancel here because UI is not being shown due to a SoundTrigger
+                // HAL event.
+                HotwordMetricsLogger.cancelHotwordTriggerToUiLatencySession(mContext);
                 mImpl.showSessionLocked(options,
                         VoiceInteractionSession.SHOW_SOURCE_ACTIVITY,
                         new IVoiceInteractionSessionShowCallback.Stub() {
@@ -954,6 +957,13 @@
                     Slog.w(TAG, "showSessionFromSession without running voice interaction service");
                     return false;
                 }
+                // If the token is null, then the request to show the session is not coming from
+                // the active VoiceInteractionService session.
+                // We need to cancel here because UI is not being shown due to a SoundTrigger
+                // HAL event.
+                if (token == null) {
+                    HotwordMetricsLogger.cancelHotwordTriggerToUiLatencySession(mContext);
+                }
                 final long caller = Binder.clearCallingIdentity();
                 try {
                     return mImpl.showSessionLocked(sessionArgs, flags, null, null);
@@ -1718,6 +1728,11 @@
 
                 final long caller = Binder.clearCallingIdentity();
                 try {
+                    // HotwordDetector trigger uses VoiceInteractionService#showSession
+                    // We need to cancel here because UI is not being shown due to a SoundTrigger
+                    // HAL event.
+                    HotwordMetricsLogger.cancelHotwordTriggerToUiLatencySession(mContext);
+
                     return mImpl.showSessionLocked(args,
                             sourceFlags
                                     | VoiceInteractionSession.SHOW_WITH_ASSIST
@@ -2361,8 +2376,11 @@
                 public void onVoiceSessionWindowVisibilityChanged(boolean visible)
                         throws RemoteException {
                     if (visible) {
-                        LatencyTracker.getInstance(mContext)
-                                .onActionEnd(LatencyTracker.ACTION_SHOW_VOICE_INTERACTION);
+                        // The AlwaysOnHotwordDetector trigger latency is always completed here even
+                        // if the reason the window was shown was not due to a SoundTrigger HAL
+                        // event. It is expected that the latency will be canceled if shown for
+                        // other invocation reasons, and this call becomes a noop.
+                        HotwordMetricsLogger.stopHotwordTriggerToUiLatencySession(mContext);
                     }
                 }
 
diff --git a/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java b/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java
index 3db0116..fdd9194 100644
--- a/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java
+++ b/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java
@@ -86,7 +86,7 @@
         mFile = testContext.getFileStreamPath("tracing_test.dat");
         //noinspection ResultOfMethodCallIgnored
         mFile.delete();
-        mProtoLog = new ProtoLogImpl(mFile, 1024 * 1024, mReader);
+        mProtoLog = new ProtoLogImpl(mFile, 1024 * 1024, mReader, 1024);
     }
 
     @After
diff --git a/tests/testables/src/android/testing/TestableContext.java b/tests/testables/src/android/testing/TestableContext.java
index e2668bc..0f04d6a 100644
--- a/tests/testables/src/android/testing/TestableContext.java
+++ b/tests/testables/src/android/testing/TestableContext.java
@@ -33,11 +33,15 @@
 import android.util.ArrayMap;
 import android.view.LayoutInflater;
 
+import androidx.annotation.Nullable;
+
 import org.junit.rules.TestRule;
 import org.junit.rules.TestWatcher;
 import org.junit.runner.Description;
 import org.junit.runners.model.Statement;
 
+import java.util.ArrayList;
+
 /**
  * A ContextWrapper with utilities specifically designed to make Testing easier.
  *
@@ -61,6 +65,7 @@
     private final TestableContentResolver mTestableContentResolver;
     private final TestableSettingsProvider mSettingsProvider;
 
+    private ArrayList<MockServiceResolver> mMockServiceResolvers;
     private ArrayMap<String, Object> mMockSystemServices;
     private ArrayMap<ComponentName, IBinder> mMockServices;
     private ArrayMap<ServiceConnection, ComponentName> mActiveServices;
@@ -214,12 +219,15 @@
     /**
      * Adds a mock service to be connected to by a bindService call.
      * <p>
-     *     Normally a TestableContext will pass through all bind requests to the base context
-     *     but when addMockService has been called for a ComponentName being bound, then
-     *     TestableContext will immediately trigger a {@link ServiceConnection#onServiceConnected}
-     *     with the specified service, and will call {@link ServiceConnection#onServiceDisconnected}
-     *     when the service is unbound.
+     * Normally a TestableContext will pass through all bind requests to the base context
+     * but when addMockService has been called for a ComponentName being bound, then
+     * TestableContext will immediately trigger a {@link ServiceConnection#onServiceConnected}
+     * with the specified service, and will call {@link ServiceConnection#onServiceDisconnected}
+     * when the service is unbound.
      * </p>
+     *
+     * @see #addMockServiceResolver(MockServiceResolver) for custom resolution of service Intents to
+     * ComponentNames
      */
     public void addMockService(ComponentName component, IBinder service) {
         if (mMockServices == null) mMockServices = new ArrayMap<>();
@@ -227,12 +235,38 @@
     }
 
     /**
+     * Strategy to resolve a service {@link Intent} to a mock service {@link ComponentName}.
+     */
+    public interface MockServiceResolver {
+        @Nullable
+        ComponentName resolve(Intent service);
+    }
+
+    /**
+     * Registers a strategy to resolve service intents to registered mock services.
+     * <p>
+     * The result of the first {@link MockServiceResolver} to return a non-null
+     * {@link ComponentName} is used to look up a mock service. The mock service must be registered
+     * via {@link #addMockService(ComponentName, IBinder)} separately, using the same component
+     * name.
+     *
+     * If none of the resolvers return a non-null value, or the first returned component name
+     * does not link to a registered mock service, the bind requests are passed to the base context
+     *
+     * The resolvers are queried in order of registration.
+     */
+    public void addMockServiceResolver(MockServiceResolver resolver) {
+        if (mMockServiceResolvers == null) mMockServiceResolvers = new ArrayList<>();
+        mMockServiceResolvers.add(resolver);
+    }
+
+    /**
      * @see #addMockService(ComponentName, IBinder)
      */
     @Override
     public boolean bindService(Intent service, ServiceConnection conn, int flags) {
         if (mService != null) mService.getLeakInfo(conn).addAllocation(new Throwable());
-        if (checkMocks(service.getComponent(), conn)) return true;
+        if (checkMocks(service, conn)) return true;
         return super.bindService(service, conn, flags);
     }
 
@@ -243,7 +277,7 @@
     public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
             Handler handler, UserHandle user) {
         if (mService != null) mService.getLeakInfo(conn).addAllocation(new Throwable());
-        if (checkMocks(service.getComponent(), conn)) return true;
+        if (checkMocks(service, conn)) return true;
         return super.bindServiceAsUser(service, conn, flags, handler, user);
     }
 
@@ -254,18 +288,36 @@
     public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
             UserHandle user) {
         if (mService != null) mService.getLeakInfo(conn).addAllocation(new Throwable());
-        if (checkMocks(service.getComponent(), conn)) return true;
+        if (checkMocks(service, conn)) return true;
         return super.bindServiceAsUser(service, conn, flags, user);
     }
 
-    private boolean checkMocks(ComponentName component, ServiceConnection conn) {
-        if (mMockServices != null && component != null && mMockServices.containsKey(component)) {
-            if (mActiveServices == null) mActiveServices = new ArrayMap<>();
-            mActiveServices.put(conn, component);
-            conn.onServiceConnected(component, mMockServices.get(component));
-            return true;
+    private boolean checkMocks(Intent service, ServiceConnection conn) {
+        if (mMockServices == null) return false;
+
+        ComponentName serviceComponent = resolveMockServiceComponent(service);
+        if (serviceComponent == null) return false;
+
+        IBinder serviceImpl = mMockServices.get(serviceComponent);
+        if (serviceImpl == null) return false;
+
+        if (mActiveServices == null) mActiveServices = new ArrayMap<>();
+        mActiveServices.put(conn, serviceComponent);
+        conn.onServiceConnected(serviceComponent, serviceImpl);
+        return true;
+    }
+
+    private ComponentName resolveMockServiceComponent(Intent service) {
+        ComponentName specifiedComponentName = service.getComponent();
+        if (specifiedComponentName != null) return specifiedComponentName;
+
+        if (mMockServiceResolvers == null) return null;
+
+        for (MockServiceResolver resolver : mMockServiceResolvers) {
+            ComponentName resolvedComponent = resolver.resolve(service);
+            if (resolvedComponent != null) return resolvedComponent;
         }
-        return false;
+        return null;
     }
 
     /**