diff --git a/Android.bp b/Android.bp
index 0c199a634725826f55f3bfd4cfc5ca314763c631..7d5e788c5a37920d21fb79bea228a5dfe2c9a7bb 100644
--- a/Android.bp
+++ b/Android.bp
@@ -323,7 +323,6 @@ java_defaults {
             ":installd_aidl",
             ":libaudioclient_aidl",
             ":libbinder_aidl",
-            ":libbluetooth-binder-aidl",
             ":libcamera_client_aidl",
             ":libcamera_client_framework_aidl",
             ":libupdate_engine_aidl",
diff --git a/cmds/svc/src/com/android/commands/svc/NfcCommand.java b/cmds/svc/src/com/android/commands/svc/NfcCommand.java
index 870e0078450f7612aae369f07e14b94d20cfbbbf..ee2af129d4001fbb23298c3a8b15b7fb8dd534e7 100644
--- a/cmds/svc/src/com/android/commands/svc/NfcCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/NfcCommand.java
@@ -20,6 +20,7 @@ import android.app.ActivityThread;
 import android.content.Context;
 import android.nfc.NfcAdapter;
 import android.nfc.NfcManager;
+import android.os.Looper;
 
 public class NfcCommand extends Svc.Command {
 
@@ -42,6 +43,8 @@ public class NfcCommand extends Svc.Command {
 
     @Override
     public void run(String[] args) {
+        Looper.prepareMainLooper();
+        ActivityThread.initializeMainlineModules();
         Context context = ActivityThread.systemMain().getSystemContext();
         NfcManager nfcManager = context.getSystemService(NfcManager.class);
         if (nfcManager == null) {
diff --git a/core/api/current.txt b/core/api/current.txt
index 940be6b33467ea4363eb37883d3bc08bae3b0804..28f83d887c30c0551f5cc0093dedec8ce83e873f 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -9644,13 +9644,13 @@ package android.companion {
     method @Deprecated @MainThread public void onDeviceAppeared(@NonNull android.companion.AssociationInfo);
     method @Deprecated @MainThread public void onDeviceDisappeared(@NonNull String);
     method @Deprecated @MainThread public void onDeviceDisappeared(@NonNull android.companion.AssociationInfo);
-    method @MainThread public void onDeviceEvent(@NonNull android.companion.AssociationInfo, int);
-    field public static final int DEVICE_EVENT_BLE_APPEARED = 0; // 0x0
-    field public static final int DEVICE_EVENT_BLE_DISAPPEARED = 1; // 0x1
-    field public static final int DEVICE_EVENT_BT_CONNECTED = 2; // 0x2
-    field public static final int DEVICE_EVENT_BT_DISCONNECTED = 3; // 0x3
-    field public static final int DEVICE_EVENT_SELF_MANAGED_APPEARED = 4; // 0x4
-    field public static final int DEVICE_EVENT_SELF_MANAGED_DISAPPEARED = 5; // 0x5
+    method @FlaggedApi("android.companion.device_presence") @MainThread public void onDeviceEvent(@NonNull android.companion.AssociationInfo, int);
+    field @FlaggedApi("android.companion.device_presence") public static final int DEVICE_EVENT_BLE_APPEARED = 0; // 0x0
+    field @FlaggedApi("android.companion.device_presence") public static final int DEVICE_EVENT_BLE_DISAPPEARED = 1; // 0x1
+    field @FlaggedApi("android.companion.device_presence") public static final int DEVICE_EVENT_BT_CONNECTED = 2; // 0x2
+    field @FlaggedApi("android.companion.device_presence") public static final int DEVICE_EVENT_BT_DISCONNECTED = 3; // 0x3
+    field @FlaggedApi("android.companion.device_presence") public static final int DEVICE_EVENT_SELF_MANAGED_APPEARED = 4; // 0x4
+    field @FlaggedApi("android.companion.device_presence") public static final int DEVICE_EVENT_SELF_MANAGED_DISAPPEARED = 5; // 0x5
     field public static final String SERVICE_INTERFACE = "android.companion.CompanionDeviceService";
   }
 
@@ -11101,7 +11101,7 @@ package android.content {
     field public static final String EXTRA_ALLOW_MULTIPLE = "android.intent.extra.ALLOW_MULTIPLE";
     field @Deprecated public static final String EXTRA_ALLOW_REPLACE = "android.intent.extra.ALLOW_REPLACE";
     field public static final String EXTRA_ALTERNATE_INTENTS = "android.intent.extra.ALTERNATE_INTENTS";
-    field public static final String EXTRA_ARCHIVAL = "android.intent.extra.ARCHIVAL";
+    field @FlaggedApi("android.content.pm.archiving") public static final String EXTRA_ARCHIVAL = "android.intent.extra.ARCHIVAL";
     field public static final String EXTRA_ASSIST_CONTEXT = "android.intent.extra.ASSIST_CONTEXT";
     field public static final String EXTRA_ASSIST_INPUT_DEVICE_ID = "android.intent.extra.ASSIST_INPUT_DEVICE_ID";
     field public static final String EXTRA_ASSIST_INPUT_HINT_KEYBOARD = "android.intent.extra.ASSIST_INPUT_HINT_KEYBOARD";
@@ -11988,6 +11988,40 @@ package android.content.pm {
     method public final int compare(android.content.pm.ApplicationInfo, android.content.pm.ApplicationInfo);
   }
 
+  @FlaggedApi("android.content.pm.archiving") public final class ArchivedActivity {
+    ctor public ArchivedActivity(@NonNull CharSequence, @NonNull android.content.ComponentName);
+    method @NonNull public android.content.ComponentName getComponentName();
+    method @Nullable public android.graphics.drawable.Drawable getIcon();
+    method @NonNull public CharSequence getLabel();
+    method @Nullable public android.graphics.drawable.Drawable getMonochromeIcon();
+    method @NonNull public android.content.pm.ArchivedActivity setComponentName(@NonNull android.content.ComponentName);
+    method @NonNull public android.content.pm.ArchivedActivity setIcon(@NonNull android.graphics.drawable.Drawable);
+    method @NonNull public android.content.pm.ArchivedActivity setLabel(@NonNull CharSequence);
+    method @NonNull public android.content.pm.ArchivedActivity setMonochromeIcon(@NonNull android.graphics.drawable.Drawable);
+  }
+
+  @FlaggedApi("android.content.pm.archiving") public final class ArchivedPackage {
+    ctor public ArchivedPackage(@NonNull String, @NonNull android.content.pm.SigningInfo, @NonNull java.util.List<android.content.pm.ArchivedActivity>);
+    method @Nullable public String getDefaultToDeviceProtectedStorage();
+    method @NonNull public java.util.List<android.content.pm.ArchivedActivity> getLauncherActivities();
+    method @NonNull public String getPackageName();
+    method @Nullable public String getRequestLegacyExternalStorage();
+    method @NonNull public android.content.pm.SigningInfo getSigningInfo();
+    method public int getTargetSdkVersion();
+    method @Nullable public String getUserDataFragile();
+    method public int getVersionCode();
+    method public int getVersionCodeMajor();
+    method @NonNull public android.content.pm.ArchivedPackage setDefaultToDeviceProtectedStorage(@NonNull String);
+    method @NonNull public android.content.pm.ArchivedPackage setLauncherActivities(@NonNull java.util.List<android.content.pm.ArchivedActivity>);
+    method @NonNull public android.content.pm.ArchivedPackage setPackageName(@NonNull String);
+    method @NonNull public android.content.pm.ArchivedPackage setRequestLegacyExternalStorage(@NonNull String);
+    method @NonNull public android.content.pm.ArchivedPackage setSigningInfo(@NonNull android.content.pm.SigningInfo);
+    method @NonNull public android.content.pm.ArchivedPackage setTargetSdkVersion(int);
+    method @NonNull public android.content.pm.ArchivedPackage setUserDataFragile(@NonNull String);
+    method @NonNull public android.content.pm.ArchivedPackage setVersionCode(int);
+    method @NonNull public android.content.pm.ArchivedPackage setVersionCodeMajor(int);
+  }
+
   public final class Attribution implements android.os.Parcelable {
     method public int describeContents();
     method @IdRes public int getLabel();
@@ -12320,6 +12354,7 @@ package android.content.pm {
     method @Nullable public android.content.pm.PackageInstaller.SessionInfo getSessionInfo(int);
     method @NonNull public java.util.List<android.content.pm.PackageInstaller.SessionInfo> getStagedSessions();
     method @RequiresPermission(allOf={android.Manifest.permission.INSTALL_PACKAGES, "com.android.permission.INSTALL_EXISTING_PACKAGES"}) public void installExistingPackage(@NonNull String, int, @Nullable android.content.IntentSender);
+    method @FlaggedApi("android.content.pm.archiving") @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void installPackageArchived(@NonNull android.content.pm.ArchivedPackage, @NonNull android.content.pm.PackageInstaller.SessionParams, @NonNull android.content.IntentSender);
     method @NonNull public android.content.pm.PackageInstaller.Session openSession(int) throws java.io.IOException;
     method public void registerSessionCallback(@NonNull android.content.pm.PackageInstaller.SessionCallback);
     method public void registerSessionCallback(@NonNull android.content.pm.PackageInstaller.SessionCallback, @NonNull android.os.Handler);
@@ -12601,6 +12636,7 @@ package android.content.pm {
     method @NonNull public abstract CharSequence getApplicationLabel(@NonNull android.content.pm.ApplicationInfo);
     method @Nullable public abstract android.graphics.drawable.Drawable getApplicationLogo(@NonNull android.content.pm.ApplicationInfo);
     method @Nullable public abstract android.graphics.drawable.Drawable getApplicationLogo(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @FlaggedApi("android.content.pm.archiving") @Nullable public android.content.pm.ArchivedPackage getArchivedPackage(@NonNull String);
     method @NonNull public CharSequence getBackgroundPermissionOptionLabel();
     method @Nullable public abstract android.content.pm.ChangedPackages getChangedPackages(@IntRange(from=0) int);
     method public abstract int getComponentEnabledSetting(@NonNull android.content.ComponentName);
@@ -16259,6 +16295,8 @@ package android.graphics {
 
   public static class Paint.FontMetricsInt {
     ctor public Paint.FontMetricsInt();
+    method @FlaggedApi("com.android.text.flags.fix_line_height_for_locale") public void set(@NonNull android.graphics.Paint.FontMetricsInt);
+    method @FlaggedApi("com.android.text.flags.fix_line_height_for_locale") public void set(@NonNull android.graphics.Paint.FontMetrics);
     field public int ascent;
     field public int bottom;
     field public int descent;
@@ -33473,7 +33511,7 @@ package android.os {
     field public static final String DISALLOW_MICROPHONE_TOGGLE = "disallow_microphone_toggle";
     field public static final String DISALLOW_MODIFY_ACCOUNTS = "no_modify_accounts";
     field public static final String DISALLOW_MOUNT_PHYSICAL_MEDIA = "no_physical_media";
-    field public static final String DISALLOW_NEAR_FIELD_COMMUNICATION_RADIO = "no_near_field_communication_radio";
+    field @FlaggedApi("android.nfc.enable_nfc_user_restriction") public static final String DISALLOW_NEAR_FIELD_COMMUNICATION_RADIO = "no_near_field_communication_radio";
     field public static final String DISALLOW_NETWORK_RESET = "no_network_reset";
     field public static final String DISALLOW_OUTGOING_BEAM = "no_outgoing_beam";
     field public static final String DISALLOW_OUTGOING_CALLS = "no_outgoing_calls";
@@ -43125,6 +43163,7 @@ package android.telephony {
     field public static final String KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL = "show_iccid_in_sim_status_bool";
     field public static final String KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL = "show_ims_registration_status_bool";
     field public static final String KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL = "show_onscreen_dial_button_bool";
+    field @FlaggedApi("com.android.internal.telephony.flags.hide_roaming_icon") public static final String KEY_SHOW_ROAMING_INDICATOR_BOOL = "show_roaming_indicator_bool";
     field public static final String KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL = "show_signal_strength_in_sim_status_bool";
     field public static final String KEY_SHOW_VIDEO_CALL_CHARGES_ALERT_DIALOG_BOOL = "show_video_call_charges_alert_dialog_bool";
     field public static final String KEY_SHOW_WFC_LOCATION_PRIVACY_POLICY_BOOL = "show_wfc_location_privacy_policy_bool";
@@ -46719,6 +46758,7 @@ package android.text {
     method @NonNull public android.text.DynamicLayout.Builder setJustificationMode(int);
     method @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") @NonNull public android.text.DynamicLayout.Builder setLineBreakConfig(@NonNull android.graphics.text.LineBreakConfig);
     method @NonNull public android.text.DynamicLayout.Builder setLineSpacing(float, @FloatRange(from=0.0) float);
+    method @FlaggedApi("com.android.text.flags.fix_line_height_for_locale") @NonNull public android.text.DynamicLayout.Builder setMinimumFontMetrics(@Nullable android.graphics.Paint.FontMetrics);
     method @NonNull public android.text.DynamicLayout.Builder setTextDirection(@NonNull android.text.TextDirectionHeuristic);
     method @FlaggedApi("com.android.text.flags.use_bounds_for_width") @NonNull public android.text.DynamicLayout.Builder setUseBoundsForWidth(boolean);
     method @NonNull public android.text.DynamicLayout.Builder setUseLineSpacingFromFallbacks(boolean);
@@ -46907,6 +46947,7 @@ package android.text {
     method public int getLineVisibleEnd(int);
     method public float getLineWidth(int);
     method @FlaggedApi("com.android.text.flags.use_bounds_for_width") @IntRange(from=1) public final int getMaxLines();
+    method @FlaggedApi("com.android.text.flags.fix_line_height_for_locale") @Nullable public android.graphics.Paint.FontMetrics getMinimumFontMetrics();
     method public int getOffsetForHorizontal(int, float);
     method public int getOffsetToLeftOf(int);
     method public int getOffsetToRightOf(int);
@@ -46973,6 +47014,7 @@ package android.text {
     method @NonNull public android.text.Layout.Builder setLineSpacingAmount(float);
     method @NonNull public android.text.Layout.Builder setLineSpacingMultiplier(@FloatRange(from=0) float);
     method @NonNull public android.text.Layout.Builder setMaxLines(@IntRange(from=1) int);
+    method @FlaggedApi("com.android.text.flags.fix_line_height_for_locale") @NonNull public android.text.Layout.Builder setMinimumFontMetrics(@Nullable android.graphics.Paint.FontMetrics);
     method @NonNull public android.text.Layout.Builder setRightIndents(@Nullable int[]);
     method @NonNull public android.text.Layout.Builder setTextDirectionHeuristic(@NonNull android.text.TextDirectionHeuristic);
     method @FlaggedApi("com.android.text.flags.use_bounds_for_width") @NonNull public android.text.Layout.Builder setUseBoundsForWidth(boolean);
@@ -47244,6 +47286,7 @@ package android.text {
     method @NonNull public android.text.StaticLayout.Builder setLineBreakConfig(@NonNull android.graphics.text.LineBreakConfig);
     method @NonNull public android.text.StaticLayout.Builder setLineSpacing(float, @FloatRange(from=0.0) float);
     method @NonNull public android.text.StaticLayout.Builder setMaxLines(@IntRange(from=0) int);
+    method @FlaggedApi("com.android.text.flags.fix_line_height_for_locale") @NonNull public android.text.StaticLayout.Builder setMinimumFontMetrics(@Nullable android.graphics.Paint.FontMetrics);
     method public android.text.StaticLayout.Builder setText(CharSequence);
     method @NonNull public android.text.StaticLayout.Builder setTextDirection(@NonNull android.text.TextDirectionHeuristic);
     method @FlaggedApi("com.android.text.flags.use_bounds_for_width") @NonNull public android.text.StaticLayout.Builder setUseBoundsForWidth(boolean);
@@ -59922,6 +59965,7 @@ package android.widget {
     method public int getMinHeight();
     method public int getMinLines();
     method public int getMinWidth();
+    method @FlaggedApi("com.android.text.flags.fix_line_height_for_locale") @Nullable public android.graphics.Paint.FontMetrics getMinimumFontMetrics();
     method public final android.text.method.MovementMethod getMovementMethod();
     method public int getOffsetForPosition(float, float);
     method public android.text.TextPaint getPaint();
@@ -60058,6 +60102,7 @@ package android.widget {
     method public void setMinHeight(int);
     method public void setMinLines(int);
     method public void setMinWidth(int);
+    method @FlaggedApi("com.android.text.flags.fix_line_height_for_locale") public void setMinimumFontMetrics(@Nullable android.graphics.Paint.FontMetrics);
     method public final void setMovementMethod(android.text.method.MovementMethod);
     method public void setOnEditorActionListener(android.widget.TextView.OnEditorActionListener);
     method public void setPaintFlags(int);
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 21ed098f448a4f5fa0882238d568557e9792133a..fd308ce2e85a74075470c2131a68f4f45e4eafa6 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -48,6 +48,7 @@ import android.content.IntentSender;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApkChecksum;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.ArchivedPackage;
 import android.content.pm.ChangedPackages;
 import android.content.pm.Checksum;
 import android.content.pm.ComponentInfo;
@@ -3935,6 +3936,19 @@ public class ApplicationPackageManager extends PackageManager {
         }
     }
 
+    @Override
+    public @Nullable ArchivedPackage getArchivedPackage(@NonNull String packageName) {
+        try {
+            var parcel = mPM.getArchivedPackage(packageName, mContext.getUserId());
+            if (parcel == null) {
+                return null;
+            }
+            return new ArchivedPackage(parcel);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
     @Override
     public boolean canUserUninstall(String packageName, UserHandle user) {
         try {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 94e1292a75546619e43897c91b9a7e893f99aaa4..3bde39c03f255b0eb8c745e09f20893afeaffdc6 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -5607,7 +5607,8 @@ public class Notification implements Parcelable
             // Use different highlighted colors for conversations' unread count
             if (p.mHighlightExpander) {
                 pillColor = Colors.flattenAlpha(getColors(p).getTertiaryAccentColor(), bgColor);
-                textColor = Colors.flattenAlpha(getColors(p).getOnAccentTextColor(), pillColor);
+                textColor = Colors.flattenAlpha(
+                        getColors(p).getOnTertiaryAccentTextColor(), pillColor);
             }
             contentView.setInt(R.id.expand_button, "setHighlightTextColor", textColor);
             contentView.setInt(R.id.expand_button, "setHighlightPillColor", pillColor);
@@ -12833,7 +12834,7 @@ public class Notification implements Parcelable
         private int mPrimaryAccentColor = COLOR_INVALID;
         private int mSecondaryAccentColor = COLOR_INVALID;
         private int mTertiaryAccentColor = COLOR_INVALID;
-        private int mOnAccentTextColor = COLOR_INVALID;
+        private int mOnTertiaryAccentTextColor = COLOR_INVALID;
         private int mErrorColor = COLOR_INVALID;
         private int mContrastColor = COLOR_INVALID;
         private int mRippleAlpha = 0x33;
@@ -12908,7 +12909,7 @@ public class Notification implements Parcelable
                 mPrimaryAccentColor = mPrimaryTextColor;
                 mSecondaryAccentColor = mSecondaryTextColor;
                 mTertiaryAccentColor = flattenAlpha(mPrimaryTextColor, mBackgroundColor);
-                mOnAccentTextColor = mBackgroundColor;
+                mOnTertiaryAccentTextColor = mBackgroundColor;
                 mErrorColor = mPrimaryTextColor;
                 mRippleAlpha = 0x33;
             } else {
@@ -12930,7 +12931,7 @@ public class Notification implements Parcelable
                     mPrimaryAccentColor = getColor(ta, 3, COLOR_INVALID);
                     mSecondaryAccentColor = getColor(ta, 4, COLOR_INVALID);
                     mTertiaryAccentColor = getColor(ta, 5, COLOR_INVALID);
-                    mOnAccentTextColor = getColor(ta, 6, COLOR_INVALID);
+                    mOnTertiaryAccentTextColor = getColor(ta, 6, COLOR_INVALID);
                     mErrorColor = getColor(ta, 7, COLOR_INVALID);
                     mRippleAlpha = Color.alpha(getColor(ta, 8, 0x33ffffff));
                 }
@@ -12955,8 +12956,8 @@ public class Notification implements Parcelable
                 if (mTertiaryAccentColor == COLOR_INVALID) {
                     mTertiaryAccentColor = mContrastColor;
                 }
-                if (mOnAccentTextColor == COLOR_INVALID) {
-                    mOnAccentTextColor = ColorUtils.setAlphaComponent(
+                if (mOnTertiaryAccentTextColor == COLOR_INVALID) {
+                    mOnTertiaryAccentTextColor = ColorUtils.setAlphaComponent(
                             ContrastColorUtil.resolvePrimaryColor(
                                     ctx, mTertiaryAccentColor, nightMode), 0xFF);
                 }
@@ -13029,8 +13030,8 @@ public class Notification implements Parcelable
         }
 
         /** @return the theme's text color to be used on the tertiary accent color. */
-        public @ColorInt int getOnAccentTextColor() {
-            return mOnAccentTextColor;
+        public @ColorInt int getOnTertiaryAccentTextColor() {
+            return mOnTertiaryAccentTextColor;
         }
 
         /**
diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig
index f99615fd2ef4f6652977a7f6e8ee7168731cbf4a..5a41c65535e6ca013fdbaf15d6e90a68c6be9692 100644
--- a/core/java/android/app/admin/flags/flags.aconfig
+++ b/core/java/android/app/admin/flags/flags.aconfig
@@ -27,3 +27,17 @@ flag {
   description: "Allow holders of INTERACT_ACROSS_USERS_FULL to suspend apps in different users."
   bug: "263464464"
 }
+
+flag {
+  name: "dedicated_device_control_enabled"
+  namespace: "enterprise"
+  description: "Allow the device management role holder to control which platform features are available on dedicated devices."
+  bug: "281964214"
+}
+
+flag {
+  name: "security_log_v2_enabled"
+  namespace: "enterprise"
+  description: "Improve access to security logging in the context of Zero Trust."
+  bug: "295324350"
+}
diff --git a/core/java/android/app/servertransaction/ActivityLifecycleItem.java b/core/java/android/app/servertransaction/ActivityLifecycleItem.java
index b34f6788fb6014f0e29ca18c222ada189b10e8ff..06bff5df490a67690323808f5cf68dccd017b023 100644
--- a/core/java/android/app/servertransaction/ActivityLifecycleItem.java
+++ b/core/java/android/app/servertransaction/ActivityLifecycleItem.java
@@ -58,6 +58,11 @@ public abstract class ActivityLifecycleItem extends ActivityTransactionItem {
         super(in);
     }
 
+    @Override
+    boolean isActivityLifecycleItem() {
+        return true;
+    }
+
     /** A final lifecycle state that an activity should reach. */
     @LifecycleState
     public abstract int getTargetState();
diff --git a/core/java/android/app/servertransaction/ClientTransaction.java b/core/java/android/app/servertransaction/ClientTransaction.java
index 8617386516afb7ccc88baccb39104870fdb04dc5..9c0cd39e81029076de6c9e25973b71314e1e9735 100644
--- a/core/java/android/app/servertransaction/ClientTransaction.java
+++ b/core/java/android/app/servertransaction/ClientTransaction.java
@@ -45,6 +45,13 @@ import java.util.Objects;
  */
 public class ClientTransaction implements Parcelable, ObjectPoolItem {
 
+    /**
+     * List of transaction items that should be executed in order. Including both
+     * {@link ActivityLifecycleItem} and other {@link ClientTransactionItem}.
+     */
+    @Nullable
+    private List<ClientTransactionItem> mTransactionItems;
+
     /** A list of individual callbacks to a client. */
     @UnsupportedAppUsage
     private List<ClientTransactionItem> mActivityCallbacks;
@@ -64,9 +71,32 @@ public class ClientTransaction implements Parcelable, ObjectPoolItem {
     }
 
     /**
-     * Add a message to the end of the sequence of callbacks.
+     * Adds a message to the end of the sequence of transaction items.
+     * @param item A single message that can contain a client activity/window request/callback.
+     * TODO(b/260873529): replace both {@link #addCallback} and {@link #setLifecycleStateRequest}.
+     */
+    public void addTransactionItem(@NonNull ClientTransactionItem item) {
+        if (mTransactionItems == null) {
+            mTransactionItems = new ArrayList<>();
+        }
+        mTransactionItems.add(item);
+    }
+
+    /**
+     * Gets the list of client window requests/callbacks.
+     * TODO(b/260873529): must be non null after remove the deprecated methods.
+     */
+    @Nullable
+    public List<ClientTransactionItem> getTransactionItems() {
+        return mTransactionItems;
+    }
+
+    /**
+     * Adds a message to the end of the sequence of callbacks.
      * @param activityCallback A single message that can contain a lifecycle request/callback.
+     * @deprecated use {@link #addTransactionItem(ClientTransactionItem)} instead.
      */
+    @Deprecated
     public void addCallback(@NonNull ClientTransactionItem activityCallback) {
         if (mActivityCallbacks == null) {
             mActivityCallbacks = new ArrayList<>();
@@ -74,25 +104,35 @@ public class ClientTransaction implements Parcelable, ObjectPoolItem {
         mActivityCallbacks.add(activityCallback);
     }
 
-    /** Get the list of callbacks. */
+    /**
+     * Gets the list of callbacks.
+     * @deprecated use {@link #getTransactionItems()} instead.
+     */
     @Nullable
     @VisibleForTesting
     @UnsupportedAppUsage
+    @Deprecated
     public List<ClientTransactionItem> getCallbacks() {
         return mActivityCallbacks;
     }
 
-    /** Get the target state lifecycle request. */
+    /**
+     * Gets the target state lifecycle request.
+     * @deprecated use {@link #getTransactionItems()} instead.
+     */
     @VisibleForTesting(visibility = PACKAGE)
     @UnsupportedAppUsage
+    @Deprecated
     public ActivityLifecycleItem getLifecycleStateRequest() {
         return mLifecycleStateRequest;
     }
 
     /**
-     * Set the lifecycle state in which the client should be after executing the transaction.
+     * Sets the lifecycle state in which the client should be after executing the transaction.
      * @param stateRequest A lifecycle request initialized with right parameters.
+     * @deprecated use {@link #addTransactionItem(ClientTransactionItem)} instead.
      */
+    @Deprecated
     public void setLifecycleStateRequest(@NonNull ActivityLifecycleItem stateRequest) {
         mLifecycleStateRequest = stateRequest;
     }
@@ -103,6 +143,14 @@ public class ClientTransaction implements Parcelable, ObjectPoolItem {
      *                                 requested by transaction items.
      */
     public void preExecute(@NonNull ClientTransactionHandler clientTransactionHandler) {
+        if (mTransactionItems != null) {
+            final int size = mTransactionItems.size();
+            for (int i = 0; i < size; ++i) {
+                mTransactionItems.get(i).preExecute(clientTransactionHandler);
+            }
+            return;
+        }
+
         if (mActivityCallbacks != null) {
             final int size = mActivityCallbacks.size();
             for (int i = 0; i < size; ++i) {
@@ -147,6 +195,13 @@ public class ClientTransaction implements Parcelable, ObjectPoolItem {
 
     @Override
     public void recycle() {
+        if (mTransactionItems != null) {
+            int size = mTransactionItems.size();
+            for (int i = 0; i < size; i++) {
+                mTransactionItems.get(i).recycle();
+            }
+            mTransactionItems = null;
+        }
         if (mActivityCallbacks != null) {
             int size = mActivityCallbacks.size();
             for (int i = 0; i < size; i++) {
@@ -165,8 +220,15 @@ public class ClientTransaction implements Parcelable, ObjectPoolItem {
     // Parcelable implementation
 
     /** Write to Parcel. */
+    @SuppressWarnings("AndroidFrameworkEfficientParcelable") // Item class is not final.
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
+        final boolean writeTransactionItems = mTransactionItems != null;
+        dest.writeBoolean(writeTransactionItems);
+        if (writeTransactionItems) {
+            dest.writeParcelableList(mTransactionItems, flags);
+        }
+
         dest.writeParcelable(mLifecycleStateRequest, flags);
         final boolean writeActivityCallbacks = mActivityCallbacks != null;
         dest.writeBoolean(writeActivityCallbacks);
@@ -177,11 +239,20 @@ public class ClientTransaction implements Parcelable, ObjectPoolItem {
 
     /** Read from Parcel. */
     private ClientTransaction(@NonNull Parcel in) {
-        mLifecycleStateRequest = in.readParcelable(getClass().getClassLoader(), android.app.servertransaction.ActivityLifecycleItem.class);
+        final boolean readTransactionItems = in.readBoolean();
+        if (readTransactionItems) {
+            mTransactionItems = new ArrayList<>();
+            in.readParcelableList(mTransactionItems, getClass().getClassLoader(),
+                    ClientTransactionItem.class);
+        }
+
+        mLifecycleStateRequest = in.readParcelable(getClass().getClassLoader(),
+                ActivityLifecycleItem.class);
         final boolean readActivityCallbacks = in.readBoolean();
         if (readActivityCallbacks) {
             mActivityCallbacks = new ArrayList<>();
-            in.readParcelableList(mActivityCallbacks, getClass().getClassLoader(), android.app.servertransaction.ClientTransactionItem.class);
+            in.readParcelableList(mActivityCallbacks, getClass().getClassLoader(),
+                    ClientTransactionItem.class);
         }
     }
 
@@ -209,7 +280,8 @@ public class ClientTransaction implements Parcelable, ObjectPoolItem {
             return false;
         }
         final ClientTransaction other = (ClientTransaction) o;
-        return Objects.equals(mActivityCallbacks, other.mActivityCallbacks)
+        return Objects.equals(mTransactionItems, other.mTransactionItems)
+                && Objects.equals(mActivityCallbacks, other.mActivityCallbacks)
                 && Objects.equals(mLifecycleStateRequest, other.mLifecycleStateRequest)
                 && mClient == other.mClient;
     }
@@ -217,6 +289,7 @@ public class ClientTransaction implements Parcelable, ObjectPoolItem {
     @Override
     public int hashCode() {
         int result = 17;
+        result = 31 * result + Objects.hashCode(mTransactionItems);
         result = 31 * result + Objects.hashCode(mActivityCallbacks);
         result = 31 * result + Objects.hashCode(mLifecycleStateRequest);
         result = 31 * result + Objects.hashCode(mClient);
@@ -227,6 +300,22 @@ public class ClientTransaction implements Parcelable, ObjectPoolItem {
     void dump(@NonNull String prefix, @NonNull PrintWriter pw,
             @NonNull ClientTransactionHandler transactionHandler) {
         pw.append(prefix).println("ClientTransaction{");
+        if (mTransactionItems != null) {
+            pw.append(prefix).print("  transactionItems=[");
+            final String itemPrefix = prefix + "    ";
+            final int size = mTransactionItems.size();
+            if (size > 0) {
+                pw.println();
+                for (int i = 0; i < size; i++) {
+                    mTransactionItems.get(i).dump(itemPrefix, pw, transactionHandler);
+                }
+                pw.append(prefix).println("  ]");
+            } else {
+                pw.println("]");
+            }
+            pw.append(prefix).println("}");
+            return;
+        }
         pw.append(prefix).print("  callbacks=[");
         final String itemPrefix = prefix + "    ";
         final int size = mActivityCallbacks != null ? mActivityCallbacks.size() : 0;
diff --git a/core/java/android/app/servertransaction/ClientTransactionItem.java b/core/java/android/app/servertransaction/ClientTransactionItem.java
index 07e5a7dc5f0272695f6d09059b45468217d463e3..f94e22de06e5e7bc027c341f20a236297682ca3e 100644
--- a/core/java/android/app/servertransaction/ClientTransactionItem.java
+++ b/core/java/android/app/servertransaction/ClientTransactionItem.java
@@ -72,6 +72,13 @@ public abstract class ClientTransactionItem implements BaseClientRequest, Parcel
         return null;
     }
 
+    /**
+     * Whether this is a {@link ActivityLifecycleItem}.
+     */
+    boolean isActivityLifecycleItem() {
+        return false;
+    }
+
     /** Dumps this transaction item. */
     void dump(@NonNull String prefix, @NonNull PrintWriter pw,
             @NonNull ClientTransactionHandler transactionHandler) {
diff --git a/core/java/android/app/servertransaction/TransactionExecutor.java b/core/java/android/app/servertransaction/TransactionExecutor.java
index 066f9fe8497042505b74134346e05648d0ab9447..9f5e0dc14cca77aa98942cfdfa04fdaf98fa7954 100644
--- a/core/java/android/app/servertransaction/TransactionExecutor.java
+++ b/core/java/android/app/servertransaction/TransactionExecutor.java
@@ -28,6 +28,7 @@ import static android.app.servertransaction.ActivityLifecycleItem.UNDEFINED;
 import static android.app.servertransaction.TransactionExecutorHelper.getShortActivityName;
 import static android.app.servertransaction.TransactionExecutorHelper.getStateName;
 import static android.app.servertransaction.TransactionExecutorHelper.lastCallbackRequestingState;
+import static android.app.servertransaction.TransactionExecutorHelper.shouldExcludeLastLifecycleState;
 import static android.app.servertransaction.TransactionExecutorHelper.tId;
 import static android.app.servertransaction.TransactionExecutorHelper.transactionToString;
 
@@ -61,6 +62,9 @@ public class TransactionExecutor {
     private final PendingTransactionActions mPendingActions = new PendingTransactionActions();
     private final TransactionExecutorHelper mHelper = new TransactionExecutorHelper();
 
+    /** Keeps track of display ids whose Configuration got updated within a transaction. */
+    private final ArraySet<Integer> mConfigUpdatedDisplayIds = new ArraySet<>();
+
     /** Initialize an instance with transaction handler, that will execute all requested actions. */
     public TransactionExecutor(@NonNull ClientTransactionHandler clientTransactionHandler) {
         mTransactionHandler = clientTransactionHandler;
@@ -79,15 +83,52 @@ public class TransactionExecutor {
             Slog.d(TAG, transactionToString(transaction, mTransactionHandler));
         }
 
-        executeCallbacks(transaction);
-        executeLifecycleState(transaction);
+        if (transaction.getTransactionItems() != null) {
+            executeTransactionItems(transaction);
+        } else {
+            // TODO(b/260873529): cleanup after launch.
+            executeCallbacks(transaction);
+            executeLifecycleState(transaction);
+        }
+
+        if (!mConfigUpdatedDisplayIds.isEmpty()) {
+            // Whether this transaction should trigger DisplayListener#onDisplayChanged.
+            final ClientTransactionListenerController controller =
+                    ClientTransactionListenerController.getInstance();
+            final int displayCount = mConfigUpdatedDisplayIds.size();
+            for (int i = 0; i < displayCount; i++) {
+                final int displayId = mConfigUpdatedDisplayIds.valueAt(i);
+                controller.onDisplayChanged(displayId);
+            }
+            mConfigUpdatedDisplayIds.clear();
+        }
 
         mPendingActions.clear();
         if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "End resolving transaction");
     }
 
-    /** Cycle through all states requested by callbacks and execute them at proper times. */
+    /** Cycles through all transaction items and execute them at proper times. */
     @VisibleForTesting
+    public void executeTransactionItems(@NonNull ClientTransaction transaction) {
+        final List<ClientTransactionItem> items = transaction.getTransactionItems();
+        final int size = items.size();
+        for (int i = 0; i < size; i++) {
+            final ClientTransactionItem item = items.get(i);
+            if (item.isActivityLifecycleItem()) {
+                executeLifecycleItem(transaction, (ActivityLifecycleItem) item);
+            } else {
+                executeNonLifecycleItem(transaction, item,
+                        shouldExcludeLastLifecycleState(items, i));
+            }
+        }
+    }
+
+    /**
+     * Cycle through all states requested by callbacks and execute them at proper times.
+     * @deprecated use {@link #executeTransactionItems} instead.
+     */
+    @VisibleForTesting
+    @Deprecated
     public void executeCallbacks(@NonNull ClientTransaction transaction) {
         final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
         if (callbacks == null || callbacks.isEmpty()) {
@@ -105,83 +146,78 @@ public class TransactionExecutor {
         // Index of the last callback that requests some post-execution state.
         final int lastCallbackRequestingState = lastCallbackRequestingState(transaction);
 
-        // Keep track of display ids whose Configuration got updated with this transaction.
-        ArraySet<Integer> configUpdatedDisplays = null;
-
         final int size = callbacks.size();
         for (int i = 0; i < size; ++i) {
             final ClientTransactionItem item = callbacks.get(i);
-            final IBinder token = item.getActivityToken();
-            ActivityClientRecord r = mTransactionHandler.getActivityClient(token);
-
-            if (token != null && r == null
-                    && mTransactionHandler.getActivitiesToBeDestroyed().containsKey(token)) {
-                // The activity has not been created but has been requested to destroy, so all
-                // transactions for the token are just like being cancelled.
-                Slog.w(TAG, "Skip pre-destroyed transaction item:\n" + item);
-                continue;
-            }
 
-            if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "Resolving callback: " + item);
+            // Skip the very last transition and perform it by explicit state request instead.
             final int postExecutionState = item.getPostExecutionState();
+            final boolean shouldExcludeLastLifecycleState = postExecutionState != UNDEFINED
+                    && i == lastCallbackRequestingState && finalState == postExecutionState;
+            executeNonLifecycleItem(transaction, item, shouldExcludeLastLifecycleState);
+        }
+    }
 
-            if (item.shouldHaveDefinedPreExecutionState()) {
-                final int closestPreExecutionState = mHelper.getClosestPreExecutionState(r,
-                        item.getPostExecutionState());
-                if (closestPreExecutionState != UNDEFINED) {
-                    cycleToPath(r, closestPreExecutionState, transaction);
-                }
-            }
+    private void executeNonLifecycleItem(@NonNull ClientTransaction transaction,
+            @NonNull ClientTransactionItem item, boolean shouldExcludeLastLifecycleState) {
+        final IBinder token = item.getActivityToken();
+        ActivityClientRecord r = mTransactionHandler.getActivityClient(token);
 
-            // Can't read flag from isolated process.
-            final boolean isSyncWindowConfigUpdateFlagEnabled = !Process.isIsolated()
-                    && syncWindowConfigUpdateFlag();
-            final Context configUpdatedContext = isSyncWindowConfigUpdateFlagEnabled
-                    ? item.getContextToUpdate(mTransactionHandler)
-                    : null;
-            final Configuration preExecutedConfig = configUpdatedContext != null
-                    ? new Configuration(configUpdatedContext.getResources().getConfiguration())
-                    : null;
-
-            item.execute(mTransactionHandler, mPendingActions);
-
-            if (configUpdatedContext != null) {
-                final Configuration postExecutedConfig = configUpdatedContext.getResources()
-                        .getConfiguration();
-                if (!areConfigurationsEqualForDisplay(postExecutedConfig, preExecutedConfig)) {
-                    if (configUpdatedDisplays == null) {
-                        configUpdatedDisplays = new ArraySet<>();
-                    }
-                    configUpdatedDisplays.add(configUpdatedContext.getDisplayId());
-                }
-            }
+        if (token != null && r == null
+                && mTransactionHandler.getActivitiesToBeDestroyed().containsKey(token)) {
+            // The activity has not been created but has been requested to destroy, so all
+            // transactions for the token are just like being cancelled.
+            Slog.w(TAG, "Skip pre-destroyed transaction item:\n" + item);
+            return;
+        }
 
-            item.postExecute(mTransactionHandler, mPendingActions);
-            if (r == null) {
-                // Launch activity request will create an activity record.
-                r = mTransactionHandler.getActivityClient(token);
-            }
+        if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "Resolving callback: " + item);
+        final int postExecutionState = item.getPostExecutionState();
 
-            if (postExecutionState != UNDEFINED && r != null) {
-                // Skip the very last transition and perform it by explicit state request instead.
-                final boolean shouldExcludeLastTransition =
-                        i == lastCallbackRequestingState && finalState == postExecutionState;
-                cycleToPath(r, postExecutionState, shouldExcludeLastTransition, transaction);
+        if (item.shouldHaveDefinedPreExecutionState()) {
+            final int closestPreExecutionState = mHelper.getClosestPreExecutionState(r,
+                    postExecutionState);
+            if (closestPreExecutionState != UNDEFINED) {
+                cycleToPath(r, closestPreExecutionState, transaction);
             }
         }
 
-        if (configUpdatedDisplays != null) {
-            final ClientTransactionListenerController controller =
-                    ClientTransactionListenerController.getInstance();
-            final int displayCount = configUpdatedDisplays.size();
-            for (int i = 0; i < displayCount; i++) {
-                final int displayId = configUpdatedDisplays.valueAt(i);
-                controller.onDisplayChanged(displayId);
+        // Can't read flag from isolated process.
+        final boolean isSyncWindowConfigUpdateFlagEnabled = !Process.isIsolated()
+                && syncWindowConfigUpdateFlag();
+        final Context configUpdatedContext = isSyncWindowConfigUpdateFlagEnabled
+                ? item.getContextToUpdate(mTransactionHandler)
+                : null;
+        final Configuration preExecutedConfig = configUpdatedContext != null
+                ? new Configuration(configUpdatedContext.getResources().getConfiguration())
+                : null;
+
+        item.execute(mTransactionHandler, mPendingActions);
+
+        if (configUpdatedContext != null) {
+            final Configuration postExecutedConfig = configUpdatedContext.getResources()
+                    .getConfiguration();
+            if (!areConfigurationsEqualForDisplay(postExecutedConfig, preExecutedConfig)) {
+                mConfigUpdatedDisplayIds.add(configUpdatedContext.getDisplayId());
             }
         }
+
+        item.postExecute(mTransactionHandler, mPendingActions);
+        if (r == null) {
+            // Launch activity request will create an activity record.
+            r = mTransactionHandler.getActivityClient(token);
+        }
+
+        if (postExecutionState != UNDEFINED && r != null) {
+            cycleToPath(r, postExecutionState, shouldExcludeLastLifecycleState, transaction);
+        }
     }
 
-    /** Transition to the final state if requested by the transaction. */
+    /**
+     * Transition to the final state if requested by the transaction.
+     * @deprecated use {@link #executeTransactionItems} instead
+     */
+    @Deprecated
     private void executeLifecycleState(@NonNull ClientTransaction transaction) {
         final ActivityLifecycleItem lifecycleItem = transaction.getLifecycleStateRequest();
         if (lifecycleItem == null) {
@@ -189,6 +225,11 @@ public class TransactionExecutor {
             return;
         }
 
+        executeLifecycleItem(transaction, lifecycleItem);
+    }
+
+    private void executeLifecycleItem(@NonNull ClientTransaction transaction,
+            @NonNull ActivityLifecycleItem lifecycleItem) {
         final IBinder token = lifecycleItem.getActivityToken();
         final ActivityClientRecord r = mTransactionHandler.getActivityClient(token);
         if (DEBUG_RESOLVER) {
diff --git a/core/java/android/app/servertransaction/TransactionExecutorHelper.java b/core/java/android/app/servertransaction/TransactionExecutorHelper.java
index 7e89a5b45a2d44369ef480f004fd1b0de724ebba..dfbccb41d045729594eda00c10b826c3d398837e 100644
--- a/core/java/android/app/servertransaction/TransactionExecutorHelper.java
+++ b/core/java/android/app/servertransaction/TransactionExecutorHelper.java
@@ -236,21 +236,39 @@ public class TransactionExecutorHelper {
      * index 1 will be returned, because ActivityResult request on position 1 will be the last
      * request that moves activity to the RESUMED state where it will eventually end.
      */
-    static int lastCallbackRequestingState(ClientTransaction transaction) {
+    static int lastCallbackRequestingState(@NonNull ClientTransaction transaction) {
         final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
-        if (callbacks == null || callbacks.size() == 0) {
+        if (callbacks == null || callbacks.isEmpty()
+                || transaction.getLifecycleStateRequest() == null) {
             return -1;
         }
+        return lastCallbackRequestingStateIndex(callbacks, 0, callbacks.size() - 1,
+                transaction.getLifecycleStateRequest().getActivityToken());
+    }
 
+    /**
+     * Returns the index of the last callback between the start index and last index that requests
+     * the state for the given activity token in which that activity will be after execution.
+     * If there is a group of callbacks in the end that requests the same specific state or doesn't
+     * request any - we will find the first one from such group.
+     *
+     * E.g. ActivityResult requests RESUMED post-execution state, Configuration does not request any
+     * specific state. If there is a sequence
+     *   Configuration - ActivityResult - Configuration - ActivityResult
+     * index 1 will be returned, because ActivityResult request on position 1 will be the last
+     * request that moves activity to the RESUMED state where it will eventually end.
+     */
+    private static int lastCallbackRequestingStateIndex(@NonNull List<ClientTransactionItem> items,
+            int startIndex, int lastIndex, @NonNull IBinder activityToken) {
         // Go from the back of the list to front, look for the request closes to the beginning that
         // requests the state in which activity will end after all callbacks are executed.
         int lastRequestedState = UNDEFINED;
         int lastRequestingCallback = -1;
-        for (int i = callbacks.size() - 1; i >= 0; i--) {
-            final ClientTransactionItem callback = callbacks.get(i);
-            final int postExecutionState = callback.getPostExecutionState();
-            if (postExecutionState != UNDEFINED) {
-                // Found a callback that requests some post-execution state.
+        for (int i = lastIndex; i >= startIndex; i--) {
+            final ClientTransactionItem item = items.get(i);
+            final int postExecutionState = item.getPostExecutionState();
+            if (postExecutionState != UNDEFINED && activityToken.equals(item.getActivityToken())) {
+                // Found a callback that requests some post-execution state for the given activity.
                 if (lastRequestedState == UNDEFINED || lastRequestedState == postExecutionState) {
                     // It's either a first-from-end callback that requests state or it requests
                     // the same state as the last one. In both cases, we will use it as the new
@@ -266,6 +284,53 @@ public class TransactionExecutorHelper {
         return lastRequestingCallback;
     }
 
+    /**
+     * For the transaction item at {@code currentIndex}, if it is requesting post execution state,
+     * whether or not to exclude the last state. This only returns {@code true} when there is a
+     * following explicit {@link ActivityLifecycleItem} requesting the same state for the same
+     * activity, so that last state will be covered by the following {@link ActivityLifecycleItem}.
+     */
+    static boolean shouldExcludeLastLifecycleState(@NonNull List<ClientTransactionItem> items,
+            int currentIndex) {
+        final ClientTransactionItem item = items.get(currentIndex);
+        final IBinder activityToken = item.getActivityToken();
+        final int postExecutionState = item.getPostExecutionState();
+        if (activityToken == null || postExecutionState == UNDEFINED) {
+            // Not a transaction item requesting post execution state.
+            return false;
+        }
+        final int nextLifecycleItemIndex = findNextLifecycleItemIndex(items, currentIndex + 1,
+                activityToken);
+        if (nextLifecycleItemIndex == -1) {
+            // No following ActivityLifecycleItem for this activity token.
+            return false;
+        }
+        final ActivityLifecycleItem lifecycleItem =
+                (ActivityLifecycleItem) items.get(nextLifecycleItemIndex);
+        if (postExecutionState != lifecycleItem.getTargetState()) {
+            // The explicit ActivityLifecycleItem is not requesting the same state.
+            return false;
+        }
+        // Only exclude for the first non-lifecycle item that requests the same specific state.
+        return currentIndex == lastCallbackRequestingStateIndex(items, currentIndex,
+                nextLifecycleItemIndex - 1, activityToken);
+    }
+
+    /**
+     * Finds the index of the next {@link ActivityLifecycleItem} for the given activity token.
+     */
+    private static int findNextLifecycleItemIndex(@NonNull List<ClientTransactionItem> items,
+            int startIndex, @NonNull IBinder activityToken) {
+        final int size = items.size();
+        for (int i = startIndex; i < size; i++) {
+            final ClientTransactionItem item = items.get(i);
+            if (item.isActivityLifecycleItem() && item.getActivityToken().equals(activityToken)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
     /** Dump transaction to string. */
     static String transactionToString(@NonNull ClientTransaction transaction,
             @NonNull ClientTransactionHandler transactionHandler) {
diff --git a/core/java/android/companion/CompanionDeviceService.java b/core/java/android/companion/CompanionDeviceService.java
index 570ecaa47b4e49539fe389399bae7424bf5b74fa..c99a45764de7f3c23cd49525b75f7046c04e7ecb 100644
--- a/core/java/android/companion/CompanionDeviceService.java
+++ b/core/java/android/companion/CompanionDeviceService.java
@@ -17,6 +17,7 @@
 
 package android.companion;
 
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.MainThread;
 import android.annotation.NonNull;
@@ -140,24 +141,28 @@ public abstract class CompanionDeviceService extends Service {
      * Companion app receives {@link #onDeviceEvent(AssociationInfo, int)} callback
      * with this event if the device comes into BLE range.
      */
+    @FlaggedApi(Flags.FLAG_DEVICE_PRESENCE)
     public static final int DEVICE_EVENT_BLE_APPEARED = 0;
 
     /**
      * Companion app receives {@link #onDeviceEvent(AssociationInfo, int)} callback
      * with this event if the device is no longer in BLE range.
      */
+    @FlaggedApi(Flags.FLAG_DEVICE_PRESENCE)
     public static final int DEVICE_EVENT_BLE_DISAPPEARED = 1;
 
     /**
      * Companion app receives {@link #onDeviceEvent(AssociationInfo, int)} callback
      * with this event when the bluetooth device is connected.
      */
+    @FlaggedApi(Flags.FLAG_DEVICE_PRESENCE)
     public static final int DEVICE_EVENT_BT_CONNECTED = 2;
 
     /**
      * Companion app receives {@link #onDeviceEvent(AssociationInfo, int)} callback
      * with this event if the bluetooth device is disconnected.
      */
+    @FlaggedApi(Flags.FLAG_DEVICE_PRESENCE)
     public static final int DEVICE_EVENT_BT_DISCONNECTED = 3;
 
     /**
@@ -165,6 +170,7 @@ public abstract class CompanionDeviceService extends Service {
      * {@link #onDeviceEvent(AssociationInfo, int)} if it reports that a device has appeared on its
      * own.
      */
+    @FlaggedApi(Flags.FLAG_DEVICE_PRESENCE)
     public static final int DEVICE_EVENT_SELF_MANAGED_APPEARED = 4;
 
     /**
@@ -172,6 +178,7 @@ public abstract class CompanionDeviceService extends Service {
      * {@link #onDeviceEvent(AssociationInfo, int)} if it reports that a device has disappeared on
      * its own.
      */
+    @FlaggedApi(Flags.FLAG_DEVICE_PRESENCE)
     public static final int DEVICE_EVENT_SELF_MANAGED_DISAPPEARED = 5;
 
     private final Stub mRemote = new Stub();
@@ -348,6 +355,7 @@ public abstract class CompanionDeviceService extends Service {
      * @param associationInfo A record for the companion device.
      * @param event Associated companion device's event.
      */
+    @FlaggedApi(Flags.FLAG_DEVICE_PRESENCE)
     @MainThread
     public void onDeviceEvent(@NonNull AssociationInfo associationInfo,
             @DeviceEvent int event) {
diff --git a/core/java/android/companion/flags.aconfig b/core/java/android/companion/flags.aconfig
index 4f9c849865fccba9a0f4b3306b66c8dec3984043..6e33dff3a379fa0af50f996aae0aa555772a4bec 100644
--- a/core/java/android/companion/flags.aconfig
+++ b/core/java/android/companion/flags.aconfig
@@ -19,4 +19,11 @@ flag {
     namespace: "companion"
     description: "Enable Association tag APIs "
     bug: "289241123"
-}
\ No newline at end of file
+}
+
+flag {
+    name: "device_presence"
+    namespace: "companion"
+    description: "Enable device presence APIs"
+    bug: "283000075"
+}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 7b6bad31539af4030708e80f9436ab65954b6da7..ffc4805df2649addfd58a6a9d4c77cf6e2c25d45 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -6340,6 +6340,7 @@ public class Intent implements Parcelable, Cloneable {
      * the package is being archived. Either by removing the existing APK, or by installing
      * a package without an APK.
      */
+    @FlaggedApi(android.content.pm.Flags.FLAG_ARCHIVING)
     public static final String EXTRA_ARCHIVAL = "android.intent.extra.ARCHIVAL";
 
     /**
diff --git a/core/java/android/content/pm/ArchivedActivity.java b/core/java/android/content/pm/ArchivedActivity.java
new file mode 100644
index 0000000000000000000000000000000000000000..5139e2dedd723a7662e89938dc7e37c5fdec8d89
--- /dev/null
+++ b/core/java/android/content/pm/ArchivedActivity.java
@@ -0,0 +1,246 @@
+/*
+ * 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.content.pm;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+
+import com.android.internal.util.DataClass;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Objects;
+
+@DataClass(genBuilder = false, genConstructor = false, genSetters = true)
+@FlaggedApi(Flags.FLAG_ARCHIVING)
+public final class ArchivedActivity {
+    /** The label for the activity. */
+    private @NonNull CharSequence mLabel;
+    /** The component name of this activity. */
+    private @NonNull ComponentName mComponentName;
+    /**
+     * Icon of the activity in the app's locale. if null then the default icon would be shown in the
+     * launcher.
+     */
+    private @Nullable Drawable mIcon;
+    /** Monochrome icon, if defined, of the activity. */
+    private @Nullable Drawable mMonochromeIcon;
+
+    public ArchivedActivity(@NonNull CharSequence label, @NonNull ComponentName componentName) {
+        Objects.requireNonNull(label);
+        Objects.requireNonNull(componentName);
+        mLabel = label;
+        mComponentName = componentName;
+    }
+
+    /* @hide */
+    ArchivedActivity(@NonNull ArchivedActivityParcel parcel) {
+        mLabel = parcel.title;
+        mComponentName = parcel.originalComponentName;
+        mIcon = drawableFromCompressedBitmap(parcel.iconBitmap);
+        mMonochromeIcon = drawableFromCompressedBitmap(parcel.monochromeIconBitmap);
+    }
+
+    /* @hide */
+    @NonNull ArchivedActivityParcel getParcel() {
+        var parcel = new ArchivedActivityParcel();
+        parcel.title = mLabel.toString();
+        parcel.originalComponentName = mComponentName;
+        parcel.iconBitmap = mIcon == null ? null :
+                bytesFromBitmap(drawableToBitmap(mIcon));
+        parcel.monochromeIconBitmap = mMonochromeIcon == null ? null :
+                bytesFromBitmap(drawableToBitmap(mMonochromeIcon));
+        return parcel;
+    }
+
+    /**
+     * Convert a generic drawable into a bitmap.
+     * @hide
+     */
+    public static Bitmap drawableToBitmap(Drawable drawable) {
+        return drawableToBitmap(drawable, /* maxIconSize= */ Integer.MAX_VALUE);
+    }
+
+    /**
+     * Same as above, but.
+     * @hide
+     */
+    public static Bitmap drawableToBitmap(Drawable drawable, int maxIconSize) {
+        if (drawable instanceof BitmapDrawable) {
+            return ((BitmapDrawable) drawable).getBitmap();
+
+        }
+
+        Bitmap bitmap;
+        if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
+            // Needed for drawables that are just a single color.
+            bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
+        } else {
+            bitmap =
+                    Bitmap.createBitmap(
+                            drawable.getIntrinsicWidth(),
+                            drawable.getIntrinsicHeight(),
+                            Bitmap.Config.ARGB_8888);
+        }
+        Canvas canvas = new Canvas(bitmap);
+        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+        drawable.draw(canvas);
+        if (bitmap.getWidth() > maxIconSize || bitmap.getHeight() > maxIconSize) {
+            var scaledBitmap = Bitmap.createScaledBitmap(bitmap, maxIconSize, maxIconSize, true);
+            if (scaledBitmap != bitmap) {
+                bitmap.recycle();
+            }
+            return scaledBitmap;
+        }
+        return bitmap;
+    }
+
+    /**
+     * Compress bitmap to PNG format.
+     * The bitmap is going to be recycled.
+     * @hide
+     */
+    public static byte[] bytesFromBitmap(Bitmap bitmap) {
+        if (bitmap == null) {
+            return null;
+        }
+
+        try (ByteArrayOutputStream baos = new ByteArrayOutputStream(
+                bitmap.getByteCount())) {
+            bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
+            return baos.toByteArray();
+        } catch (IOException ignored) {
+            return null;
+        }
+    }
+
+    private static Drawable drawableFromCompressedBitmap(byte[] bytes) {
+        if (bytes == null) {
+            return null;
+        }
+        return new BitmapDrawable(null /*res*/, new ByteArrayInputStream(bytes));
+    }
+
+
+
+    // Code below generated by codegen v1.0.23.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/ArchivedActivity.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    /**
+     * The label for the activity.
+     */
+    @DataClass.Generated.Member
+    public @NonNull CharSequence getLabel() {
+        return mLabel;
+    }
+
+    /**
+     * The component name of this activity.
+     */
+    @DataClass.Generated.Member
+    public @NonNull ComponentName getComponentName() {
+        return mComponentName;
+    }
+
+    /**
+     * Icon of the activity in the app's locale. if null then the default icon would be shown in the
+     * launcher.
+     */
+    @DataClass.Generated.Member
+    public @Nullable Drawable getIcon() {
+        return mIcon;
+    }
+
+    /**
+     * Monochrome icon, if defined, of the activity.
+     */
+    @DataClass.Generated.Member
+    public @Nullable Drawable getMonochromeIcon() {
+        return mMonochromeIcon;
+    }
+
+    /**
+     * The label for the activity.
+     */
+    @DataClass.Generated.Member
+    public @NonNull ArchivedActivity setLabel(@NonNull CharSequence value) {
+        mLabel = value;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mLabel);
+        return this;
+    }
+
+    /**
+     * The component name of this activity.
+     */
+    @DataClass.Generated.Member
+    public @NonNull ArchivedActivity setComponentName(@NonNull ComponentName value) {
+        mComponentName = value;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mComponentName);
+        return this;
+    }
+
+    /**
+     * Icon of the activity in the app's locale. if null then the default icon would be shown in the
+     * launcher.
+     */
+    @DataClass.Generated.Member
+    public @NonNull ArchivedActivity setIcon(@NonNull Drawable value) {
+        mIcon = value;
+        return this;
+    }
+
+    /**
+     * Monochrome icon, if defined, of the activity.
+     */
+    @DataClass.Generated.Member
+    public @NonNull ArchivedActivity setMonochromeIcon(@NonNull Drawable value) {
+        mMonochromeIcon = value;
+        return this;
+    }
+
+    @DataClass.Generated(
+            time = 1698173429911L,
+            codegenVersion = "1.0.23",
+            sourceFile = "frameworks/base/core/java/android/content/pm/ArchivedActivity.java",
+            inputSignatures = "private @android.annotation.NonNull java.lang.CharSequence mLabel\nprivate @android.annotation.NonNull android.content.ComponentName mComponentName\nprivate @android.annotation.Nullable android.graphics.drawable.Drawable mIcon\nprivate @android.annotation.Nullable android.graphics.drawable.Drawable mMonochromeIcon\n @android.annotation.NonNull android.content.pm.ArchivedActivityParcel getParcel()\npublic static  android.graphics.Bitmap drawableToBitmap(android.graphics.drawable.Drawable)\npublic static  android.graphics.Bitmap drawableToBitmap(android.graphics.drawable.Drawable,int)\npublic static  byte[] bytesFromBitmap(android.graphics.Bitmap)\nprivate static  android.graphics.drawable.Drawable drawableFromCompressedBitmap(byte[])\nclass ArchivedActivity extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=false, genConstructor=false, genSetters=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/content/pm/ArchivedPackage.java b/core/java/android/content/pm/ArchivedPackage.java
new file mode 100644
index 0000000000000000000000000000000000000000..42795db356843175e42581706e0f30888b0cc83d
--- /dev/null
+++ b/core/java/android/content/pm/ArchivedPackage.java
@@ -0,0 +1,344 @@
+/*
+ * 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.content.pm;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Intent;
+
+import com.android.internal.util.DataClass;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+@DataClass(genBuilder = false, genConstructor = false, genSetters = true)
+@FlaggedApi(Flags.FLAG_ARCHIVING)
+public final class ArchivedPackage {
+    /** Name of the package as used to identify it in the system */
+    private @NonNull String mPackageName;
+    /** Signing certificates used to sign the package. */
+    private @NonNull SigningInfo mSigningInfo;
+    /**
+     * The version number of the package, as specified by the &lt;manifest&gt;tag's
+     * {@link android.R.styleable#AndroidManifest_versionCode versionCode} attribute.
+     */
+    private int mVersionCode = 0;
+    /**
+     * The major version number of the package, as specified by the &lt;manifest&gt;tag's
+     * {@link android.R.styleable#AndroidManifest_versionCode versionCodeMajor} attribute.
+     */
+    private int mVersionCodeMajor = 0;
+    /**
+     * This is the SDK version number that the application is targeting, as specified by the
+     * &lt;manifest&gt; tag's {@link android.R.styleable#AndroidManifestUsesSdk_targetSdkVersion}
+     * attribute.
+     */
+    private int mTargetSdkVersion = 0;
+    /**
+     * Package data will default to device protected storage. Specified by the &lt;manifest&gt;
+     * tag's {@link android.R.styleable#AndroidManifestApplication_defaultToDeviceProtectedStorage}
+     * attribute.
+     */
+    private @Nullable String mDefaultToDeviceProtectedStorage;
+    /**
+     * If {@code true} this app would like to run under the legacy storage model. Specified by the
+     * &lt;manifest&gt; tag's
+     * {@link android.R.styleable#AndroidManifestApplication_requestLegacyExternalStorage}
+     * attribute.
+     */
+    private @Nullable String mRequestLegacyExternalStorage;
+    /**
+     * If {@code true} the user is prompted to keep the app's data on uninstall. Specified by the
+     * &lt;manifest&gt; tag's
+     * {@link android.R.styleable#AndroidManifestApplication_hasFragileUserData} attribute.
+     */
+    private @Nullable String mUserDataFragile;
+    /**
+     * List of the package's activities that specify {@link Intent#ACTION_MAIN} and
+     * {@link Intent#CATEGORY_LAUNCHER}.
+     * @see LauncherApps#getActivityList
+     */
+    private @NonNull List<ArchivedActivity> mLauncherActivities;
+
+    public ArchivedPackage(@NonNull String packageName, @NonNull SigningInfo signingInfo,
+            @NonNull List<ArchivedActivity> launcherActivities) {
+        Objects.requireNonNull(packageName);
+        Objects.requireNonNull(signingInfo);
+        Objects.requireNonNull(launcherActivities);
+        this.mPackageName = packageName;
+        this.mSigningInfo = signingInfo;
+        this.mLauncherActivities = launcherActivities;
+    }
+
+    /**
+     * Constructs the archived package from parcel.
+     * @hide
+     */
+    public ArchivedPackage(@NonNull ArchivedPackageParcel parcel) {
+        mPackageName = parcel.packageName;
+        mSigningInfo = new SigningInfo(parcel.signingDetails);
+        mVersionCode = parcel.versionCode;
+        mVersionCodeMajor = parcel.versionCodeMajor;
+        mTargetSdkVersion = parcel.targetSdkVersion;
+        mDefaultToDeviceProtectedStorage = parcel.defaultToDeviceProtectedStorage;
+        mRequestLegacyExternalStorage = parcel.requestLegacyExternalStorage;
+        mUserDataFragile = parcel.userDataFragile;
+        mLauncherActivities = new ArrayList<>();
+        if (parcel.archivedActivities != null) {
+            for (var activityParcel : parcel.archivedActivities) {
+                mLauncherActivities.add(new ArchivedActivity(activityParcel));
+            }
+        }
+    }
+
+    /* @hide */
+    ArchivedPackageParcel getParcel() {
+        var parcel = new ArchivedPackageParcel();
+        parcel.packageName = mPackageName;
+        parcel.signingDetails = mSigningInfo.getSigningDetails();
+        parcel.versionCode = mVersionCode;
+        parcel.versionCodeMajor = mVersionCodeMajor;
+        parcel.targetSdkVersion = mTargetSdkVersion;
+        parcel.defaultToDeviceProtectedStorage = mDefaultToDeviceProtectedStorage;
+        parcel.requestLegacyExternalStorage = mRequestLegacyExternalStorage;
+        parcel.userDataFragile = mUserDataFragile;
+
+        parcel.archivedActivities = new ArchivedActivityParcel[mLauncherActivities.size()];
+        for (int i = 0, size = parcel.archivedActivities.length; i < size; ++i) {
+            parcel.archivedActivities[i] = mLauncherActivities.get(i).getParcel();
+        }
+
+        return parcel;
+    }
+
+
+
+    // Code below generated by codegen v1.0.23.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/ArchivedPackage.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    /**
+     * Name of the package as used to identify it in the system
+     */
+    @DataClass.Generated.Member
+    public @NonNull String getPackageName() {
+        return mPackageName;
+    }
+
+    /**
+     * Signing certificates used to sign the package.
+     */
+    @DataClass.Generated.Member
+    public @NonNull SigningInfo getSigningInfo() {
+        return mSigningInfo;
+    }
+
+    /**
+     * The version number of the package, as specified by the &lt;manifest&gt;tag's
+     * {@link android.R.styleable#AndroidManifest_versionCode versionCode} attribute.
+     */
+    @DataClass.Generated.Member
+    public int getVersionCode() {
+        return mVersionCode;
+    }
+
+    /**
+     * The major version number of the package, as specified by the &lt;manifest&gt;tag's
+     * {@link android.R.styleable#AndroidManifest_versionCode versionCodeMajor} attribute.
+     */
+    @DataClass.Generated.Member
+    public int getVersionCodeMajor() {
+        return mVersionCodeMajor;
+    }
+
+    /**
+     * This is the SDK version number that the application is targeting, as specified by the
+     * &lt;manifest&gt; tag's {@link android.R.styleable#AndroidManifestUsesSdk_targetSdkVersion}
+     * attribute.
+     */
+    @DataClass.Generated.Member
+    public int getTargetSdkVersion() {
+        return mTargetSdkVersion;
+    }
+
+    /**
+     * Package data will default to device protected storage. Specified by the &lt;manifest&gt;
+     * tag's {@link android.R.styleable#AndroidManifestApplication_defaultToDeviceProtectedStorage}
+     * attribute.
+     */
+    @DataClass.Generated.Member
+    public @Nullable String getDefaultToDeviceProtectedStorage() {
+        return mDefaultToDeviceProtectedStorage;
+    }
+
+    /**
+     * If {@code true} this app would like to run under the legacy storage model. Specified by the
+     * &lt;manifest&gt; tag's
+     * {@link android.R.styleable#AndroidManifestApplication_requestLegacyExternalStorage}
+     * attribute.
+     */
+    @DataClass.Generated.Member
+    public @Nullable String getRequestLegacyExternalStorage() {
+        return mRequestLegacyExternalStorage;
+    }
+
+    /**
+     * If {@code true} the user is prompted to keep the app's data on uninstall. Specified by the
+     * &lt;manifest&gt; tag's
+     * {@link android.R.styleable#AndroidManifestApplication_hasFragileUserData} attribute.
+     */
+    @DataClass.Generated.Member
+    public @Nullable String getUserDataFragile() {
+        return mUserDataFragile;
+    }
+
+    /**
+     * List of the package's activities that specify {@link Intent#ACTION_MAIN} and
+     * {@link Intent#CATEGORY_LAUNCHER}.
+     *
+     * @see LauncherApps#getActivityList
+     */
+    @DataClass.Generated.Member
+    public @NonNull List<ArchivedActivity> getLauncherActivities() {
+        return mLauncherActivities;
+    }
+
+    /**
+     * Name of the package as used to identify it in the system
+     */
+    @DataClass.Generated.Member
+    public @NonNull ArchivedPackage setPackageName(@NonNull String value) {
+        mPackageName = value;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mPackageName);
+        return this;
+    }
+
+    /**
+     * Signing certificates used to sign the package.
+     */
+    @DataClass.Generated.Member
+    public @NonNull ArchivedPackage setSigningInfo(@NonNull SigningInfo value) {
+        mSigningInfo = value;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mSigningInfo);
+        return this;
+    }
+
+    /**
+     * The version number of the package, as specified by the &lt;manifest&gt;tag's
+     * {@link android.R.styleable#AndroidManifest_versionCode versionCode} attribute.
+     */
+    @DataClass.Generated.Member
+    public @NonNull ArchivedPackage setVersionCode( int value) {
+        mVersionCode = value;
+        return this;
+    }
+
+    /**
+     * The major version number of the package, as specified by the &lt;manifest&gt;tag's
+     * {@link android.R.styleable#AndroidManifest_versionCode versionCodeMajor} attribute.
+     */
+    @DataClass.Generated.Member
+    public @NonNull ArchivedPackage setVersionCodeMajor( int value) {
+        mVersionCodeMajor = value;
+        return this;
+    }
+
+    /**
+     * This is the SDK version number that the application is targeting, as specified by the
+     * &lt;manifest&gt; tag's {@link android.R.styleable#AndroidManifestUsesSdk_targetSdkVersion}
+     * attribute.
+     */
+    @DataClass.Generated.Member
+    public @NonNull ArchivedPackage setTargetSdkVersion( int value) {
+        mTargetSdkVersion = value;
+        return this;
+    }
+
+    /**
+     * Package data will default to device protected storage. Specified by the &lt;manifest&gt;
+     * tag's {@link android.R.styleable#AndroidManifestApplication_defaultToDeviceProtectedStorage}
+     * attribute.
+     */
+    @DataClass.Generated.Member
+    public @NonNull ArchivedPackage setDefaultToDeviceProtectedStorage(@NonNull String value) {
+        mDefaultToDeviceProtectedStorage = value;
+        return this;
+    }
+
+    /**
+     * If {@code true} this app would like to run under the legacy storage model. Specified by the
+     * &lt;manifest&gt; tag's
+     * {@link android.R.styleable#AndroidManifestApplication_requestLegacyExternalStorage}
+     * attribute.
+     */
+    @DataClass.Generated.Member
+    public @NonNull ArchivedPackage setRequestLegacyExternalStorage(@NonNull String value) {
+        mRequestLegacyExternalStorage = value;
+        return this;
+    }
+
+    /**
+     * If {@code true} the user is prompted to keep the app's data on uninstall. Specified by the
+     * &lt;manifest&gt; tag's
+     * {@link android.R.styleable#AndroidManifestApplication_hasFragileUserData} attribute.
+     */
+    @DataClass.Generated.Member
+    public @NonNull ArchivedPackage setUserDataFragile(@NonNull String value) {
+        mUserDataFragile = value;
+        return this;
+    }
+
+    /**
+     * List of the package's activities that specify {@link Intent#ACTION_MAIN} and
+     * {@link Intent#CATEGORY_LAUNCHER}.
+     *
+     * @see LauncherApps#getActivityList
+     */
+    @DataClass.Generated.Member
+    public @NonNull ArchivedPackage setLauncherActivities(@NonNull List<ArchivedActivity> value) {
+        mLauncherActivities = value;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mLauncherActivities);
+        return this;
+    }
+
+    @DataClass.Generated(
+            time = 1697824890503L,
+            codegenVersion = "1.0.23",
+            sourceFile = "frameworks/base/core/java/android/content/pm/ArchivedPackage.java",
+            inputSignatures = "private @android.annotation.NonNull java.lang.String mPackageName\nprivate @android.annotation.NonNull android.content.pm.SigningInfo mSigningInfo\nprivate  int mVersionCode\nprivate  int mVersionCodeMajor\nprivate  int mTargetSdkVersion\nprivate @android.annotation.Nullable java.lang.String mDefaultToDeviceProtectedStorage\nprivate @android.annotation.Nullable java.lang.String mRequestLegacyExternalStorage\nprivate @android.annotation.Nullable java.lang.String mUserDataFragile\nprivate @android.annotation.NonNull java.util.List<android.content.pm.ArchivedActivity> mLauncherActivities\n  android.content.pm.ArchivedPackageParcel getParcel()\nclass ArchivedPackage extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=false, genConstructor=false, genSetters=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl
index edb07ce423c10a2db6b81ce18001c7625dbf1499..59ed0453bc0132d31ffb748df428a17cc3dddabd 100644
--- a/core/java/android/content/pm/IPackageInstaller.aidl
+++ b/core/java/android/content/pm/IPackageInstaller.aidl
@@ -16,6 +16,7 @@
 
 package android.content.pm;
 
+import android.content.pm.ArchivedPackageParcel;
 import android.content.pm.IPackageDeleteObserver2;
 import android.content.pm.IPackageInstallerCallback;
 import android.content.pm.IPackageInstallerSession;
@@ -82,4 +83,11 @@ interface IPackageInstaller {
 
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission(anyOf={android.Manifest.permission.INSTALL_PACKAGES,android.Manifest.permission.REQUEST_INSTALL_PACKAGES})")
     void requestUnarchive(String packageName, String callerPackageName, in UserHandle userHandle);
+
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES)")
+    void installPackageArchived(in ArchivedPackageParcel archivedPackageParcel,
+            in PackageInstaller.SessionParams params,
+            in IntentSender statusReceiver,
+            String installerPackageName, in UserHandle userHandle);
+
 }
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index d837aae350969784fe67a25cbc11f549898b2a46..cd8938d1dd7762a1ceb458ec4bddcbe06e55afa7 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1000,6 +1000,37 @@ public class PackageInstaller {
         }
     }
 
+    /**
+     * Install package in an archived state.
+     *
+     * @param archivedPackage archived package data such as package name, signature etc.
+     * @param sessionParams used to create an underlying installation session
+     * @param statusReceiver Called when the state of the session changes. Intents
+     *                       sent to this receiver contain {@link #EXTRA_STATUS}. Refer to the
+     *                       individual status codes on how to handle them.
+     * @see #createSession
+     * @see PackageInstaller.Session#commit
+     */
+    @RequiresPermission(Manifest.permission.INSTALL_PACKAGES)
+    @FlaggedApi(Flags.FLAG_ARCHIVING)
+    public void installPackageArchived(@NonNull ArchivedPackage archivedPackage,
+            @NonNull SessionParams sessionParams,
+            @NonNull IntentSender statusReceiver) {
+        Objects.requireNonNull(archivedPackage, "archivedPackage cannot be null");
+        Objects.requireNonNull(sessionParams, "sessionParams cannot be null");
+        Objects.requireNonNull(statusReceiver, "statusReceiver cannot be null");
+        try {
+            mInstaller.installPackageArchived(
+                    archivedPackage.getParcel(),
+                    sessionParams,
+                    statusReceiver,
+                    mInstallerPackageName,
+                    new UserHandle(mUserId));
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     /** {@hide} */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES)
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index b15c9e4fa15bd7bfdc3626d54a77b92a1e27cea6..6d4276d4f47a3614c37ccc457c1fc22d01308a91 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -11026,6 +11026,16 @@ public abstract class PackageManager {
                 "makeUidVisible not implemented in subclass");
     }
 
+    /**
+     * Return archived package info for the package or null if the package is not installed.
+     * @see PackageInstaller#installPackageArchived
+     */
+    @FlaggedApi(android.content.pm.Flags.FLAG_ARCHIVING)
+    public @Nullable ArchivedPackage getArchivedPackage(@NonNull String packageName) {
+        throw new UnsupportedOperationException(
+                "getArchivedPackage not implemented in subclass");
+    }
+
     // Some of the flags don't affect the query result, but let's be conservative and cache
     // each combination of flags separately.
 
diff --git a/core/java/android/content/pm/SigningInfo.java b/core/java/android/content/pm/SigningInfo.java
index ee9aaca3ed43e7604a2c3999ddace9806af87167..554de0c2ea7b897b3d3e2bb3e853028eb9392405 100644
--- a/core/java/android/content/pm/SigningInfo.java
+++ b/core/java/android/content/pm/SigningInfo.java
@@ -126,6 +126,12 @@ public final class SigningInfo implements Parcelable {
         mSigningDetails.writeToParcel(dest, parcelableFlags);
     }
 
+    /* @hide */
+    @NonNull
+    SigningDetails getSigningDetails() {
+        return mSigningDetails;
+    }
+
     public static final @android.annotation.NonNull Parcelable.Creator<SigningInfo> CREATOR =
             new Parcelable.Creator<SigningInfo>() {
         @Override
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
index bf77681bbbbd6cea1134cf3d5a1a93a8200716fd..db7055b1756d4ab460a83e27dcb8b8c73e6939d1 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
@@ -357,7 +357,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
             mCameraRepeatingSurface = mRepeatingRequestImageReader.getSurface();
         }
         mRepeatingRequestImageCallback = new CameraOutputImageCallback(
-                mRepeatingRequestImageReader);
+                mRepeatingRequestImageReader, true /*pruneOlderBuffers*/);
         mRepeatingRequestImageReader
                 .setOnImageAvailableListener(mRepeatingRequestImageCallback, mHandler);
     }
@@ -398,7 +398,8 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
                         CameraExtensionCharacteristics.PROCESSING_INPUT_FORMAT);
             }
 
-            mBurstCaptureImageCallback = new CameraOutputImageCallback(mBurstCaptureImageReader);
+            mBurstCaptureImageCallback = new CameraOutputImageCallback(mBurstCaptureImageReader,
+                    false /*pruneOlderBuffers*/);
             mBurstCaptureImageReader.setOnImageAvailableListener(mBurstCaptureImageCallback,
                     mHandler);
             mCameraBurstSurface = mBurstCaptureImageReader.getSurface();
@@ -1106,7 +1107,9 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
                 }
 
                 for (Pair<Image, TotalCaptureResult> captureStage : mCaptureStageMap.values()) {
-                    captureStage.first.close();
+                    if (captureStage.first != null) {
+                        captureStage.first.close();
+                    }
                 }
                 mCaptureStageMap.clear();
             }
@@ -1207,6 +1210,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
                 if (mImageProcessor != null) {
                     if (mCapturePendingMap.indexOfKey(timestamp) >= 0) {
                         Image img = mCapturePendingMap.get(timestamp).first;
+                        mCapturePendingMap.remove(timestamp);
                         mCaptureStageMap.put(stageId, new Pair<>(img, result));
                         checkAndFireBurstProcessing();
                     } else {
@@ -1303,6 +1307,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
                 reader.detachImage(img);
                 if (mCapturePendingMap.indexOfKey(timestamp) >= 0) {
                     Integer stageId = mCapturePendingMap.get(timestamp).second;
+                    mCapturePendingMap.remove(timestamp);
                     Pair<Image, TotalCaptureResult> captureStage =
                             mCaptureStageMap.get(stageId);
                     if (captureStage != null) {
@@ -1402,9 +1407,11 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
         private HashMap<Long, Pair<Image, OnImageAvailableListener>> mImageListenerMap =
                 new HashMap<>();
         private boolean mOutOfBuffers = false;
+        private final boolean mPruneOlderBuffers;
 
-        CameraOutputImageCallback(ImageReader imageReader) {
+        CameraOutputImageCallback(ImageReader imageReader, boolean pruneOlderBuffers) {
             mImageReader = imageReader;
+            mPruneOlderBuffers = pruneOlderBuffers;
         }
 
         @Override
@@ -1447,6 +1454,10 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
                 ArrayList<Long> removedTs = new ArrayList<>();
                 for (long ts : timestamps) {
                     if (ts < timestamp) {
+                        if (!mPruneOlderBuffers) {
+                            Log.w(TAG, "Unexpected older image with ts: " + ts);
+                            continue;
+                        }
                         Log.e(TAG, "Dropped image with ts: " + ts);
                         Pair<Image, OnImageAvailableListener> entry = mImageListenerMap.get(ts);
                         if (entry.second != null) {
diff --git a/core/java/android/hardware/hdmi/OWNERS b/core/java/android/hardware/hdmi/OWNERS
index 861e4409b0149f1409a9674db6d342236c9a55fa..6952e5d78d9891662ecb77c4423529638e0b90bf 100644
--- a/core/java/android/hardware/hdmi/OWNERS
+++ b/core/java/android/hardware/hdmi/OWNERS
@@ -2,5 +2,4 @@
 
 include /services/core/java/com/android/server/display/OWNERS
 
-marvinramin@google.com
-lcnathalie@google.com
+quxiangfang@google.com
diff --git a/core/java/android/nfc/flags.aconfig b/core/java/android/nfc/flags.aconfig
index 55b0b4261763e3066ab8b60ea102d0abdc85aacd..cd50ace036def70da35457d552221e9df24ffc96 100644
--- a/core/java/android/nfc/flags.aconfig
+++ b/core/java/android/nfc/flags.aconfig
@@ -13,3 +13,10 @@ flag {
     description: "Flag for NFC reader option API changes"
     bug: "291187960"
 }
+
+flag {
+    name: "enable_nfc_user_restriction"
+    namespace: "nfc"
+    description: "Flag for NFC user restriction"
+    bug: "291187960"
+}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 9034ff10286b8f7da2cdf133db5c81ba81b39d92..72bc2113f93f37d954ff73ffe7b4ea15963af92a 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -23,6 +23,7 @@ import android.Manifest;
 import android.accounts.AccountManager;
 import android.annotation.ColorInt;
 import android.annotation.DrawableRes;
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -58,6 +59,7 @@ import android.graphics.BitmapFactory;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.location.LocationManager;
+import android.nfc.Flags;
 import android.provider.Settings;
 import android.util.AndroidException;
 import android.util.ArraySet;
@@ -1871,6 +1873,7 @@ public class UserManager {
      * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_USER_RESTRICTION)
     public static final String DISALLOW_NEAR_FIELD_COMMUNICATION_RADIO =
             "no_near_field_communication_radio";
 
diff --git a/core/java/android/text/BoringLayout.java b/core/java/android/text/BoringLayout.java
index 65a1da6b81b84a883c2c72e9f7b052896d7debb3..4c8188801eff6b49e8cb5386cb83f38a362b30f4 100644
--- a/core/java/android/text/BoringLayout.java
+++ b/core/java/android/text/BoringLayout.java
@@ -190,7 +190,8 @@ public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback
             @Nullable TextUtils.TruncateAt ellipsize, @IntRange(from = 0) int ellipsizedWidth,
             boolean useFallbackLineSpacing) {
         return replaceOrMake(source, paint, outerWidth, align, 1.0f, 0.0f, metrics, includePad,
-                ellipsize, ellipsizedWidth, useFallbackLineSpacing, false /* useBoundsForWidth */);
+                ellipsize, ellipsizedWidth, useFallbackLineSpacing, false /* useBoundsForWidth */,
+                null /* minimumFontMetrics */);
     }
 
     /** @hide */
@@ -199,7 +200,8 @@ public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback
             @NonNull Alignment align, float spacingMultiplier, float spacingAmount,
             @NonNull BoringLayout.Metrics metrics, boolean includePad,
             @Nullable TextUtils.TruncateAt ellipsize, @IntRange(from = 0) int ellipsizedWidth,
-            boolean useFallbackLineSpacing, boolean useBoundsForWidth) {
+            boolean useFallbackLineSpacing, boolean useBoundsForWidth,
+            @Nullable Paint.FontMetrics minimumFontMetrics) {
         boolean trust;
 
         if (ellipsize == null || ellipsize == TextUtils.TruncateAt.MARQUEE) {
@@ -270,7 +272,8 @@ public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback
                 spacingAdd, includePad, false /* fallbackLineSpacing */,
                 outerwidth /* ellipsizedWidth */, null /* ellipsize */, 1 /* maxLines */,
                 BREAK_STRATEGY_SIMPLE, HYPHENATION_FREQUENCY_NONE, null /* leftIndents */,
-                null /* rightIndents */, JUSTIFICATION_MODE_NONE, LineBreakConfig.NONE, false);
+                null /* rightIndents */, JUSTIFICATION_MODE_NONE, LineBreakConfig.NONE, false,
+                null);
 
         mEllipsizedWidth = outerwidth;
         mEllipsizedStart = 0;
@@ -343,7 +346,7 @@ public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback
                 ellipsizedWidth, ellipsize, 1 /* maxLines */,
                 BREAK_STRATEGY_SIMPLE, HYPHENATION_FREQUENCY_NONE, null /* leftIndents */,
                 null /* rightIndents */, JUSTIFICATION_MODE_NONE,
-                LineBreakConfig.NONE, metrics, false /* useBoundsForWidth */);
+                LineBreakConfig.NONE, metrics, false /* useBoundsForWidth */, null);
     }
 
     /** @hide */
@@ -359,12 +362,13 @@ public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback
             int ellipsizedWidth,
             TextUtils.TruncateAt ellipsize,
             Metrics metrics,
-            boolean useBoundsForWidth) {
+            boolean useBoundsForWidth,
+            @Nullable Paint.FontMetrics minimumFontMetrics) {
         this(text, paint, width, align, TextDirectionHeuristics.LTR,
                 spacingMult, spacingAdd, includePad, fallbackLineSpacing, ellipsizedWidth,
                 ellipsize, 1 /* maxLines */, Layout.BREAK_STRATEGY_SIMPLE,
                 Layout.HYPHENATION_FREQUENCY_NONE, null, null, Layout.JUSTIFICATION_MODE_NONE,
-                LineBreakConfig.NONE, metrics, useBoundsForWidth);
+                LineBreakConfig.NONE, metrics, useBoundsForWidth, minimumFontMetrics);
     }
 
     /* package */ BoringLayout(
@@ -387,12 +391,13 @@ public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback
             int justificationMode,
             LineBreakConfig lineBreakConfig,
             Metrics metrics,
-            boolean useBoundsForWidth) {
+            boolean useBoundsForWidth,
+            @Nullable Paint.FontMetrics minimumFontMetrics) {
 
         super(text, paint, width, align, textDir, spacingMult, spacingAdd, includePad,
                 fallbackLineSpacing, ellipsizedWidth, ellipsize, maxLines, breakStrategy,
                 hyphenationFrequency, leftIndents, rightIndents, justificationMode,
-                lineBreakConfig, useBoundsForWidth);
+                lineBreakConfig, useBoundsForWidth, minimumFontMetrics);
 
 
         boolean trust;
@@ -548,6 +553,15 @@ public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback
     public static @Nullable Metrics isBoring(@NonNull CharSequence text, @NonNull TextPaint paint,
             @NonNull TextDirectionHeuristic textDir, boolean useFallbackLineSpacing,
             @Nullable Metrics metrics) {
+        return isBoring(text, paint, textDir, useFallbackLineSpacing, null, metrics);
+    }
+
+    /**
+     * @hide
+     */
+    public static @Nullable Metrics isBoring(@NonNull CharSequence text, @NonNull TextPaint paint,
+            @NonNull TextDirectionHeuristic textDir, boolean useFallbackLineSpacing,
+            @Nullable Paint.FontMetrics minimumFontMetrics, @Nullable Metrics metrics) {
         final int textLength = text.length();
         if (hasAnyInterestingChars(text, textLength)) {
            return null;  // There are some interesting characters. Not boring.
@@ -570,6 +584,19 @@ public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback
             fm.reset();
         }
 
+        if (ClientFlags.fixLineHeightForLocale()) {
+            if (minimumFontMetrics == null) {
+                paint.getFontMetricsIntForLocale(fm);
+            } else {
+                fm.set(minimumFontMetrics);
+                // Because the font metrics is provided by public APIs, adjust the top/bottom with
+                // ascent/descent: top must be smaller than ascent, bottom must be larger than
+                // descent.
+                fm.top = Math.min(fm.top, fm.ascent);
+                fm.bottom = Math.max(fm.bottom, fm.descent);
+            }
+        }
+
         TextLine line = TextLine.obtain();
         line.set(paint, text, 0, textLength, Layout.DIR_LEFT_TO_RIGHT,
                 Layout.DIRS_ALL_LEFT_TO_RIGHT, false, null,
diff --git a/core/java/android/text/ClientFlags.java b/core/java/android/text/ClientFlags.java
index e17a955121b0df02cd47c3e407f1d1831ac18cd3..0421d5aaa69b11bb13c9134e1bfa5c27cc85664c 100644
--- a/core/java/android/text/ClientFlags.java
+++ b/core/java/android/text/ClientFlags.java
@@ -47,4 +47,11 @@ public class ClientFlags {
     public static boolean useBoundsForWidth() {
         return TextFlags.isFeatureEnabled(Flags.FLAG_USE_BOUNDS_FOR_WIDTH);
     }
+
+    /**
+     * @see Flags#fixLineHeightForLocale()
+     */
+    public static boolean fixLineHeightForLocale() {
+        return TextFlags.isFeatureEnabled(Flags.FLAG_FIX_LINE_HEIGHT_FOR_LOCALE);
+    }
 }
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index a0cd0748f5094c977411dc53518c967c450ffd20..7b9cb6afd6a0d0a4d457d5f589468e26575984a2 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -16,6 +16,7 @@
 
 package android.text;
 
+import static com.android.text.flags.Flags.FLAG_FIX_LINE_HEIGHT_FOR_LOCALE;
 import static com.android.text.flags.Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN;
 import static com.android.text.flags.Flags.FLAG_USE_BOUNDS_FOR_WIDTH;
 
@@ -314,6 +315,43 @@ public class DynamicLayout extends Layout {
             return this;
         }
 
+        /**
+         * Set the minimum font metrics used for line spacing.
+         *
+         * <p>
+         * {@code null} is the default value. If {@code null} is set or left as default, the
+         * font metrics obtained by {@link Paint#getFontMetricsForLocale(Paint.FontMetrics)} is
+         * used.
+         *
+         * <p>
+         * The minimum meaning here is the minimum value of line spacing: maximum value of
+         * {@link Paint#ascent()}, minimum value of {@link Paint#descent()}.
+         *
+         * <p>
+         * By setting this value, each line will have minimum line spacing regardless of the text
+         * rendered. For example, usually Japanese script has larger vertical metrics than Latin
+         * script. By setting the metrics obtained by
+         * {@link Paint#getFontMetricsForLocale(Paint.FontMetrics)} for Japanese or leave it
+         * {@code null} if the Paint's locale is Japanese, the line spacing for Japanese is reserved
+         * if the text is an English text. If the vertical metrics of the text is larger than
+         * Japanese, for example Burmese, the bigger font metrics is used.
+         *
+         * @param minimumFontMetrics A minimum font metrics. Passing {@code null} for using the
+         *                          value obtained by
+         *                          {@link Paint#getFontMetricsForLocale(Paint.FontMetrics)}
+         * @see android.widget.TextView#setMinimumFontMetrics(Paint.FontMetrics)
+         * @see android.widget.TextView#getMinimumFontMetrics()
+         * @see Layout#getMinimumFontMetrics()
+         * @see Layout.Builder#setMinimumFontMetrics(Paint.FontMetrics)
+         * @see StaticLayout.Builder#setMinimumFontMetrics(Paint.FontMetrics)
+         */
+        @NonNull
+        @FlaggedApi(FLAG_FIX_LINE_HEIGHT_FOR_LOCALE)
+        public Builder setMinimumFontMetrics(@Nullable Paint.FontMetrics minimumFontMetrics) {
+            mMinimumFontMetrics = minimumFontMetrics;
+            return this;
+        }
+
         /**
          * Build the {@link DynamicLayout} after options have been set.
          *
@@ -347,6 +385,7 @@ public class DynamicLayout extends Layout {
         private int mEllipsizedWidth;
         private LineBreakConfig mLineBreakConfig = LineBreakConfig.NONE;
         private boolean mUseBoundsForWidth;
+        private @Nullable Paint.FontMetrics mMinimumFontMetrics;
 
         private final Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt();
 
@@ -422,7 +461,7 @@ public class DynamicLayout extends Layout {
                 false /* fallbackLineSpacing */, ellipsizedWidth, ellipsize,
                 Integer.MAX_VALUE /* maxLines */, breakStrategy, hyphenationFrequency,
                 null /* leftIndents */, null /* rightIndents */, justificationMode,
-                lineBreakConfig, false /* useBoundsForWidth */);
+                lineBreakConfig, false /* useBoundsForWidth */, null /* minimumFontMetrics */);
 
         final Builder b = Builder.obtain(base, paint, width)
                 .setAlignment(align)
@@ -448,7 +487,7 @@ public class DynamicLayout extends Layout {
                 b.mIncludePad, b.mFallbackLineSpacing, b.mEllipsizedWidth, b.mEllipsize,
                 Integer.MAX_VALUE /* maxLines */, b.mBreakStrategy, b.mHyphenationFrequency,
                 null /* leftIndents */, null /* rightIndents */, b.mJustificationMode,
-                b.mLineBreakConfig, b.mUseBoundsForWidth);
+                b.mLineBreakConfig, b.mUseBoundsForWidth, b.mMinimumFontMetrics);
 
         mDisplay = b.mDisplay;
         mIncludePad = b.mIncludePad;
@@ -476,6 +515,7 @@ public class DynamicLayout extends Layout {
         mBase = b.mBase;
         mFallbackLineSpacing = b.mFallbackLineSpacing;
         mUseBoundsForWidth = b.mUseBoundsForWidth;
+        mMinimumFontMetrics = b.mMinimumFontMetrics;
         if (b.mEllipsize != null) {
             mInts = new PackedIntVector(COLUMNS_ELLIPSIZE);
             mEllipsizedWidth = b.mEllipsizedWidth;
@@ -672,6 +712,7 @@ public class DynamicLayout extends Layout {
                 .setAddLastLineLineSpacing(!islast)
                 .setIncludePad(false)
                 .setUseBoundsForWidth(mUseBoundsForWidth)
+                .setMinimumFontMetrics(mMinimumFontMetrics)
                 .setCalculateBounds(true);
 
         reflowed = b.buildPartialStaticLayoutForDynamicLayout(true /* trackpadding */, reflowed);
@@ -1324,6 +1365,7 @@ public class DynamicLayout extends Layout {
     private Rect mTempRect = new Rect();
 
     private boolean mUseBoundsForWidth;
+    @Nullable Paint.FontMetrics mMinimumFontMetrics;
 
     @UnsupportedAppUsage
     private static StaticLayout sStaticLayout = null;
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 4f4dea7801713ef652b992c19b97a0aa50b73a16..47c29d96855868c527ea4c482bff571d8de6fc65 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -16,6 +16,7 @@
 
 package android.text;
 
+import static com.android.text.flags.Flags.FLAG_FIX_LINE_HEIGHT_FOR_LOCALE;
 import static com.android.text.flags.Flags.FLAG_USE_BOUNDS_FOR_WIDTH;
 
 import android.annotation.FlaggedApi;
@@ -287,7 +288,7 @@ public abstract class Layout {
         this(text, paint, width, align, TextDirectionHeuristics.FIRSTSTRONG_LTR,
                 spacingMult, spacingAdd, false, false, 0, null, Integer.MAX_VALUE,
                 BREAK_STRATEGY_SIMPLE, HYPHENATION_FREQUENCY_NONE, null, null,
-                JUSTIFICATION_MODE_NONE, LineBreakConfig.NONE, false);
+                JUSTIFICATION_MODE_NONE, LineBreakConfig.NONE, false, null);
     }
 
     /**
@@ -336,7 +337,8 @@ public abstract class Layout {
             int[] rightIndents,
             int justificationMode,
             LineBreakConfig lineBreakConfig,
-            boolean useBoundsForWidth
+            boolean useBoundsForWidth,
+            Paint.FontMetrics minimumFontMetrics
     ) {
 
         if (width < 0)
@@ -371,6 +373,7 @@ public abstract class Layout {
         mJustificationMode = justificationMode;
         mLineBreakConfig = lineBreakConfig;
         mUseBoundsForWidth = useBoundsForWidth;
+        mMinimumFontMetrics = minimumFontMetrics;
     }
 
     /**
@@ -3332,6 +3335,7 @@ public abstract class Layout {
     private int mJustificationMode;
     private LineBreakConfig mLineBreakConfig;
     private boolean mUseBoundsForWidth;
+    private @Nullable Paint.FontMetrics mMinimumFontMetrics;
 
     /** @hide */
     @IntDef(prefix = { "DIR_" }, value = {
@@ -3787,12 +3791,48 @@ public abstract class Layout {
             return this;
         }
 
+        /**
+         * Set the minimum font metrics used for line spacing.
+         *
+         * <p>
+         * {@code null} is the default value. If {@code null} is set or left it as default, the font
+         * metrics obtained by {@link Paint#getFontMetricsForLocale(Paint.FontMetrics)} is used.
+         *
+         * <p>
+         * The minimum meaning here is the minimum value of line spacing: maximum value of
+         * {@link Paint#ascent()}, minimum value of {@link Paint#descent()}.
+         *
+         * <p>
+         * By setting this value, each line will have minimum line spacing regardless of the text
+         * rendered. For example, usually Japanese script has larger vertical metrics than Latin
+         * script. By setting the metrics obtained by
+         * {@link Paint#getFontMetricsForLocale(Paint.FontMetrics)} for Japanese or leave it
+         * {@code null} if the Paint's locale is Japanese, the line spacing for Japanese is reserved
+         * if the text is an English text. If the vertical metrics of the text is larger than
+         * Japanese, for example Burmese, the bigger font metrics is used.
+         *
+         * @param minimumFontMetrics A minimum font metrics. Passing {@code null} for using the
+         *                          value obtained by
+         *                          {@link Paint#getFontMetricsForLocale(Paint.FontMetrics)}
+         * @see android.widget.TextView#setMinimumFontMetrics(Paint.FontMetrics)
+         * @see android.widget.TextView#getMinimumFontMetrics()
+         * @see Layout#getMinimumFontMetrics()
+         * @see StaticLayout.Builder#setMinimumFontMetrics(Paint.FontMetrics)
+         * @see DynamicLayout.Builder#setMinimumFontMetrics(Paint.FontMetrics)
+         */
+        @NonNull
+        @FlaggedApi(FLAG_FIX_LINE_HEIGHT_FOR_LOCALE)
+        public Builder setMinimumFontMetrics(@Nullable Paint.FontMetrics minimumFontMetrics) {
+            mMinimumFontMetrics = minimumFontMetrics;
+            return this;
+        }
+
         private BoringLayout.Metrics isBoring() {
             if (mStart != 0 || mEnd != mText.length()) {  // BoringLayout only support entire text.
                 return null;
             }
             BoringLayout.Metrics metrics = BoringLayout.isBoring(mText, mPaint, mTextDir,
-                    mFallbackLineSpacing, null);
+                    mFallbackLineSpacing, mMinimumFontMetrics, null);
             if (metrics == null) {
                 return null;
             }
@@ -3833,7 +3873,8 @@ public abstract class Layout {
                         mText, mPaint, mWidth, mAlignment, mTextDir, mSpacingMult, mSpacingAdd,
                         mIncludePad, mFallbackLineSpacing, mEllipsizedWidth, mEllipsize, mMaxLines,
                         mBreakStrategy, mHyphenationFrequency, mLeftIndents, mRightIndents,
-                        mJustificationMode, mLineBreakConfig, metrics, mUseBoundsForWidth);
+                        mJustificationMode, mLineBreakConfig, metrics, mUseBoundsForWidth,
+                        mMinimumFontMetrics);
             }
         }
 
@@ -3858,6 +3899,7 @@ public abstract class Layout {
         private int mJustificationMode = JUSTIFICATION_MODE_NONE;
         private LineBreakConfig mLineBreakConfig = LineBreakConfig.NONE;
         private boolean mUseBoundsForWidth;
+        private Paint.FontMetrics mMinimumFontMetrics;
     }
 
     ///////////////////////////////////////////////////////////////////////////////////////////////
@@ -4164,4 +4206,22 @@ public abstract class Layout {
     public boolean getUseBoundsForWidth() {
         return mUseBoundsForWidth;
     }
+
+    /**
+     * Get the minimum font metrics used for line spacing.
+     *
+     * @see android.widget.TextView#setMinimumFontMetrics(Paint.FontMetrics)
+     * @see android.widget.TextView#getMinimumFontMetrics()
+     * @see Layout.Builder#setMinimumFontMetrics(Paint.FontMetrics)
+     * @see StaticLayout.Builder#setMinimumFontMetrics(Paint.FontMetrics)
+     * @see DynamicLayout.Builder#setMinimumFontMetrics(Paint.FontMetrics)
+     *
+     * @return a minimum font metrics. {@code null} for using the value obtained by
+     *         {@link Paint#getFontMetricsForLocale(Paint.FontMetrics)}
+     */
+    @Nullable
+    @FlaggedApi(FLAG_FIX_LINE_HEIGHT_FOR_LOCALE)
+    public Paint.FontMetrics getMinimumFontMetrics() {
+        return mMinimumFontMetrics;
+    }
 }
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 01279cea073f2c3034a760a04b80315ccf35ee03..77e616b358cba716fb805cf57784ef50b4db0ecb 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -16,6 +16,7 @@
 
 package android.text;
 
+import static com.android.text.flags.Flags.FLAG_FIX_LINE_HEIGHT_FOR_LOCALE;
 import static com.android.text.flags.Flags.FLAG_USE_BOUNDS_FOR_WIDTH;
 
 import android.annotation.FlaggedApi;
@@ -459,6 +460,43 @@ public class StaticLayout extends Layout {
             return this;
         }
 
+        /**
+         * Set the minimum font metrics used for line spacing.
+         *
+         * <p>
+         * {@code null} is the default value. If {@code null} is set or left as default, the
+         * font metrics obtained by {@link Paint#getFontMetricsForLocale(Paint.FontMetrics)} is
+         * used.
+         *
+         * <p>
+         * The minimum meaning here is the minimum value of line spacing: maximum value of
+         * {@link Paint#ascent()}, minimum value of {@link Paint#descent()}.
+         *
+         * <p>
+         * By setting this value, each line will have minimum line spacing regardless of the text
+         * rendered. For example, usually Japanese script has larger vertical metrics than Latin
+         * script. By setting the metrics obtained by
+         * {@link Paint#getFontMetricsForLocale(Paint.FontMetrics)} for Japanese or leave it
+         * {@code null} if the Paint's locale is Japanese, the line spacing for Japanese is reserved
+         * if the text is an English text. If the vertical metrics of the text is larger than
+         * Japanese, for example Burmese, the bigger font metrics is used.
+         *
+         * @param minimumFontMetrics A minimum font metrics. Passing {@code null} for using the
+         *                          value obtained by
+         *                          {@link Paint#getFontMetricsForLocale(Paint.FontMetrics)}
+         * @see android.widget.TextView#setMinimumFontMetrics(Paint.FontMetrics)
+         * @see android.widget.TextView#getMinimumFontMetrics()
+         * @see Layout#getMinimumFontMetrics()
+         * @see Layout.Builder#setMinimumFontMetrics(Paint.FontMetrics)
+         * @see DynamicLayout.Builder#setMinimumFontMetrics(Paint.FontMetrics)
+         */
+        @NonNull
+        @FlaggedApi(FLAG_FIX_LINE_HEIGHT_FOR_LOCALE)
+        public Builder setMinimumFontMetrics(@Nullable Paint.FontMetrics minimumFontMetrics) {
+            mMinimumFontMetrics = minimumFontMetrics;
+            return this;
+        }
+
         /**
          * Build the {@link StaticLayout} after options have been set.
          *
@@ -520,6 +558,7 @@ public class StaticLayout extends Layout {
         private LineBreakConfig mLineBreakConfig = LineBreakConfig.NONE;
         private boolean mUseBoundsForWidth;
         private boolean mCalculateBounds;
+        @Nullable private Paint.FontMetrics mMinimumFontMetrics;
 
         private final Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt();
 
@@ -550,7 +589,8 @@ public class StaticLayout extends Layout {
                 null,  // rightIndents
                 JUSTIFICATION_MODE_NONE,
                 null,  // lineBreakConfig,
-                false  // useBoundsForWidth
+                false,  // useBoundsForWidth
+                null  // minimumFontMetrics
         );
 
         mColumns = COLUMNS_ELLIPSIZE;
@@ -627,7 +667,8 @@ public class StaticLayout extends Layout {
                 b.mPaint, b.mWidth, b.mAlignment, b.mTextDir, b.mSpacingMult, b.mSpacingAdd,
                 b.mIncludePad, b.mFallbackLineSpacing, b.mEllipsizedWidth, b.mEllipsize,
                 b.mMaxLines, b.mBreakStrategy, b.mHyphenationFrequency, b.mLeftIndents,
-                b.mRightIndents, b.mJustificationMode, b.mLineBreakConfig, b.mUseBoundsForWidth);
+                b.mRightIndents, b.mJustificationMode, b.mLineBreakConfig, b.mUseBoundsForWidth,
+                b.mMinimumFontMetrics);
 
         mColumns = columnSize;
         if (b.mEllipsize != null) {
@@ -711,6 +752,35 @@ public class StaticLayout extends Layout {
             indents = null;
         }
 
+        int defaultTop;
+        int defaultAscent;
+        int defaultDescent;
+        int defaultBottom;
+        if (ClientFlags.fixLineHeightForLocale()) {
+            if (b.mMinimumFontMetrics != null) {
+                defaultTop = (int) Math.floor(b.mMinimumFontMetrics.top);
+                defaultAscent = Math.round(b.mMinimumFontMetrics.ascent);
+                defaultDescent = Math.round(b.mMinimumFontMetrics.descent);
+                defaultBottom = (int) Math.ceil(b.mMinimumFontMetrics.bottom);
+            } else {
+                paint.getFontMetricsIntForLocale(fm);
+                defaultTop = fm.top;
+                defaultAscent = fm.ascent;
+                defaultDescent = fm.descent;
+                defaultBottom = fm.bottom;
+            }
+
+            // Because the font metrics is provided by public APIs, adjust the top/bottom with
+            // ascent/descent: top must be smaller than ascent, bottom must be larger than descent.
+            defaultTop = Math.min(defaultTop, defaultAscent);
+            defaultBottom = Math.max(defaultBottom, defaultDescent);
+        } else {
+            defaultTop = 0;
+            defaultAscent = 0;
+            defaultDescent = 0;
+            defaultBottom = 0;
+        }
+
         final LineBreaker lineBreaker = new LineBreaker.Builder()
                 .setBreakStrategy(b.mBreakStrategy)
                 .setHyphenationFrequency(getBaseHyphenationFrequency(b.mHyphenationFrequency))
@@ -889,7 +959,10 @@ public class StaticLayout extends Layout {
             // measuring
             int here = paraStart;
 
-            int fmTop = 0, fmBottom = 0, fmAscent = 0, fmDescent = 0;
+            int fmTop = defaultTop;
+            int fmBottom = defaultBottom;
+            int fmAscent = defaultAscent;
+            int fmDescent = defaultDescent;
             int fmCacheIndex = 0;
             int spanEndCacheIndex = 0;
             int breakIndex = 0;
@@ -982,7 +1055,15 @@ public class StaticLayout extends Layout {
                 && mLineCount < mMaximumVisibleLineCount) {
             final MeasuredParagraph measuredPara =
                     MeasuredParagraph.buildForBidi(source, bufEnd, bufEnd, textDir, null);
-            paint.getFontMetricsInt(fm);
+            if (ClientFlags.fixLineHeightForLocale()) {
+                fm.top = defaultTop;
+                fm.ascent = defaultAscent;
+                fm.descent = defaultDescent;
+                fm.bottom = defaultBottom;
+            } else {
+                paint.getFontMetricsInt(fm);
+            }
+
             v = out(source,
                     bufEnd, bufEnd, fm.ascent, fm.descent,
                     fm.top, fm.bottom,
diff --git a/core/java/android/text/TextFlags.java b/core/java/android/text/TextFlags.java
index b8b30c230e5e24c315a3993107d4995fe33cd1f1..24663862400dc8ba5925f3e3d9f470341442c693 100644
--- a/core/java/android/text/TextFlags.java
+++ b/core/java/android/text/TextFlags.java
@@ -58,6 +58,7 @@ public final class TextFlags {
             Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN,
             Flags.FLAG_PHRASE_STRICT_FALLBACK,
             Flags.FLAG_USE_BOUNDS_FOR_WIDTH,
+            Flags.FLAG_FIX_LINE_HEIGHT_FOR_LOCALE,
     };
 
     /**
@@ -69,6 +70,7 @@ public final class TextFlags {
             Flags.noBreakNoHyphenationSpan(),
             Flags.phraseStrictFallback(),
             Flags.useBoundsForWidth(),
+            Flags.fixLineHeightForLocale(),
     };
 
     /**
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index fb24211e591a9e88cb46418c7a4864120024d7d9..90663c7ad38ed8df44a2a9eff38755987c3cb671 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -1283,7 +1283,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
             @AnimationType int animationType,
             @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation,
             boolean useInsetsAnimationThread, @Nullable ImeTracker.Token statsToken) {
-        ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_CONTROL_ANIMATION);
         if ((types & mTypesBeingCancelled) != 0) {
             final boolean monitoredAnimation =
                     animationType == ANIMATION_TYPE_SHOW || animationType == ANIMATION_TYPE_HIDE;
@@ -1295,12 +1294,15 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
                     ImeTracker.forLatency().onHideCancelled(statsToken,
                             PHASE_CLIENT_ANIMATION_CANCEL, ActivityThread::currentApplication);
                 }
+                ImeTracker.forLogging().onCancelled(statsToken,
+                        ImeTracker.PHASE_CLIENT_CONTROL_ANIMATION);
             }
             throw new IllegalStateException("Cannot start a new insets animation of "
                     + Type.toString(types)
                     + " while an existing " + Type.toString(mTypesBeingCancelled)
                     + " is being cancelled.");
         }
+        ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_CONTROL_ANIMATION);
         if (types == 0) {
             // nothing to animate.
             listener.onCancelled(null);
@@ -1309,8 +1311,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
             Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.showRequestFromApiToImeReady", 0);
             return;
         }
-        ImeTracker.forLogging().onProgress(statsToken,
-                ImeTracker.PHASE_CLIENT_DISABLED_USER_ANIMATION);
         if (DEBUG) Log.d(TAG, "controlAnimation types: " + types);
         mLastStartedAnimTypes |= types;
 
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 42b3e38b544fa9bd1a466bd59f1a2f2108b3222b..57011e8794540226b3d0e5901e8995392709a9e9 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -363,14 +363,6 @@ public final class ContentCaptureManager {
     public static final String DEVICE_CONFIG_PROPERTY_ENABLE_CONTENT_PROTECTION_RECEIVER =
             "enable_content_protection_receiver";
 
-    /**
-     * Sets the size of the app blocklist for the content protection flow.
-     *
-     * @hide
-     */
-    public static final String DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_APPS_BLOCKLIST_SIZE =
-            "content_protection_apps_blocklist_size";
-
     /**
      * Sets the size of the in-memory ring buffer for the content protection flow.
      *
@@ -440,8 +432,6 @@ public final class ContentCaptureManager {
     /** @hide */
     public static final boolean DEFAULT_ENABLE_CONTENT_PROTECTION_RECEIVER = false;
     /** @hide */
-    public static final int DEFAULT_CONTENT_PROTECTION_APPS_BLOCKLIST_SIZE = 5000;
-    /** @hide */
     public static final int DEFAULT_CONTENT_PROTECTION_BUFFER_SIZE = 150;
     /** @hide */
     public static final List<List<String>> DEFAULT_CONTENT_PROTECTION_REQUIRED_GROUPS =
diff --git a/core/java/android/view/inputmethod/ImeTracker.java b/core/java/android/view/inputmethod/ImeTracker.java
index f9d8b083ee9ca7bed81a424cae35f1c28e056c4d..1bc7353971156fcfd9dccfb71e506b29c7dd0c20 100644
--- a/core/java/android/view/inputmethod/ImeTracker.java
+++ b/core/java/android/view/inputmethod/ImeTracker.java
@@ -172,7 +172,6 @@ public interface ImeTracker {
             PHASE_CLIENT_HANDLE_HIDE_INSETS,
             PHASE_CLIENT_APPLY_ANIMATION,
             PHASE_CLIENT_CONTROL_ANIMATION,
-            PHASE_CLIENT_DISABLED_USER_ANIMATION,
             PHASE_CLIENT_COLLECT_SOURCE_CONTROLS,
             PHASE_CLIENT_INSETS_CONSUMER_REQUEST_SHOW,
             PHASE_CLIENT_REQUEST_IME_SHOW,
@@ -292,9 +291,6 @@ public interface ImeTracker {
     /** Started the IME window insets show animation. */
     int PHASE_CLIENT_CONTROL_ANIMATION = ImeProtoEnums.PHASE_CLIENT_CONTROL_ANIMATION;
 
-    /** Checked that the IME is controllable. */
-    int PHASE_CLIENT_DISABLED_USER_ANIMATION = ImeProtoEnums.PHASE_CLIENT_DISABLED_USER_ANIMATION;
-
     /** Collecting insets source controls. */
     int PHASE_CLIENT_COLLECT_SOURCE_CONTROLS = ImeProtoEnums.PHASE_CLIENT_COLLECT_SOURCE_CONTROLS;
 
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index a0628c4b95804d2ee043d2e0c217e45a4b1339d5..6da6a64dc0423bc93bfa53fdfdad4cad0703c571 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -28,6 +28,7 @@ import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_C
 import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY;
 import static android.view.inputmethod.CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION;
 
+import static com.android.text.flags.Flags.FLAG_FIX_LINE_HEIGHT_FOR_LOCALE;
 import static com.android.text.flags.Flags.FLAG_USE_BOUNDS_FOR_WIDTH;
 
 import android.R;
@@ -865,6 +866,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
     private final boolean mUseTextPaddingForUiTranslation;
 
     private boolean mUseBoundsForWidth;
+    @Nullable private Paint.FontMetrics mMinimumFontMetrics;
 
     @ViewDebug.ExportedProperty(category = "text")
     @UnsupportedAppUsage
@@ -4900,6 +4902,58 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
         return mUseBoundsForWidth;
     }
 
+    /**
+     * Set the minimum font metrics used for line spacing.
+     *
+     * <p>
+     * {@code null} is the default value. If {@code null} is set or left as default, the font
+     * metrics obtained by {@link Paint#getFontMetricsForLocale(Paint.FontMetrics)} is used.
+     *
+     * <p>
+     * The minimum meaning here is the minimum value of line spacing: maximum value of
+     * {@link Paint#ascent()}, minimum value of {@link Paint#descent()}.
+     *
+     * <p>
+     * By setting this value, each line will have minimum line spacing regardless of the text
+     * rendered. For example, usually Japanese script has larger vertical metrics than Latin script.
+     * By setting the metrics obtained by {@link Paint#getFontMetricsForLocale(Paint.FontMetrics)}
+     * for Japanese or leave it {@code null} if the TextView's locale or system locale is Japanese,
+     * the line spacing for Japanese is reserved if the TextView contains English text. If the
+     * vertical metrics of the text is larger than Japanese, for example Burmese, the bigger font
+     * metrics is used.
+     *
+     * @param minimumFontMetrics A minimum font metrics. Passing {@code null} for using the value
+     *                           obtained by
+     *                           {@link Paint#getFontMetricsForLocale(Paint.FontMetrics)}
+     * @see #getMinimumFontMetrics()
+     * @see Layout#getMinimumFontMetrics()
+     * @see Layout.Builder#setMinimumFontMetrics(Paint.FontMetrics)
+     * @see StaticLayout.Builder#setMinimumFontMetrics(Paint.FontMetrics)
+     * @see DynamicLayout.Builder#setMinimumFontMetrics(Paint.FontMetrics)
+     */
+    @FlaggedApi(FLAG_FIX_LINE_HEIGHT_FOR_LOCALE)
+    public void setMinimumFontMetrics(@Nullable Paint.FontMetrics minimumFontMetrics) {
+        mMinimumFontMetrics = minimumFontMetrics;
+    }
+
+    /**
+     * Get the minimum font metrics used for line spacing.
+     *
+     * @see #setMinimumFontMetrics(Paint.FontMetrics)
+     * @see Layout#getMinimumFontMetrics()
+     * @see Layout.Builder#setMinimumFontMetrics(Paint.FontMetrics)
+     * @see StaticLayout.Builder#setMinimumFontMetrics(Paint.FontMetrics)
+     * @see DynamicLayout.Builder#setMinimumFontMetrics(Paint.FontMetrics)
+     *
+     * @return a minimum font metrics. {@code null} for using the value obtained by
+     *         {@link Paint#getFontMetricsForLocale(Paint.FontMetrics)}
+     */
+    @Nullable
+    @FlaggedApi(FLAG_FIX_LINE_HEIGHT_FOR_LOCALE)
+    public Paint.FontMetrics getMinimumFontMetrics() {
+        return mMinimumFontMetrics;
+    }
+
     /**
      * @return whether fallback line spacing is enabled, {@code true} by default
      *
@@ -10683,7 +10737,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
 
             if (hintBoring == UNKNOWN_BORING) {
                 hintBoring = BoringLayout.isBoring(mHint, mTextPaint, mTextDir,
-                        isFallbackLineSpacingForBoringLayout(), mHintBoring);
+                        isFallbackLineSpacingForBoringLayout(),
+                        mMinimumFontMetrics, mHintBoring);
                 if (hintBoring != null) {
                     mHintBoring = hintBoring;
                 }
@@ -10732,7 +10787,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                         .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE)
                         .setLineBreakConfig(LineBreakConfig.getLineBreakConfig(
                                 mLineBreakStyle, mLineBreakWordStyle))
-                        .setUseBoundsForWidth(mUseBoundsForWidth);
+                        .setUseBoundsForWidth(mUseBoundsForWidth)
+                        .setMinimumFontMetrics(mMinimumFontMetrics);
                 if (shouldEllipsize) {
                     builder.setEllipsize(mEllipsize)
                             .setEllipsizedWidth(ellipsisWidth);
@@ -10796,12 +10852,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                             mLineBreakStyle, mLineBreakWordStyle))
                     .setUseBoundsForWidth(mUseBoundsForWidth)
                     .setEllipsize(getKeyListener() == null ? effectiveEllipsize : null)
-                    .setEllipsizedWidth(ellipsisWidth);
+                    .setEllipsizedWidth(ellipsisWidth)
+                    .setMinimumFontMetrics(mMinimumFontMetrics);
             result = builder.build();
         } else {
             if (boring == UNKNOWN_BORING) {
                 boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir,
-                        isFallbackLineSpacingForBoringLayout(), mBoring);
+                        isFallbackLineSpacingForBoringLayout(), mMinimumFontMetrics, mBoring);
                 if (boring != null) {
                     mBoring = boring;
                 }
@@ -10815,7 +10872,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                                 wantWidth, alignment, mSpacingMult, mSpacingAdd,
                                 boring, mIncludePad, null, wantWidth,
                                 isFallbackLineSpacingForBoringLayout(),
-                                mUseBoundsForWidth);
+                                mUseBoundsForWidth, mMinimumFontMetrics);
                     } else {
                         result = new BoringLayout(
                                 mTransformed,
@@ -10829,7 +10886,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                                 wantWidth,
                                 null,
                                 boring,
-                                mUseBoundsForWidth);
+                                mUseBoundsForWidth,
+                                mMinimumFontMetrics);
                     }
 
                     if (useSaved) {
@@ -10841,7 +10899,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                                 wantWidth, alignment, mSpacingMult, mSpacingAdd,
                                 boring, mIncludePad, effectiveEllipsize,
                                 ellipsisWidth, isFallbackLineSpacingForBoringLayout(),
-                                mUseBoundsForWidth);
+                                mUseBoundsForWidth, mMinimumFontMetrics);
                     } else {
                         result = new BoringLayout(
                                 mTransformed,
@@ -10855,7 +10913,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                                 ellipsisWidth,
                                 effectiveEllipsize,
                                 boring,
-                                mUseBoundsForWidth);
+                                mUseBoundsForWidth,
+                                mMinimumFontMetrics);
                     }
                 }
             }
@@ -10874,7 +10933,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                     .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE)
                     .setLineBreakConfig(LineBreakConfig.getLineBreakConfig(
                             mLineBreakStyle, mLineBreakWordStyle))
-                    .setUseBoundsForWidth(mUseBoundsForWidth);
+                    .setUseBoundsForWidth(mUseBoundsForWidth)
+                    .setMinimumFontMetrics(mMinimumFontMetrics);
             if (shouldEllipsize) {
                 builder.setEllipsize(effectiveEllipsize)
                         .setEllipsizedWidth(ellipsisWidth);
@@ -11002,7 +11062,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
 
             if (des < 0) {
                 boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir,
-                        isFallbackLineSpacingForBoringLayout(), mBoring);
+                        isFallbackLineSpacingForBoringLayout(), mMinimumFontMetrics, mBoring);
                 if (boring != null) {
                     mBoring = boring;
                 }
@@ -11042,7 +11102,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
 
                 if (hintDes < 0) {
                     hintBoring = BoringLayout.isBoring(mHint, mTextPaint, mTextDir,
-                            isFallbackLineSpacingForBoringLayout(), mHintBoring);
+                            isFallbackLineSpacingForBoringLayout(), mMinimumFontMetrics,
+                            mHintBoring);
                     if (hintBoring != null) {
                         mHintBoring = hintBoring;
                     }
@@ -11254,7 +11315,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                 .setTextDirection(getTextDirectionHeuristic())
                 .setLineBreakConfig(LineBreakConfig.getLineBreakConfig(
                         mLineBreakStyle, mLineBreakWordStyle))
-                .setUseBoundsForWidth(mUseBoundsForWidth);
+                .setUseBoundsForWidth(mUseBoundsForWidth)
+                .setMinimumFontMetrics(mMinimumFontMetrics);
 
         final StaticLayout layout = layoutBuilder.build();
 
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index 79b3b4f686b40383a26626edc4a3fdb0ca520efc..4705dc5db90ba30161afbe2bcfd27f179798490e 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -23,7 +23,7 @@ flag {
 }
 
 flag {
-  name: "dimmer_refactor"
+  name: "introduce_smoother_dimmer"
   namespace: "windowing_frontend"
   description: "Refactor dim to fix flickers"
   bug: "295291019"
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index 7e9cef720a136ee74b85b92c4fc50acc9c7754dc..e6b036cfaa19d6277ff8a743921f170dda33a3b2 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -58,6 +58,9 @@ import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_IN
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__ONE_HANDED_ENTER_TRANSITION;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__ONE_HANDED_EXIT_TRANSITION;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PIP_TRANSITION;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PREDICTIVE_BACK_CROSS_ACTIVITY;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PREDICTIVE_BACK_CROSS_TASK;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PREDICTIVE_BACK_HOME;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__RECENTS_SCROLLING;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SCREEN_OFF;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SCREEN_OFF_SHOW_AOD;
@@ -276,7 +279,11 @@ public class InteractionJankMonitor {
 
     public static final int CUJ_LAUNCHER_UNFOLD_ANIM = 83;
 
-    private static final int LAST_CUJ = CUJ_LAUNCHER_UNFOLD_ANIM;
+    public static final int CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY = 84;
+    public static final int CUJ_PREDICTIVE_BACK_CROSS_TASK = 85;
+    public static final int CUJ_PREDICTIVE_BACK_HOME = 86;
+
+    private static final int LAST_CUJ = CUJ_PREDICTIVE_BACK_HOME;
     private static final int NO_STATSD_LOGGING = -1;
 
     // Used to convert CujType to InteractionType enum value for statsd logging.
@@ -370,6 +377,12 @@ public class InteractionJankMonitor {
         CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_IME_INSETS_HIDE_ANIMATION] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__IME_INSETS_HIDE_ANIMATION;
         CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_SPLIT_SCREEN_DOUBLE_TAP_DIVIDER] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLIT_SCREEN_DOUBLE_TAP_DIVIDER;
         CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_UNFOLD_ANIM] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_UNFOLD_ANIM;
+        CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY] =
+            UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PREDICTIVE_BACK_CROSS_ACTIVITY;
+        CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_PREDICTIVE_BACK_CROSS_TASK] =
+            UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PREDICTIVE_BACK_CROSS_TASK;
+        CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_PREDICTIVE_BACK_HOME] =
+            UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PREDICTIVE_BACK_HOME;
     }
 
     private static class InstanceHolder {
@@ -473,6 +486,9 @@ public class InteractionJankMonitor {
             CUJ_IME_INSETS_HIDE_ANIMATION,
             CUJ_SPLIT_SCREEN_DOUBLE_TAP_DIVIDER,
             CUJ_LAUNCHER_UNFOLD_ANIM,
+            CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY,
+            CUJ_PREDICTIVE_BACK_CROSS_TASK,
+            CUJ_PREDICTIVE_BACK_HOME,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface CujType {
@@ -1108,6 +1124,12 @@ public class InteractionJankMonitor {
                 return "SPLIT_SCREEN_DOUBLE_TAP_DIVIDER";
             case CUJ_LAUNCHER_UNFOLD_ANIM:
                 return "LAUNCHER_UNFOLD_ANIM";
+            case CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY:
+                return "PREDICTIVE_BACK_CROSS_ACTIVITY";
+            case CUJ_PREDICTIVE_BACK_CROSS_TASK:
+                return "PREDICTIVE_BACK_CROSS_TASK";
+            case CUJ_PREDICTIVE_BACK_HOME:
+                return "PREDICTIVE_BACK_HOME";
         }
         return "UNKNOWN";
     }
diff --git a/core/jni/android_view_InputDevice.cpp b/core/jni/android_view_InputDevice.cpp
index f97d41b6a122eaffe3a794c2b117c4019e688e07..262f5e8e761e2f2373b76b788c3e8c8a48dcb988 100644
--- a/core/jni/android_view_InputDevice.cpp
+++ b/core/jni/android_view_InputDevice.cpp
@@ -42,13 +42,6 @@ jobject android_view_InputDevice_create(JNIEnv* env, const InputDeviceInfo& devi
         return NULL;
     }
 
-    // b/274058082: Pass a copy of the key character map to avoid concurrent
-    // access
-    std::shared_ptr<KeyCharacterMap> map = deviceInfo.getKeyCharacterMap();
-    if (map != nullptr) {
-        map = std::make_shared<KeyCharacterMap>(*map);
-    }
-
     ScopedLocalRef<jstring> descriptorObj(env,
             env->NewStringUTF(deviceInfo.getIdentifier().descriptor.c_str()));
     if (!descriptorObj.get()) {
@@ -67,9 +60,14 @@ jobject android_view_InputDevice_create(JNIEnv* env, const InputDeviceInfo& devi
                                                                   ? layoutInfo->layoutType.c_str()
                                                                   : NULL));
 
+    std::shared_ptr<KeyCharacterMap> map = deviceInfo.getKeyCharacterMap();
+    std::unique_ptr<KeyCharacterMap> mapCopy;
+    if (map != nullptr) {
+        mapCopy = std::make_unique<KeyCharacterMap>(*map);
+    }
     ScopedLocalRef<jobject> kcmObj(env,
                                    android_view_KeyCharacterMap_create(env, deviceInfo.getId(),
-                                                                       map));
+                                                                       std::move(mapCopy)));
     if (!kcmObj.get()) {
         return NULL;
     }
diff --git a/core/jni/android_view_KeyCharacterMap.cpp b/core/jni/android_view_KeyCharacterMap.cpp
index 7f69e22fb0d1d1572802d09c4768e01357e14a17..a79e37afd4cd59bc35c6521bc7158d1696fa4efa 100644
--- a/core/jni/android_view_KeyCharacterMap.cpp
+++ b/core/jni/android_view_KeyCharacterMap.cpp
@@ -48,7 +48,7 @@ static struct {
 
 class NativeKeyCharacterMap {
 public:
-    NativeKeyCharacterMap(int32_t deviceId, std::shared_ptr<KeyCharacterMap> map)
+    NativeKeyCharacterMap(int32_t deviceId, std::unique_ptr<KeyCharacterMap> map)
           : mDeviceId(deviceId), mMap(std::move(map)) {}
 
     ~NativeKeyCharacterMap() {
@@ -58,16 +58,18 @@ public:
         return mDeviceId;
     }
 
-    inline const std::shared_ptr<KeyCharacterMap> getMap() const { return mMap; }
+    inline const std::unique_ptr<KeyCharacterMap>& getMap() const {
+        return mMap;
+    }
 
 private:
     int32_t mDeviceId;
-    std::shared_ptr<KeyCharacterMap> mMap;
+    std::unique_ptr<KeyCharacterMap> mMap;
 };
 
 jobject android_view_KeyCharacterMap_create(JNIEnv* env, int32_t deviceId,
-                                            const std::shared_ptr<KeyCharacterMap> kcm) {
-    NativeKeyCharacterMap* nativeMap = new NativeKeyCharacterMap(deviceId, kcm);
+                                            std::unique_ptr<KeyCharacterMap> kcm) {
+    NativeKeyCharacterMap* nativeMap = new NativeKeyCharacterMap(deviceId, std::move(kcm));
     if (!nativeMap) {
         return nullptr;
     }
@@ -91,7 +93,7 @@ static jlong nativeReadFromParcel(JNIEnv *env, jobject clazz, jobject parcelObj)
         return 0;
     }
 
-    std::shared_ptr<KeyCharacterMap> kcm = nullptr;
+    std::unique_ptr<KeyCharacterMap> kcm;
     // Check if map is a null character map
     if (parcel->readBool()) {
         kcm = KeyCharacterMap::readFromParcel(parcel);
@@ -99,7 +101,7 @@ static jlong nativeReadFromParcel(JNIEnv *env, jobject clazz, jobject parcelObj)
             return 0;
         }
     }
-    NativeKeyCharacterMap* map = new NativeKeyCharacterMap(deviceId, kcm);
+    NativeKeyCharacterMap* map = new NativeKeyCharacterMap(deviceId, std::move(kcm));
     return reinterpret_cast<jlong>(map);
 }
 
@@ -230,9 +232,9 @@ static jobjectArray nativeGetEvents(JNIEnv *env, jobject clazz, jlong ptr,
 }
 
 static jboolean nativeEquals(JNIEnv* env, jobject clazz, jlong ptr1, jlong ptr2) {
-    const std::shared_ptr<KeyCharacterMap>& map1 =
+    const std::unique_ptr<KeyCharacterMap>& map1 =
             (reinterpret_cast<NativeKeyCharacterMap*>(ptr1))->getMap();
-    const std::shared_ptr<KeyCharacterMap>& map2 =
+    const std::unique_ptr<KeyCharacterMap>& map2 =
             (reinterpret_cast<NativeKeyCharacterMap*>(ptr2))->getMap();
     if (map1 == nullptr || map2 == nullptr) {
         return map1 == map2;
diff --git a/core/jni/android_view_KeyCharacterMap.h b/core/jni/android_view_KeyCharacterMap.h
index be0335380f872f93078b2d8e4d666227fc3b4f71..a8aabd1d464a218e111f6dfb4fbb22727d357ce1 100644
--- a/core/jni/android_view_KeyCharacterMap.h
+++ b/core/jni/android_view_KeyCharacterMap.h
@@ -25,7 +25,7 @@ namespace android {
 
 /* Creates a KeyCharacterMap object from the given information. */
 extern jobject android_view_KeyCharacterMap_create(JNIEnv* env, int32_t deviceId,
-                                                   const std::shared_ptr<KeyCharacterMap> kcm);
+                                                   std::unique_ptr<KeyCharacterMap> kcm);
 
 } // namespace android
 
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
index 7f3e01432dd9d78323c5cd8786bced973582c864..9430ba6a939a07e53d9c22f7fd6fd98d0e912045 100644
--- a/core/tests/coretests/src/android/app/NotificationTest.java
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -857,7 +857,8 @@ public class NotificationTest {
             assertEquals(cDay.getPrimaryAccentColor(), cNight.getPrimaryAccentColor());
             assertEquals(cDay.getSecondaryAccentColor(), cNight.getSecondaryAccentColor());
             assertEquals(cDay.getTertiaryAccentColor(), cNight.getTertiaryAccentColor());
-            assertEquals(cDay.getOnAccentTextColor(), cNight.getOnAccentTextColor());
+            assertEquals(cDay.getOnTertiaryAccentTextColor(),
+                    cNight.getOnTertiaryAccentTextColor());
             assertEquals(cDay.getProtectionColor(), cNight.getProtectionColor());
             assertEquals(cDay.getContrastColor(), cNight.getContrastColor());
             assertEquals(cDay.getRippleAlpha(), cNight.getRippleAlpha());
@@ -1830,7 +1831,7 @@ public class NotificationTest {
         assertThat(c.getPrimaryAccentColor()).isNotEqualTo(Notification.COLOR_INVALID);
         assertThat(c.getSecondaryAccentColor()).isNotEqualTo(Notification.COLOR_INVALID);
         assertThat(c.getTertiaryAccentColor()).isNotEqualTo(Notification.COLOR_INVALID);
-        assertThat(c.getOnAccentTextColor()).isNotEqualTo(Notification.COLOR_INVALID);
+        assertThat(c.getOnTertiaryAccentTextColor()).isNotEqualTo(Notification.COLOR_INVALID);
         assertThat(c.getErrorColor()).isNotEqualTo(Notification.COLOR_INVALID);
         assertThat(c.getContrastColor()).isNotEqualTo(Notification.COLOR_INVALID);
         assertThat(c.getRippleAlpha()).isAtLeast(0x00);
@@ -1848,7 +1849,7 @@ public class NotificationTest {
         assertContrastIsAtLeast(c.getTertiaryAccentColor(), c.getBackgroundColor(), 1);
 
         // The text that is used within the accent color DOES need to have contrast
-        assertContrastIsAtLeast(c.getOnAccentTextColor(), c.getTertiaryAccentColor(), 4.5);
+        assertContrastIsAtLeast(c.getOnTertiaryAccentTextColor(), c.getTertiaryAccentColor(), 4.5);
     }
 
     private void resolveColorsInNightMode(boolean nightMode, Notification.Colors c, int rawColor,
diff --git a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionTests.java b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionTests.java
index 531404bffd5080ecfa9291b6117ba5e1ebadb939..d10cf16914083f4d2809060d7cda415281ba816f 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionTests.java
@@ -62,4 +62,24 @@ public class ClientTransactionTests {
         verify(callback2, times(1)).preExecute(clientTransactionHandler);
         verify(stateRequest, times(1)).preExecute(clientTransactionHandler);
     }
+
+    @Test
+    public void testPreExecuteTransactionItems() {
+        final ClientTransactionItem callback1 = mock(ClientTransactionItem.class);
+        final ClientTransactionItem callback2 = mock(ClientTransactionItem.class);
+        final ActivityLifecycleItem stateRequest = mock(ActivityLifecycleItem.class);
+        final ClientTransactionHandler clientTransactionHandler =
+                mock(ClientTransactionHandler.class);
+
+        final ClientTransaction transaction = ClientTransaction.obtain(null /* client */);
+        transaction.addTransactionItem(callback1);
+        transaction.addTransactionItem(callback2);
+        transaction.addTransactionItem(stateRequest);
+
+        transaction.preExecute(clientTransactionHandler);
+
+        verify(callback1, times(1)).preExecute(clientTransactionHandler);
+        verify(callback2, times(1)).preExecute(clientTransactionHandler);
+        verify(stateRequest, times(1)).preExecute(clientTransactionHandler);
+    }
 }
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
index 44a4d580dbc0339939d6be5056dbd83194207c0c..f2b0f2e622b8327026c3870c24464273f36bb2a0 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
@@ -246,6 +246,31 @@ public class TransactionExecutorTests {
         inOrder.verify(stateRequest).execute(eq(mTransactionHandler), eq(mClientRecord), any());
     }
 
+    @Test
+    public void testExecuteTransactionItems_transactionResolution() {
+        ClientTransactionItem callback1 = mock(ClientTransactionItem.class);
+        when(callback1.getPostExecutionState()).thenReturn(UNDEFINED);
+        ClientTransactionItem callback2 = mock(ClientTransactionItem.class);
+        when(callback2.getPostExecutionState()).thenReturn(UNDEFINED);
+        ActivityLifecycleItem stateRequest = mock(ActivityLifecycleItem.class);
+        IBinder token = mock(IBinder.class);
+        when(stateRequest.getActivityToken()).thenReturn(token);
+        when(mTransactionHandler.getActivity(token)).thenReturn(mock(Activity.class));
+
+        ClientTransaction transaction = ClientTransaction.obtain(null /* client */);
+        transaction.addTransactionItem(callback1);
+        transaction.addTransactionItem(callback2);
+        transaction.addTransactionItem(stateRequest);
+
+        transaction.preExecute(mTransactionHandler);
+        mExecutor.execute(transaction);
+
+        InOrder inOrder = inOrder(mTransactionHandler, callback1, callback2, stateRequest);
+        inOrder.verify(callback1).execute(eq(mTransactionHandler), any());
+        inOrder.verify(callback2).execute(eq(mTransactionHandler), any());
+        inOrder.verify(stateRequest).execute(eq(mTransactionHandler), eq(mClientRecord), any());
+    }
+
     @Test
     public void testDoNotLaunchDestroyedActivity() {
         final Map<IBinder, DestroyActivityItem> activitiesToBeDestroyed = new ArrayMap<>();
@@ -278,13 +303,44 @@ public class TransactionExecutorTests {
         assertTrue(activitiesToBeDestroyed.isEmpty());
     }
 
+    @Test
+    public void testExecuteTransactionItems_doNotLaunchDestroyedActivity() {
+        final Map<IBinder, DestroyActivityItem> activitiesToBeDestroyed = new ArrayMap<>();
+        when(mTransactionHandler.getActivitiesToBeDestroyed()).thenReturn(activitiesToBeDestroyed);
+        // Assume launch transaction is still in queue, so there is no client record.
+        when(mTransactionHandler.getActivityClient(any())).thenReturn(null);
+
+        // An incoming destroy transaction enters binder thread (preExecute).
+        final IBinder token = mock(IBinder.class);
+        final ClientTransaction destroyTransaction = ClientTransaction.obtain(null /* client */);
+        destroyTransaction.addTransactionItem(
+                DestroyActivityItem.obtain(token, false /* finished */, 0 /* configChanges */));
+        destroyTransaction.preExecute(mTransactionHandler);
+        // The activity should be added to to-be-destroyed container.
+        assertEquals(1, activitiesToBeDestroyed.size());
+
+        // A previous queued launch transaction runs on main thread (execute).
+        final ClientTransaction launchTransaction = ClientTransaction.obtain(null /* client */);
+        final LaunchActivityItem launchItem =
+                spy(new LaunchActivityItemBuilder().setActivityToken(token).build());
+        launchTransaction.addTransactionItem(launchItem);
+        mExecutor.execute(launchTransaction);
+
+        // The launch transaction should not be executed because its token is in the
+        // to-be-destroyed container.
+        verify(launchItem, never()).execute(any(), any());
+
+        // After the destroy transaction has been executed, the token should be removed.
+        mExecutor.execute(destroyTransaction);
+        assertTrue(activitiesToBeDestroyed.isEmpty());
+    }
+
     @Test
     public void testActivityResultRequiredStateResolution() {
         when(mTransactionHandler.getActivity(any())).thenReturn(mock(Activity.class));
 
         PostExecItem postExecItem = new PostExecItem(ON_RESUME);
 
-        IBinder token = mock(IBinder.class);
         ClientTransaction transaction = ClientTransaction.obtain(null /* client */);
         transaction.addCallback(postExecItem);
 
@@ -299,6 +355,26 @@ public class TransactionExecutorTests {
         verify(mExecutor).cycleToPath(eq(mClientRecord), eq(ON_START), eq(transaction));
     }
 
+    @Test
+    public void testExecuteTransactionItems_activityResultRequiredStateResolution() {
+        when(mTransactionHandler.getActivity(any())).thenReturn(mock(Activity.class));
+
+        PostExecItem postExecItem = new PostExecItem(ON_RESUME);
+
+        ClientTransaction transaction = ClientTransaction.obtain(null /* client */);
+        transaction.addTransactionItem(postExecItem);
+
+        // Verify resolution that should get to onPause
+        mClientRecord.setState(ON_RESUME);
+        mExecutor.executeTransactionItems(transaction);
+        verify(mExecutor).cycleToPath(eq(mClientRecord), eq(ON_PAUSE), eq(transaction));
+
+        // Verify resolution that should get to onStart
+        mClientRecord.setState(ON_STOP);
+        mExecutor.executeTransactionItems(transaction);
+        verify(mExecutor).cycleToPath(eq(mClientRecord), eq(ON_START), eq(transaction));
+    }
+
     @Test
     public void testClosestStateResolutionForSameState() {
         final int[] allStates = new int[] {
@@ -444,6 +520,18 @@ public class TransactionExecutorTests {
         mExecutor.executeCallbacks(transaction);
     }
 
+    @Test(expected = IllegalArgumentException.class)
+    public void testExecuteTransactionItems_activityItemNullRecordThrowsException() {
+        final ActivityTransactionItem activityItem = mock(ActivityTransactionItem.class);
+        when(activityItem.getPostExecutionState()).thenReturn(UNDEFINED);
+        final IBinder token = mock(IBinder.class);
+        final ClientTransaction transaction = ClientTransaction.obtain(null /* client */);
+        transaction.addTransactionItem(activityItem);
+        when(mTransactionHandler.getActivityClient(token)).thenReturn(null);
+
+        mExecutor.executeTransactionItems(transaction);
+    }
+
     @Test
     public void testActivityItemExecute() {
         final IBinder token = mock(IBinder.class);
@@ -464,6 +552,26 @@ public class TransactionExecutorTests {
         inOrder.verify(stateRequest).execute(eq(mTransactionHandler), eq(mClientRecord), any());
     }
 
+    @Test
+    public void testExecuteTransactionItems_activityItemExecute() {
+        final IBinder token = mock(IBinder.class);
+        final ClientTransaction transaction = ClientTransaction.obtain(null /* client */);
+        final ActivityTransactionItem activityItem = mock(ActivityTransactionItem.class);
+        when(activityItem.getPostExecutionState()).thenReturn(UNDEFINED);
+        when(activityItem.getActivityToken()).thenReturn(token);
+        transaction.addTransactionItem(activityItem);
+        final ActivityLifecycleItem stateRequest = mock(ActivityLifecycleItem.class);
+        transaction.addTransactionItem(stateRequest);
+        when(stateRequest.getActivityToken()).thenReturn(token);
+        when(mTransactionHandler.getActivity(token)).thenReturn(mock(Activity.class));
+
+        mExecutor.execute(transaction);
+
+        final InOrder inOrder = inOrder(activityItem, stateRequest);
+        inOrder.verify(activityItem).execute(eq(mTransactionHandler), eq(mClientRecord), any());
+        inOrder.verify(stateRequest).execute(eq(mTransactionHandler), eq(mClientRecord), any());
+    }
+
     private static int[] shuffledArray(int[] inputArray) {
         final List<Integer> list = Arrays.stream(inputArray).boxed().collect(Collectors.toList());
         Collections.shuffle(list);
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index 7d047c93520f490998f98040586d57e6e9ab42df..4aa62c503a41b8b10af4765735d39136058a684a 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -285,6 +285,10 @@ public class TransactionParcelTests {
                 78 /* configChanges */);
 
         ClientTransaction transaction = ClientTransaction.obtain(null /* client */);
+        transaction.addTransactionItem(callback1);
+        transaction.addTransactionItem(callback2);
+        transaction.addTransactionItem(lifecycleRequest);
+
         transaction.addCallback(callback1);
         transaction.addCallback(callback2);
         transaction.setLifecycleStateRequest(lifecycleRequest);
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 9fde0fd6e6ab69f72aa4de2e20a154c68dc368e0..4eaa01309ab129a59fc14ec5f7a82f206661fce3 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -2113,6 +2113,31 @@ public class Paint {
          * The recommended additional space to add between lines of text.
          */
         public float   leading;
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || !(o instanceof FontMetrics)) return false;
+            FontMetrics that = (FontMetrics) o;
+            return that.top == top && that.ascent == ascent && that.descent == descent
+                    && that.bottom == bottom && that.leading == leading;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(top, ascent, descent, bottom, leading);
+        }
+
+        @Override
+        public String toString() {
+            return "FontMetrics{"
+                    + "top=" + top
+                    + ", ascent=" + ascent
+                    + ", descent=" + descent
+                    + ", bottom=" + bottom
+                    + ", leading=" + leading
+                    + '}';
+        }
     }
 
     /**
@@ -2309,6 +2334,33 @@ public class Paint {
          */
         public int   leading;
 
+        /**
+         * Set values from {@link FontMetricsInt}.
+         * @param fontMetricsInt a font metrics.
+         */
+        @FlaggedApi(FLAG_FIX_LINE_HEIGHT_FOR_LOCALE)
+        public void set(@NonNull FontMetricsInt fontMetricsInt) {
+            top = fontMetricsInt.top;
+            ascent = fontMetricsInt.ascent;
+            descent = fontMetricsInt.descent;
+            bottom = fontMetricsInt.bottom;
+            leading = fontMetricsInt.leading;
+        }
+
+        /**
+         * Set values from {@link FontMetrics} with rounding accordingly.
+         * @param fontMetrics a font metrics.
+         */
+        @FlaggedApi(FLAG_FIX_LINE_HEIGHT_FOR_LOCALE)
+        public void set(@NonNull FontMetrics fontMetrics) {
+            // See GraphicsJNI::set_metrics_int method for consistency.
+            top = (int) Math.floor(fontMetrics.top);
+            ascent = Math.round(fontMetrics.ascent);
+            descent = Math.round(fontMetrics.descent);
+            bottom = (int) Math.ceil(fontMetrics.bottom);
+            leading = Math.round(fontMetrics.leading);
+        }
+
         @Override public String toString() {
             return "FontMetricsInt: top=" + top + " ascent=" + ascent +
                     " descent=" + descent + " bottom=" + bottom +
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index 2f1eec15e4155291004d85b976df0b526a2d78b1..49606f0bf4857c4ed1463b2834a21beefc2c5e7b 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -292,8 +292,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
             // Resets the isolated navigation and updates the container.
             final TransactionRecord transactionRecord = mTransactionManager.startNewTransaction();
             final WindowContainerTransaction wct = transactionRecord.getTransaction();
-            mPresenter.setTaskFragmentIsolatedNavigation(wct,
-                    containerToUnpin.getTaskFragmentToken(), false /* isolated */);
+            mPresenter.setTaskFragmentIsolatedNavigation(wct, containerToUnpin,
+                    false /* isolated */);
             updateContainer(wct, containerToUnpin);
             transactionRecord.apply(false /* shouldApplyIndependently */);
             updateCallbackIfNecessary();
@@ -880,19 +880,17 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
             return true;
         }
 
-        // Skip resolving if the activity is on a pinned TaskFragmentContainer.
-        // TODO(b/243518738): skip resolving for overlay container.
-        final TaskContainer taskContainer = container != null ? container.getTaskContainer() : null;
-        if (container != null && taskContainer != null
-                && taskContainer.isTaskFragmentContainerPinned(container)) {
+        // Skip resolving if the activity is on an isolated navigated TaskFragmentContainer.
+        if (container != null && container.isIsolatedNavigationEnabled()) {
             return true;
         }
 
+        final TaskContainer taskContainer = container != null ? container.getTaskContainer() : null;
         if (!isOnReparent && taskContainer != null
                 && taskContainer.getTopNonFinishingTaskFragmentContainer(false /* includePin */)
                         != container) {
             // Do not resolve if the launched activity is not the top-most container (excludes
-            // the pinned container) in the Task.
+            // the pinned and overlay container) in the Task.
             return true;
         }
 
@@ -1312,15 +1310,12 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
     @GuardedBy("mLock")
     TaskFragmentContainer resolveStartActivityIntent(@NonNull WindowContainerTransaction wct,
             int taskId, @NonNull Intent intent, @Nullable Activity launchingActivity) {
-        // Skip resolving if started from pinned TaskFragmentContainer.
-        // TODO(b/243518738): skip resolving for overlay container.
+        // Skip resolving if started from an isolated navigated TaskFragmentContainer.
         if (launchingActivity != null) {
             final TaskFragmentContainer taskFragmentContainer = getContainerWithActivity(
                     launchingActivity);
-            final TaskContainer taskContainer =
-                    taskFragmentContainer != null ? taskFragmentContainer.getTaskContainer() : null;
-            if (taskContainer != null && taskContainer.isTaskFragmentContainerPinned(
-                    taskFragmentContainer)) {
+            if (taskFragmentContainer != null
+                    && taskFragmentContainer.isIsolatedNavigationEnabled()) {
                 return null;
             }
         }
@@ -1755,31 +1750,6 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
                 false /* shouldFinishDependent */, mPresenter, wct, this);
     }
 
-    /**
-     * Returns the topmost not finished container in Task of given task id.
-     */
-    @GuardedBy("mLock")
-    @Nullable
-    TaskFragmentContainer getTopActiveContainer(int taskId) {
-        final TaskContainer taskContainer = mTaskContainers.get(taskId);
-        if (taskContainer == null) {
-            return null;
-        }
-        final List<TaskFragmentContainer> containers = taskContainer.getTaskFragmentContainers();
-        for (int i = containers.size() - 1; i >= 0; i--) {
-            final TaskFragmentContainer container = containers.get(i);
-            if (!container.isFinished() && (container.getRunningActivityCount() > 0
-                    // We may be waiting for the top TaskFragment to become non-empty after
-                    // creation. In that case, we don't want to treat the TaskFragment below it as
-                    // top active, otherwise it may incorrectly launch placeholder on top of the
-                    // pending TaskFragment.
-                    || container.isWaitingActivityAppear())) {
-                return container;
-            }
-        }
-        return null;
-    }
-
     /**
      * Updates the presentation of the container. If the container is part of the split or should
      * have a placeholder, it will also update the other part of the split.
@@ -1968,7 +1938,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
     /** Whether or not to allow activity in this container to launch placeholder. */
     @GuardedBy("mLock")
     private boolean allowLaunchPlaceholder(@NonNull TaskFragmentContainer container) {
-        final TaskFragmentContainer topContainer = getTopActiveContainer(container.getTaskId());
+        final TaskFragmentContainer topContainer = container.getTaskContainer()
+                .getTopNonFinishingTaskFragmentContainer();
         if (container != topContainer) {
             // The container is not the top most.
             if (!container.isVisible()) {
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
index 66e76c59565200a8303074d36fc193303c153476..faf7c3999402a61ecd2fd5b2e022f613a0dbadf1 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
@@ -388,13 +388,26 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
             return;
         }
 
-        setTaskFragmentIsolatedNavigation(wct, secondaryContainer.getTaskFragmentToken(),
-                !isStacked /* isolatedNav */);
+        setTaskFragmentIsolatedNavigation(wct, secondaryContainer, !isStacked /* isolatedNav */);
         if (isStacked && !splitPinRule.isSticky()) {
             secondaryContainer.getTaskContainer().removeSplitPinContainer();
         }
     }
 
+    /**
+     * Sets whether to enable isolated navigation for this {@link TaskFragmentContainer}
+     */
+    void setTaskFragmentIsolatedNavigation(@NonNull WindowContainerTransaction wct,
+                                           @NonNull TaskFragmentContainer taskFragmentContainer,
+                                           boolean isolatedNavigationEnabled) {
+        if (taskFragmentContainer.isIsolatedNavigationEnabled() == isolatedNavigationEnabled) {
+            return;
+        }
+        taskFragmentContainer.setIsolatedNavigationEnabled(isolatedNavigationEnabled);
+        setTaskFragmentIsolatedNavigation(wct, taskFragmentContainer.getTaskFragmentToken(),
+                isolatedNavigationEnabled);
+    }
+
     /**
      * Resizes the task fragment if it was already registered. Skips the operation if the container
      * creation has not been reported from the server yet.
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
index f4427aaba182891a7c7d95d4715ef930ff6b7243..9e533808ccc0356afccc0aa4ca70859d2bfd6759 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
@@ -191,11 +191,20 @@ class TaskContainer {
 
     @Nullable
     TaskFragmentContainer getTopNonFinishingTaskFragmentContainer(boolean includePin) {
+        return getTopNonFinishingTaskFragmentContainer(includePin, false /* includeOverlay */);
+    }
+
+    @Nullable
+    TaskFragmentContainer getTopNonFinishingTaskFragmentContainer(boolean includePin,
+                                                                  boolean includeOverlay) {
         for (int i = mContainers.size() - 1; i >= 0; i--) {
             final TaskFragmentContainer container = mContainers.get(i);
             if (!includePin && isTaskFragmentContainerPinned(container)) {
                 continue;
             }
+            if (!includeOverlay && container.isOverlay()) {
+                continue;
+            }
             if (!container.isFinished()) {
                 return container;
             }
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
index 2ba5c9b320f1ea9857c02f5460e8c866a8ae980d..3e7f99b96421550d331857d1cf827d0a74093614 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -160,6 +160,9 @@ class TaskFragmentContainer {
      */
     private boolean mHasCrossProcessActivities;
 
+    /** Whether this TaskFragment enable isolated navigation. */
+    private boolean mIsIsolatedNavigationEnabled;
+
     /**
      * @see #TaskFragmentContainer(Activity, Intent, TaskContainer, SplitController,
      * TaskFragmentContainer, String)
@@ -805,6 +808,16 @@ class TaskFragmentContainer {
         mLastCompanionTaskFragment = fragmentToken;
     }
 
+    /** Returns whether to enable isolated navigation or not. */
+    boolean isIsolatedNavigationEnabled() {
+        return mIsIsolatedNavigationEnabled;
+    }
+
+    /** Sets whether to enable isolated navigation or not. */
+    void setIsolatedNavigationEnabled(boolean isolatedNavigationEnabled) {
+        mIsIsolatedNavigationEnabled = isolatedNavigationEnabled;
+    }
+
     /**
      * Adds the pending appeared activity that has requested to be launched in this task fragment.
      * @see android.app.ActivityClient#isRequestedToLaunchInTaskFragment
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java
index af8017ae9544a0b7785ff8ae86d36575bd025aac..405f0b2f51dc89f6a314dbe17eb10074c3485ef2 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java
@@ -21,6 +21,7 @@ import static android.view.Display.DEFAULT_DISPLAY;
 import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_BOUNDS;
 import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_ID;
 import static androidx.window.extensions.embedding.EmbeddingTestUtils.createMockTaskFragmentInfo;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.createSplitPairRuleBuilder;
 import static androidx.window.extensions.embedding.OverlayCreateParams.KEY_OVERLAY_CREATE_PARAMS;
 import static androidx.window.extensions.embedding.OverlayCreateParams.KEY_OVERLAY_CREATE_PARAMS_BOUNDS;
 import static androidx.window.extensions.embedding.OverlayCreateParams.KEY_OVERLAY_CREATE_PARAMS_TAG;
@@ -364,6 +365,54 @@ public class OverlayPresentationTest {
         assertThat(overlayContainer.getOverlayTag()).isEqualTo(TEST_OVERLAY_CREATE_PARAMS.getTag());
     }
 
+    @Test
+    public void testGetTopNonFishingTaskFragmentContainerWithOverlay() {
+        final TaskFragmentContainer overlayContainer =
+                createTestOverlayContainer(TASK_ID, "test1");
+
+        // Add a SplitPinContainer, the overlay should be on top
+        final Activity primaryActivity = createMockActivity();
+        final Activity secondaryActivity = createMockActivity();
+
+        final TaskFragmentContainer primaryContainer =
+                createMockTaskFragmentContainer(primaryActivity);
+        final TaskFragmentContainer secondaryContainer =
+                createMockTaskFragmentContainer(secondaryActivity);
+        final SplitPairRule splitPairRule = createSplitPairRuleBuilder(
+                activityActivityPair -> true /* activityPairPredicate */,
+                activityIntentPair -> true  /* activityIntentPairPredicate */,
+                parentWindowMetrics -> true /* parentWindowMetricsPredicate */).build();
+        mSplitController.registerSplit(mTransaction, primaryContainer, primaryActivity,
+                secondaryContainer, splitPairRule,  splitPairRule.getDefaultSplitAttributes());
+        SplitPinRule splitPinRule = new SplitPinRule.Builder(new SplitAttributes.Builder().build(),
+                parentWindowMetrics -> true /* parentWindowMetricsPredicate */).build();
+        mSplitController.pinTopActivityStack(TASK_ID, splitPinRule);
+        final TaskFragmentContainer topPinnedContainer = mSplitController.getTaskContainer(TASK_ID)
+                .getSplitPinContainer().getSecondaryContainer();
+
+        // Add a normal container after the overlay, the overlay should still on top,
+        // and the SplitPinContainer should also on top of the normal one.
+        final TaskFragmentContainer container = createMockTaskFragmentContainer(mActivity);
+
+        final TaskContainer taskContainer = mSplitController.getTaskContainer(TASK_ID);
+
+        assertThat(taskContainer.getTaskFragmentContainers())
+                .containsExactly(primaryContainer, container, secondaryContainer, overlayContainer)
+                .inOrder();
+
+        assertWithMessage("The pinned container must be returned excluding the overlay")
+                .that(taskContainer.getTopNonFinishingTaskFragmentContainer())
+                .isEqualTo(topPinnedContainer);
+
+        assertThat(taskContainer.getTopNonFinishingTaskFragmentContainer(false))
+                .isEqualTo(container);
+
+        assertWithMessage("The overlay container must be returned since it's always on top")
+                .that(taskContainer.getTopNonFinishingTaskFragmentContainer(
+                        false /* includePin */, true /* includeOverlay */))
+                .isEqualTo(overlayContainer);
+    }
+
     /**
      * A simplified version of {@link SplitController.ActivityStartMonitor
      * #createOrUpdateOverlayTaskFragmentIfNeeded}
@@ -375,6 +424,15 @@ public class OverlayPresentationTest {
                 taskId, mIntent, mActivity);
     }
 
+    /** Creates a mock TaskFragment that has been registered and appeared in the organizer. */
+    @NonNull
+    private TaskFragmentContainer createMockTaskFragmentContainer(@NonNull Activity activity) {
+        final TaskFragmentContainer container = mSplitController.newContainer(activity,
+                activity.getTaskId());
+        setupTaskFragmentInfo(container, activity);
+        return container;
+    }
+
     @NonNull
     private TaskFragmentContainer createTestOverlayContainer(int taskId, @NonNull String tag) {
         TaskFragmentContainer overlayContainer = mSplitController.newContainer(
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
index 6c0b3cf7971d5362d9c2e6ae2a151e8338dddbb3..96839c57d745e571c8a8dbf92fbf47b5153bd6ab 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
@@ -48,13 +48,12 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealM
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 
-import static com.google.common.truth.Truth.assertWithMessage;
-
 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.assertSame;
 import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
@@ -175,52 +174,6 @@ public class SplitControllerTest {
         mActivity = createMockActivity();
     }
 
-    @Test
-    public void testGetTopActiveContainer() {
-        final TaskContainer taskContainer = createTestTaskContainer();
-        // tf1 has no running activity so is not active.
-        final TaskFragmentContainer tf1 = new TaskFragmentContainer(null /* activity */,
-                new Intent(), taskContainer, mSplitController, null /* pairedPrimaryContainer */);
-        // tf2 has running activity so is active.
-        final TaskFragmentContainer tf2 = mock(TaskFragmentContainer.class);
-        doReturn(1).when(tf2).getRunningActivityCount();
-        taskContainer.addTaskFragmentContainer(tf2);
-        // tf3 is finished so is not active.
-        final TaskFragmentContainer tf3 = mock(TaskFragmentContainer.class);
-        doReturn(true).when(tf3).isFinished();
-        doReturn(false).when(tf3).isWaitingActivityAppear();
-        taskContainer.addTaskFragmentContainer(tf3);
-        mSplitController.mTaskContainers.put(TASK_ID, taskContainer);
-
-        assertWithMessage("Must return tf2 because tf3 is not active.")
-                .that(mSplitController.getTopActiveContainer(TASK_ID)).isEqualTo(tf2);
-
-        taskContainer.removeTaskFragmentContainer(tf3);
-
-        assertWithMessage("Must return tf2 because tf2 has running activity.")
-                .that(mSplitController.getTopActiveContainer(TASK_ID)).isEqualTo(tf2);
-
-        taskContainer.removeTaskFragmentContainer(tf2);
-
-        assertWithMessage("Must return tf because we are waiting for tf1 to appear.")
-                .that(mSplitController.getTopActiveContainer(TASK_ID)).isEqualTo(tf1);
-
-        final TaskFragmentInfo info = mock(TaskFragmentInfo.class);
-        doReturn(new ArrayList<>()).when(info).getActivities();
-        doReturn(true).when(info).isEmpty();
-        tf1.setInfo(mTransaction, info);
-
-        assertWithMessage("Must return tf because we are waiting for tf1 to become non-empty after"
-                + " creation.")
-                .that(mSplitController.getTopActiveContainer(TASK_ID)).isEqualTo(tf1);
-
-        doReturn(false).when(info).isEmpty();
-        tf1.setInfo(mTransaction, info);
-
-        assertWithMessage("Must return null because tf1 becomes empty.")
-                .that(mSplitController.getTopActiveContainer(TASK_ID)).isNull();
-    }
-
     @Test
     public void testOnTaskFragmentVanished() {
         final TaskFragmentContainer tf = mSplitController.newContainer(mActivity, TASK_ID);
@@ -306,7 +259,9 @@ public class SplitControllerTest {
 
         mSplitController.updateContainer(mTransaction, tf);
 
-        verify(mSplitController, never()).getTopActiveContainer(TASK_ID);
+        TaskContainer taskContainer = tf.getTaskContainer();
+        spyOn(taskContainer);
+        verify(taskContainer, never()).getTopNonFinishingTaskFragmentContainer();
 
         // Verify if tf is not in split, dismissPlaceholderIfNecessary won't be called.
         doReturn(false).when(mSplitController).shouldContainerBeExpanded(tf);
@@ -321,7 +276,7 @@ public class SplitControllerTest {
         doReturn(tf).when(splitContainer).getSecondaryContainer();
         doReturn(createTestTaskContainer()).when(splitContainer).getTaskContainer();
         doReturn(createSplitRule(mActivity, mActivity)).when(splitContainer).getSplitRule();
-        final TaskContainer taskContainer = mSplitController.getTaskContainer(TASK_ID);
+        taskContainer = mSplitController.getTaskContainer(TASK_ID);
         taskContainer.addSplitContainer(splitContainer);
         // Add a mock SplitContainer on top of splitContainer
         final SplitContainer splitContainer2 = mock(SplitContainer.class);
@@ -596,13 +551,12 @@ public class SplitControllerTest {
     }
 
     @Test
-    public void testResolveStartActivityIntent_skipIfPinned() {
+    public void testResolveStartActivityIntent_skipIfIsolatedNavEnabled() {
         final TaskFragmentContainer container = createMockTaskFragmentContainer(mActivity);
-        final TaskContainer taskContainer = container.getTaskContainer();
-        spyOn(taskContainer);
+        container.setIsolatedNavigationEnabled(true);
+
         final Intent intent = new Intent();
         setupSplitRule(mActivity, intent);
-        doReturn(true).when(taskContainer).isTaskFragmentContainerPinned(container);
         assertNull(mSplitController.resolveStartActivityIntent(mTransaction, TASK_ID, intent,
                 mActivity));
     }
@@ -1569,9 +1523,9 @@ public class SplitControllerTest {
         addSplitTaskFragments(primaryActivity, thirdActivity);
 
         // Ensure another SplitContainer is added and the pinned TaskFragment still on top
-        assertTrue(taskContainer.getSplitContainers().size() == splitContainerCount + +1);
-        assertTrue(mSplitController.getTopActiveContainer(TASK_ID).getTopNonFinishingActivity()
-                == secondaryActivity);
+        assertEquals(taskContainer.getSplitContainers().size(), splitContainerCount + +1);
+        assertSame(taskContainer.getTopNonFinishingTaskFragmentContainer()
+                .getTopNonFinishingActivity(), secondaryActivity);
     }
 
     /** Creates a mock activity in the organizer process. */
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index 187964947b946e5e11f12650f07a546532d803ce..fd4522e024388d251c0e63008153ce12b2e62bed 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -172,4 +172,5 @@ android_library {
     kotlincflags: ["-Xjvm-default=all"],
     manifest: "AndroidManifest.xml",
     plugins: ["dagger2-compiler"],
+    use_resource_processor: true,
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index 3790f04b56eb46de2b458d68cc8121160f2e0ab9..d08c573736d14967eb7191d194cacbbc8f406cb8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.back;
 
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_PREDICTIVE_BACK_HOME;
 import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW;
 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_BACK_ANIMATION;
@@ -70,7 +71,6 @@ import com.android.wm.shell.common.annotations.ShellMainThread;
 import com.android.wm.shell.sysui.ShellController;
 import com.android.wm.shell.sysui.ShellInit;
 
-
 import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
@@ -317,7 +317,11 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
             executeRemoteCallWithTaskPermission(mController, "setBackToLauncherCallback",
                     (controller) -> controller.registerAnimation(
                             BackNavigationInfo.TYPE_RETURN_TO_HOME,
-                            new BackAnimationRunner(callback, runner)));
+                            new BackAnimationRunner(
+                                    callback,
+                                    runner,
+                                    controller.mContext,
+                                    CUJ_PREDICTIVE_BACK_HOME)));
         }
 
         @Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationRunner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationRunner.java
index 431df212f0995067605fad0f359e0e46bf7288b3..dc413b059fd766905ffdf0073286368ed02ece40 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationRunner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationRunner.java
@@ -19,6 +19,7 @@ package com.android.wm.shell.back;
 import static android.view.WindowManager.TRANSIT_OLD_UNSET;
 
 import android.annotation.NonNull;
+import android.content.Context;
 import android.os.RemoteException;
 import android.util.Log;
 import android.view.IRemoteAnimationFinishedCallback;
@@ -27,16 +28,22 @@ import android.view.RemoteAnimationTarget;
 import android.window.IBackAnimationRunner;
 import android.window.IOnBackInvokedCallback;
 
+import com.android.internal.jank.InteractionJankMonitor;
+import com.android.wm.shell.common.InteractionJankMonitorUtils;
+
 /**
  * Used to register the animation callback and runner, it will trigger result if gesture was finish
  * before it received IBackAnimationRunner#onAnimationStart, so the controller could continue
  * trigger the real back behavior.
  */
 public class BackAnimationRunner {
+    private static final int NO_CUJ = -1;
     private static final String TAG = "ShellBackPreview";
 
     private final IOnBackInvokedCallback mCallback;
     private final IRemoteAnimationRunner mRunner;
+    private final @InteractionJankMonitor.CujType int mCujType;
+    private final Context mContext;
 
     // Whether we are waiting to receive onAnimationStart
     private boolean mWaitingAnimation;
@@ -45,9 +52,21 @@ public class BackAnimationRunner {
     private boolean mAnimationCancelled;
 
     public BackAnimationRunner(
-            @NonNull IOnBackInvokedCallback callback, @NonNull IRemoteAnimationRunner runner) {
+            @NonNull IOnBackInvokedCallback callback,
+            @NonNull IRemoteAnimationRunner runner,
+            @NonNull Context context,
+            @InteractionJankMonitor.CujType int cujType) {
         mCallback = callback;
         mRunner = runner;
+        mCujType = cujType;
+        mContext = context;
+    }
+
+    public BackAnimationRunner(
+            @NonNull IOnBackInvokedCallback callback,
+            @NonNull IRemoteAnimationRunner runner,
+            @NonNull Context context) {
+        this(callback, runner, context, NO_CUJ);
     }
 
     /** Returns the registered animation runner */
@@ -70,10 +89,17 @@ public class BackAnimationRunner {
                 new IRemoteAnimationFinishedCallback.Stub() {
                     @Override
                     public void onAnimationFinished() {
+                        if (shouldMonitorCUJ(apps)) {
+                            InteractionJankMonitorUtils.endTracing(mCujType);
+                        }
                         finishedCallback.run();
                     }
                 };
         mWaitingAnimation = false;
+        if (shouldMonitorCUJ(apps)) {
+            InteractionJankMonitorUtils.beginTracing(
+                    mCujType, mContext, apps[0].leash, /* tag */ null);
+        }
         try {
             getRunner().onAnimationStart(TRANSIT_OLD_UNSET, apps, wallpapers,
                     nonApps, callback);
@@ -82,6 +108,10 @@ public class BackAnimationRunner {
         }
     }
 
+    private boolean shouldMonitorCUJ(RemoteAnimationTarget[] apps) {
+        return apps.length > 0 && mCujType != NO_CUJ;
+    }
+
     void startGesture() {
         mWaitingAnimation = true;
         mAnimationCancelled = false;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityAnimation.java
index 114486e848f00a91d8c0c5fe3c6f5b41e43a07b6..24479d7b5f397818b30b8cae3aa87fda0b5cf9b3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityAnimation.java
@@ -19,6 +19,7 @@ package com.android.wm.shell.back;
 import static android.view.RemoteAnimationTarget.MODE_CLOSING;
 import static android.view.RemoteAnimationTarget.MODE_OPENING;
 
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY;
 import static com.android.wm.shell.back.BackAnimationConstants.PROGRESS_COMMIT_THRESHOLD;
 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW;
 
@@ -135,7 +136,8 @@ public class CrossActivityAnimation extends ShellBackAnimation {
     @Inject
     public CrossActivityAnimation(Context context, BackAnimationBackground background) {
         mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context);
-        mBackAnimationRunner = new BackAnimationRunner(new Callback(), new Runner());
+        mBackAnimationRunner = new BackAnimationRunner(
+                new Callback(), new Runner(), context, CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY);
         mBackground = background;
         mEnteringProgressSpring = new SpringAnimation(this, ENTER_PROGRESS_PROP);
         mEnteringProgressSpring.setSpring(new SpringForce()
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java
index 209d8533ee7d0c0e46081e0a4a487b1d5ed7b2bc..fc5ff017ebe58c678a5e5abecb7233ba96725db4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java
@@ -20,6 +20,7 @@ import static android.view.RemoteAnimationTarget.MODE_CLOSING;
 import static android.view.RemoteAnimationTarget.MODE_OPENING;
 import static android.window.BackEvent.EDGE_RIGHT;
 
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_PREDICTIVE_BACK_CROSS_TASK;
 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW;
 
 import android.animation.Animator;
@@ -108,6 +109,7 @@ public class CrossTaskBackAnimation extends ShellBackAnimation {
     private final float[] mTmpTranslate = {0, 0, 0};
     private final BackAnimationRunner mBackAnimationRunner;
     private final BackAnimationBackground mBackground;
+    private final Context mContext;
     private RemoteAnimationTarget mEnteringTarget;
     private RemoteAnimationTarget mClosingTarget;
     private SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
@@ -120,8 +122,10 @@ public class CrossTaskBackAnimation extends ShellBackAnimation {
 
     @Inject
     public CrossTaskBackAnimation(Context context, BackAnimationBackground background) {
+        mContext = context;
         mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context);
-        mBackAnimationRunner = new BackAnimationRunner(new Callback(), new Runner());
+        mBackAnimationRunner = new BackAnimationRunner(
+                new Callback(), new Runner(), context, CUJ_PREDICTIVE_BACK_CROSS_TASK);
         mBackground = background;
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomizeActivityAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomizeActivityAnimation.java
index aca638c1a5cf089b5baa8e70c9f7a38758597204..5254ff4661233f9dc734507556c3e0c411cee014 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomizeActivityAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomizeActivityAnimation.java
@@ -19,6 +19,7 @@ package com.android.wm.shell.back;
 import static android.view.RemoteAnimationTarget.MODE_CLOSING;
 import static android.view.RemoteAnimationTarget.MODE_OPENING;
 
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY;
 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW;
 
 import android.animation.Animator;
@@ -97,7 +98,8 @@ public class CustomizeActivityAnimation extends ShellBackAnimation {
             SurfaceControl.Transaction transaction, Choreographer choreographer) {
         mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context);
         mBackground = background;
-        mBackAnimationRunner = new BackAnimationRunner(new Callback(), new Runner());
+        mBackAnimationRunner = new BackAnimationRunner(
+                new Callback(), new Runner(), context, CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY);
         mCustomAnimationLoader = new CustomAnimationLoader(context);
 
         mProgressSpring = new SpringAnimation(this, ENTER_PROGRESS_PROP);
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 dddcbd4c96c03b3c1961cd53842946217633c476..f0da35df39eed73e5b3c990ebccc84a3eff78449 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
@@ -317,7 +317,8 @@ public class BubbleController implements ConfigurationChangeListener,
         mBubbleIconFactory = new BubbleIconFactory(context,
                 context.getResources().getDimensionPixelSize(R.dimen.bubble_size),
                 context.getResources().getDimensionPixelSize(R.dimen.bubble_badge_size),
-                context.getResources().getColor(R.color.important_conversation),
+                context.getResources().getColor(
+                        com.android.launcher3.icons.R.color.important_conversation),
                 context.getResources().getDimensionPixelSize(
                         com.android.internal.R.dimen.importance_ring_stroke_width));
         mDisplayController = displayController;
@@ -949,7 +950,8 @@ public class BubbleController implements ConfigurationChangeListener,
         mBubbleIconFactory = new BubbleIconFactory(mContext,
                 mContext.getResources().getDimensionPixelSize(R.dimen.bubble_size),
                 mContext.getResources().getDimensionPixelSize(R.dimen.bubble_badge_size),
-                mContext.getResources().getColor(R.color.important_conversation),
+                mContext.getResources().getColor(
+                        com.android.launcher3.icons.R.color.important_conversation),
                 mContext.getResources().getDimensionPixelSize(
                         com.android.internal.R.dimen.importance_ring_stroke_width));
 
@@ -988,7 +990,8 @@ public class BubbleController implements ConfigurationChangeListener,
                 mBubbleIconFactory = new BubbleIconFactory(mContext,
                         mContext.getResources().getDimensionPixelSize(R.dimen.bubble_size),
                         mContext.getResources().getDimensionPixelSize(R.dimen.bubble_badge_size),
-                        mContext.getResources().getColor(R.color.important_conversation),
+                        mContext.getResources().getColor(
+                                com.android.launcher3.icons.R.color.important_conversation),
                         mContext.getResources().getDimensionPixelSize(
                                 com.android.internal.R.dimen.importance_ring_stroke_width));
                 mStackView.onDisplaySizeChanged();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
index dc099d9abda4e5f1bc93cc8a30aa50aed53bc134..22e836aacfc593c6449115786bf5248cd7e41f12 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
@@ -113,7 +113,7 @@ class BubbleOverflow(private val context: Context, private val positioner: Bubbl
                 context,
                 res.getDimensionPixelSize(R.dimen.bubble_size),
                 res.getDimensionPixelSize(R.dimen.bubble_badge_size),
-                res.getColor(R.color.important_conversation),
+                res.getColor(com.android.launcher3.icons.R.color.important_conversation),
                 res.getDimensionPixelSize(com.android.internal.R.dimen.importance_ring_stroke_width)
             )
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index e7d0f601ff5ae6cf08b72e6f5939a725f6fd8594..d6141cfd21baf1c08750129a550c826349e6b0f9 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -568,8 +568,12 @@ public class BackAnimationControllerTest extends ShellTestCase {
     }
 
     private void registerAnimation(int type) {
-        mController.registerAnimation(type,
-                new BackAnimationRunner(mAnimatorCallback, mBackAnimationRunner));
+        mController.registerAnimation(
+                type,
+                new BackAnimationRunner(
+                        mAnimatorCallback,
+                        mBackAnimationRunner,
+                        mContext));
     }
 
     private void unregisterAnimation(int type) {
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 14602ef926d3495468f66817e0df0630a45e2ae3..7fac0c9776ace22c24cf50982121d1040fff954f 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -562,7 +562,11 @@ Frame CanvasContext::getFrame() {
 void CanvasContext::draw(bool solelyTextureViewUpdates) {
     if (auto grContext = getGrContext()) {
         if (grContext->abandoned()) {
-            LOG_ALWAYS_FATAL("GrContext is abandoned/device lost at start of CanvasContext::draw");
+            if (grContext->isDeviceLost()) {
+                LOG_ALWAYS_FATAL("Lost GPU device unexpectedly");
+                return;
+            }
+            LOG_ALWAYS_FATAL("GrContext is abandoned at start of CanvasContext::draw");
             return;
         }
     }
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
index 9355517d8bf9dadec33cf7397c26727793e588cb..d35dcb54c36d96e1896ed09424a702dcdbd337b5 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
@@ -43,6 +43,9 @@ import org.json.JSONException
 import android.widget.inline.InlinePresentationSpec
 import androidx.autofill.inline.v1.InlineSuggestionUi
 import com.android.credentialmanager.GetFlowUtils
+import com.android.credentialmanager.getflow.CredentialEntryInfo
+import com.android.credentialmanager.getflow.ProviderDisplayInfo
+import com.android.credentialmanager.getflow.toProviderDisplayInfo
 import org.json.JSONObject
 import java.util.concurrent.Executors
 
@@ -114,10 +117,14 @@ class CredentialAutofillService : AutofillService() {
         val providerList = GetFlowUtils.toProviderList(
                 getCredResponse.candidateProviderDataList,
                 this@CredentialAutofillService)
+        if (providerList.isEmpty()) {
+            return null
+        }
         var totalEntryCount = 0
         providerList.forEach { provider ->
             totalEntryCount += provider.credentialEntryList.size
         }
+        val providerDisplayInfo: ProviderDisplayInfo = toProviderDisplayInfo(providerList)
         val inlineSuggestionsRequest = filLRequest.inlineSuggestionsRequest
         val inlineMaxSuggestedCount = inlineSuggestionsRequest?.maxSuggestionCount ?: 0
         val inlinePresentationSpecs = inlineSuggestionsRequest?.inlinePresentationSpecs
@@ -129,15 +136,30 @@ class CredentialAutofillService : AutofillService() {
         var i = 0
         val fillResponseBuilder = FillResponse.Builder()
         var emptyFillResponse = true
-        providerList.forEach {provider ->
-            // TODO(b/299321128): Before iterating the list, sort the list so that
-            //  the relevant entries don't get truncated
-            provider.credentialEntryList.forEach entryLoop@ {entry ->
-                val autofillId: AutofillId? = entry.fillInIntent?.getParcelableExtra(
-                        CredentialProviderService.EXTRA_AUTOFILL_ID,
-                        AutofillId::class.java)
-                val pendingIntent = entry.pendingIntent
+
+        providerDisplayInfo.sortedUserNameToCredentialEntryList.forEach usernameLoop@ {
+            val primaryEntry = it.sortedCredentialEntryList.first()
+            // In regular CredMan bottomsheet, only one primary entry per username is displayed.
+            // But since the credential requests from different fields are allocated into a single
+            // request for autofill, there will be duplicate primary entries, especially for
+            // username/pw autofill fields. These primary entries will be the same entries except
+            // their autofillIds will point to different autofill fields. Process all primary
+            // fields.
+            // TODO(b/307435163): Merge credential options
+            it.sortedCredentialEntryList.forEach entryLoop@ { credentialEntry ->
+                if (!isSameCredentialEntry(primaryEntry, credentialEntry)) {
+                    // Encountering different credential entry means all the duplicate primary
+                    // entries have been processed.
+                    return@usernameLoop
+                }
+                val autofillId: AutofillId? = credentialEntry
+                        .fillInIntent
+                        ?.getParcelableExtra(
+                                CredentialProviderService.EXTRA_AUTOFILL_ID,
+                                AutofillId::class.java)
+                val pendingIntent = credentialEntry.pendingIntent
                 if (autofillId == null || pendingIntent == null) {
+                    Log.e(TAG, "AutofillId or pendingIntent was missing from the entry.")
                     return@entryLoop
                 }
                 var inlinePresentation: InlinePresentation? = null
@@ -151,7 +173,7 @@ class CredentialAutofillService : AutofillService() {
                     }
                     val sliceBuilder = InlineSuggestionUi
                             .newContentBuilder(pendingIntent)
-                            .setTitle(entry.userName)
+                            .setTitle(credentialEntry.userName)
                     inlinePresentation = InlinePresentation(
                             sliceBuilder.build().slice, spec, /* pinned= */ false)
                 }
@@ -169,8 +191,8 @@ class CredentialAutofillService : AutofillService() {
                                         Field.Builder().setPresentations(
                                                 presentationBuilder.build())
                                                 .build())
-                                .setAuthentication(entry.pendingIntent.intentSender)
-                                .setAuthenticationExtras(entry.fillInIntent.extras)
+                                .setAuthentication(pendingIntent.intentSender)
+                                .setAuthenticationExtras(credentialEntry.fillInIntent.extras)
                                 .build())
                 emptyFillResponse = false
             }
@@ -292,4 +314,15 @@ class CredentialAutofillService : AutofillService() {
         }
         return result
     }
+
+    private fun isSameCredentialEntry(
+            info1: CredentialEntryInfo,
+            info2: CredentialEntryInfo
+    ): Boolean {
+        return info1.providerId == info2.providerId &&
+                info1.lastUsedTimeMillis == info2.lastUsedTimeMillis &&
+                info1.credentialType == info2.credentialType &&
+                info1.displayName == info2.displayName &&
+                info1.userName == info2.userName
+    }
 }
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
index 716f47450ae9b38370d1e467ca527e2d2963bf00..447a9d2aaa8daf58fb17205c63cf5d7ce8f93f98 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
@@ -203,9 +203,14 @@ enum class GetScreenState {
     UNLOCKED_AUTH_ENTRIES_ONLY,
 }
 
-// IMPORTANT: new invocation should be mindful that this method will throw if more than 1 remote
-// entry exists
-private fun toProviderDisplayInfo(
+
+/**
+ * IMPORTANT: new invocation should be mindful that this method will throw if more than 1 remote
+ * entry exists
+ *
+ * @hide
+ */
+fun toProviderDisplayInfo(
     providerInfoList: List<ProviderInfo>
 ): ProviderDisplayInfo {
     val userNameToCredentialEntryMap = mutableMapOf<String, MutableList<CredentialEntryInfo>>()
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/style_preference.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/style_preference.xml
index f1e028b405db1e371a01db4c90593fbc0924e02f..6979825c9a206452cb086aac63259305d216b417 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/style_preference.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/style_preference.xml
@@ -25,6 +25,7 @@
         <item name="editTextPreferenceStyle">@style/SettingsEditTextPreference.SettingsLib</item>
         <item name="dropdownPreferenceStyle">@style/SettingsDropdownPreference.SettingsLib</item>
         <item name="switchPreferenceStyle">@style/SettingsSwitchPreference.SettingsLib</item>
+        <item name="switchPreferenceCompatStyle">@style/SettingsSwitchPreferenceCompat.SettingsLib</item>
         <item name="seekBarPreferenceStyle">@style/SettingsSeekbarPreference.SettingsLib</item>
         <item name="footerPreferenceStyle">@style/Preference.Material</item>
     </style>
@@ -67,6 +68,11 @@
         <item name="iconSpaceReserved">@bool/settingslib_config_icon_space_reserved</item>
     </style>
 
+    <style name="SettingsSwitchPreferenceCompat.SettingsLib" parent="@style/Preference.SwitchPreferenceCompat.Material">
+        <item name="layout">@layout/settingslib_preference</item>
+        <item name="iconSpaceReserved">@bool/settingslib_config_icon_space_reserved</item>
+    </style>
+
     <style name="SettingsSeekbarPreference.SettingsLib" parent="@style/Preference.SeekBarPreference.Material">
         <item name="iconSpaceReserved">@bool/settingslib_config_icon_space_reserved</item>
     </style>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
index c4b6047e14feb084b98c73023df988f216d05585..f44b16104f9942696f6f6d836454ec8ab6faf5b0 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
@@ -34,12 +34,17 @@
     </style>
 
     <style name="Switch.SettingsLib" parent="@android:style/Widget.Material.CompoundButton.Switch">
-        <item name="android:switchMinWidth">52dp</item>
         <item name="android:minHeight">@dimen/settingslib_preferred_minimum_touch_target</item>
         <item name="android:track">@drawable/settingslib_switch_track</item>
         <item name="android:thumb">@drawable/settingslib_switch_thumb</item>
     </style>
 
+    <style name="SwitchCompat.SettingsLib" parent="@style/Widget.AppCompat.CompoundButton.Switch">
+        <item name="android:minHeight">@dimen/settingslib_preferred_minimum_touch_target</item>
+        <item name="track">@drawable/settingslib_switch_track</item>
+        <item name="android:thumb">@drawable/settingslib_switch_thumb</item>
+    </style>
+
     <style name="HorizontalProgressBar.SettingsLib"
            parent="android:style/Widget.Material.ProgressBar.Horizontal">
         <item name="android:progressDrawable">@drawable/settingslib_progress_horizontal</item>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml
index 69c122c9992e99d24d88745b0d1ca8c18930e8e1..698f21d8d8a6f9ec12683107def46446c197f452 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml
@@ -25,6 +25,7 @@
         <item name="android:listPreferredItemPaddingRight">16dp</item>
         <item name="preferenceTheme">@style/PreferenceTheme.SettingsLib</item>
         <item name="android:switchStyle">@style/Switch.SettingsLib</item>
+        <item name="switchStyle">@style/SwitchCompat.SettingsLib</item>
         <item name="android:progressBarStyleHorizontal">@style/HorizontalProgressBar.SettingsLib</item>
     </style>
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/SettingsJankMonitor.kt b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/SettingsJankMonitor.kt
index a5f69ffec4b422c60cb70dbb2c45a634c25cb032..02d76304f077ab95bc10a42173a919b173709680 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/SettingsJankMonitor.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/SettingsJankMonitor.kt
@@ -18,7 +18,7 @@ package com.android.settingslib.core.instrumentation
 import android.view.View
 import androidx.annotation.VisibleForTesting
 import androidx.preference.PreferenceGroupAdapter
-import androidx.preference.SwitchPreference
+import androidx.preference.TwoStatePreference
 import androidx.recyclerview.widget.RecyclerView
 import com.android.internal.jank.InteractionJankMonitor
 import java.util.concurrent.Executors
@@ -43,7 +43,10 @@ object SettingsJankMonitor {
      * @param preference the clicked preference
      */
     @JvmStatic
-    fun detectSwitchPreferenceClickJank(recyclerView: RecyclerView, preference: SwitchPreference) {
+    fun detectSwitchPreferenceClickJank(
+        recyclerView: RecyclerView,
+        preference: TwoStatePreference,
+    ) {
         val adapter = recyclerView.adapter as? PreferenceGroupAdapter ?: return
         val adapterPosition = adapter.getPreferenceAdapterPosition(preference)
         val viewHolder = recyclerView.findViewHolderForAdapterPosition(adapterPosition) ?: return
diff --git a/packages/SettingsProvider/Android.bp b/packages/SettingsProvider/Android.bp
index f4ca260d4d8918139477d371411e010b3c22b43b..a4a9290b16abc95862bce21bb38324e5a97e46fd 100644
--- a/packages/SettingsProvider/Android.bp
+++ b/packages/SettingsProvider/Android.bp
@@ -17,9 +17,10 @@ license {
     ],
 }
 
-android_app {
-    name: "SettingsProvider",
+android_library {
+    name: "SettingsProviderLib",
     defaults: ["platform_app_defaults"],
+    manifest: "AndroidManifestLib.xml",
     resource_dirs: ["res"],
     srcs: [
         "src/**/*.java",
@@ -32,38 +33,37 @@ android_app {
     ],
     static_libs: [
         "device_config_service_flags_java",
-        "junit",
         "SettingsLibDeviceStateRotationLock",
         "SettingsLibDisplayUtils",
     ],
     platform_apis: true,
+}
+
+android_app {
+    name: "SettingsProvider",
+    defaults: ["platform_app_defaults"],
+    resource_dirs: [],
+    static_libs: ["SettingsProviderLib"],
+    platform_apis: true,
     certificate: "platform",
     privileged: true,
 }
 
 android_test {
     name: "SettingsProviderTest",
-    // Note we statically link several classes to do some unit tests.  It's not accessible otherwise
-    // because this test is not an instrumentation test. (because the target runs in the system process.)
     srcs: [
         "test/**/*.java",
-        "src/android/provider/settings/backup/*",
-        "src/android/provider/settings/validators/*",
-        "src/com/android/providers/settings/GenerationRegistry.java",
-        "src/com/android/providers/settings/SettingsBackupAgent.java",
-        "src/com/android/providers/settings/SettingsState.java",
-        "src/com/android/providers/settings/SettingsHelper.java",
-        "src/com/android/providers/settings/WifiSoftApConfigChangedNotifier.java",
     ],
     static_libs: [
+        // Note we statically link SettingsProviderLib to do some unit tests.  It's not accessible otherwise
+        // because this test is not an instrumentation test. (because the target runs in the system process.)
+        "SettingsProviderLib",
+
         "androidx.test.rules",
-        "device_config_service_flags_java",
         "flag-junit",
+        "junit",
         "mockito-target-minus-junit4",
         "platform-test-annotations",
-        "SettingsLibDeviceStateRotationLock",
-        "SettingsLibDisplayUtils",
-        "platform-test-annotations",
         "truth",
     ],
     libs: [
@@ -71,12 +71,7 @@ android_test {
         "android.test.mock",
         "unsupportedappusage",
     ],
-    resource_dirs: ["res"],
-    aaptflags: [
-        "--auto-add-overlay",
-        "--extra-packages",
-        "com.android.providers.settings",
-    ],
+    resource_dirs: [],
     platform_apis: true,
     certificate: "platform",
     test_suites: ["device-tests"],
diff --git a/packages/SettingsProvider/AndroidManifestLib.xml b/packages/SettingsProvider/AndroidManifestLib.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a20b539e2c10f280a5695201694b220fcd286856
--- /dev/null
+++ b/packages/SettingsProvider/AndroidManifestLib.xml
@@ -0,0 +1,2 @@
+<manifest package="com.android.providers.settings">
+</manifest>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 95d7039859b56657a8fac72d402c756dc4286a18..4e2fad0bece22753c3bb7fc4e912d9055ec4e282 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -40,6 +40,7 @@ import static com.android.providers.settings.SettingsState.getUserIdFromKey;
 import static com.android.providers.settings.SettingsState.isConfigSettingsKey;
 import static com.android.providers.settings.SettingsState.isGlobalSettingsKey;
 import static com.android.providers.settings.SettingsState.isSecureSettingsKey;
+import static com.android.providers.settings.SettingsState.isSsaidSettingsKey;
 import static com.android.providers.settings.SettingsState.isSystemSettingsKey;
 import static com.android.providers.settings.SettingsState.makeKey;
 
@@ -411,9 +412,6 @@ public class SettingsProvider extends ContentProvider {
         SettingsState.cacheSystemPackageNamesAndSystemSignature(getContext());
         synchronized (mLock) {
             mSettingsRegistry.migrateAllLegacySettingsIfNeededLocked();
-            for (UserInfo user : mUserManager.getAliveUsers()) {
-                mSettingsRegistry.ensureSettingsForUserLocked(user.id);
-            }
             mSettingsRegistry.syncSsaidTableOnStartLocked();
         }
         mHandler.post(() -> {
@@ -429,53 +427,65 @@ public class SettingsProvider extends ContentProvider {
     public Bundle call(String method, String name, Bundle args) {
         final int requestingUserId = getRequestingUserId(args);
         switch (method) {
-            case Settings.CALL_METHOD_GET_CONFIG -> {
+            case Settings.CALL_METHOD_GET_CONFIG: {
                 Setting setting = getConfigSetting(name);
                 return packageValueForCallResult(SETTINGS_TYPE_CONFIG, name, requestingUserId,
                         setting, isTrackingGeneration(args));
             }
-            case Settings.CALL_METHOD_GET_GLOBAL -> {
+
+            case Settings.CALL_METHOD_GET_GLOBAL: {
                 Setting setting = getGlobalSetting(name);
                 return packageValueForCallResult(SETTINGS_TYPE_GLOBAL, name, requestingUserId,
                         setting, isTrackingGeneration(args));
             }
-            case Settings.CALL_METHOD_GET_SECURE -> {
+
+            case Settings.CALL_METHOD_GET_SECURE: {
                 Setting setting = getSecureSetting(name, requestingUserId);
                 return packageValueForCallResult(SETTINGS_TYPE_SECURE, name, requestingUserId,
                         setting, isTrackingGeneration(args));
             }
-            case Settings.CALL_METHOD_GET_SYSTEM -> {
+
+            case Settings.CALL_METHOD_GET_SYSTEM: {
                 Setting setting = getSystemSetting(name, requestingUserId);
                 return packageValueForCallResult(SETTINGS_TYPE_SYSTEM, name, requestingUserId,
                         setting, isTrackingGeneration(args));
             }
-            case Settings.CALL_METHOD_PUT_CONFIG -> {
+
+            case Settings.CALL_METHOD_PUT_CONFIG: {
                 String value = getSettingValue(args);
                 final boolean makeDefault = getSettingMakeDefault(args);
                 insertConfigSetting(name, value, makeDefault);
+                break;
             }
-            case Settings.CALL_METHOD_PUT_GLOBAL -> {
+
+            case Settings.CALL_METHOD_PUT_GLOBAL: {
                 String value = getSettingValue(args);
                 String tag = getSettingTag(args);
                 final boolean makeDefault = getSettingMakeDefault(args);
                 final boolean overrideableByRestore = getSettingOverrideableByRestore(args);
                 insertGlobalSetting(name, value, tag, makeDefault, requestingUserId, false,
                         overrideableByRestore);
+                break;
             }
-            case Settings.CALL_METHOD_PUT_SECURE -> {
+
+            case Settings.CALL_METHOD_PUT_SECURE: {
                 String value = getSettingValue(args);
                 String tag = getSettingTag(args);
                 final boolean makeDefault = getSettingMakeDefault(args);
                 final boolean overrideableByRestore = getSettingOverrideableByRestore(args);
                 insertSecureSetting(name, value, tag, makeDefault, requestingUserId, false,
                         overrideableByRestore);
+                break;
             }
-            case Settings.CALL_METHOD_PUT_SYSTEM -> {
+
+            case Settings.CALL_METHOD_PUT_SYSTEM: {
                 String value = getSettingValue(args);
                 boolean overrideableByRestore = getSettingOverrideableByRestore(args);
                 insertSystemSetting(name, value, requestingUserId, overrideableByRestore);
+                break;
             }
-            case Settings.CALL_METHOD_SET_ALL_CONFIG -> {
+
+            case Settings.CALL_METHOD_SET_ALL_CONFIG: {
                 String prefix = getSettingPrefix(args);
                 Map<String, String> flags = getSettingFlags(args);
                 Bundle result = new Bundle();
@@ -483,96 +493,120 @@ public class SettingsProvider extends ContentProvider {
                         setAllConfigSettings(prefix, flags));
                 return result;
             }
-            case Settings.CALL_METHOD_SET_SYNC_DISABLED_MODE_CONFIG -> {
+
+            case Settings.CALL_METHOD_SET_SYNC_DISABLED_MODE_CONFIG: {
                 final int mode = getSyncDisabledMode(args);
                 setSyncDisabledModeConfig(mode);
+                break;
             }
-            case Settings.CALL_METHOD_GET_SYNC_DISABLED_MODE_CONFIG -> {
+
+            case Settings.CALL_METHOD_GET_SYNC_DISABLED_MODE_CONFIG: {
                 Bundle result = new Bundle();
                 result.putInt(Settings.KEY_CONFIG_GET_SYNC_DISABLED_MODE_RETURN,
                         getSyncDisabledModeConfig());
                 return result;
             }
-            case Settings.CALL_METHOD_RESET_CONFIG -> {
+
+            case Settings.CALL_METHOD_RESET_CONFIG: {
                 final int mode = getResetModeEnforcingPermission(args);
                 String prefix = getSettingPrefix(args);
                 resetConfigSetting(mode, prefix);
+                break;
             }
-            case Settings.CALL_METHOD_RESET_GLOBAL -> {
+
+            case Settings.CALL_METHOD_RESET_GLOBAL: {
                 final int mode = getResetModeEnforcingPermission(args);
                 String tag = getSettingTag(args);
                 resetGlobalSetting(requestingUserId, mode, tag);
+                break;
             }
-            case Settings.CALL_METHOD_RESET_SECURE -> {
+
+            case Settings.CALL_METHOD_RESET_SECURE: {
                 final int mode = getResetModeEnforcingPermission(args);
                 String tag = getSettingTag(args);
                 resetSecureSetting(requestingUserId, mode, tag);
+                break;
             }
-            case Settings.CALL_METHOD_RESET_SYSTEM -> {
+
+            case Settings.CALL_METHOD_RESET_SYSTEM: {
                 final int mode = getResetModeEnforcingPermission(args);
                 String tag = getSettingTag(args);
                 resetSystemSetting(requestingUserId, mode, tag);
+                break;
             }
-            case Settings.CALL_METHOD_DELETE_CONFIG -> {
-                int rows = deleteConfigSetting(name) ? 1 : 0;
+
+            case Settings.CALL_METHOD_DELETE_CONFIG: {
+                int rows  = deleteConfigSetting(name) ? 1 : 0;
                 Bundle result = new Bundle();
                 result.putInt(RESULT_ROWS_DELETED, rows);
                 return result;
             }
-            case Settings.CALL_METHOD_DELETE_GLOBAL -> {
+
+            case Settings.CALL_METHOD_DELETE_GLOBAL: {
                 int rows = deleteGlobalSetting(name, requestingUserId, false) ? 1 : 0;
                 Bundle result = new Bundle();
                 result.putInt(RESULT_ROWS_DELETED, rows);
                 return result;
             }
-            case Settings.CALL_METHOD_DELETE_SECURE -> {
+
+            case Settings.CALL_METHOD_DELETE_SECURE: {
                 int rows = deleteSecureSetting(name, requestingUserId, false) ? 1 : 0;
                 Bundle result = new Bundle();
                 result.putInt(RESULT_ROWS_DELETED, rows);
                 return result;
             }
-            case Settings.CALL_METHOD_DELETE_SYSTEM -> {
+
+            case Settings.CALL_METHOD_DELETE_SYSTEM: {
                 int rows = deleteSystemSetting(name, requestingUserId) ? 1 : 0;
                 Bundle result = new Bundle();
                 result.putInt(RESULT_ROWS_DELETED, rows);
                 return result;
             }
-            case Settings.CALL_METHOD_LIST_CONFIG -> {
+
+            case Settings.CALL_METHOD_LIST_CONFIG: {
                 String prefix = getSettingPrefix(args);
                 Bundle result = packageValuesForCallResult(prefix, getAllConfigFlags(prefix),
                         isTrackingGeneration(args));
                 reportDeviceConfigAccess(prefix);
                 return result;
             }
-            case Settings.CALL_METHOD_REGISTER_MONITOR_CALLBACK_CONFIG -> {
+
+            case Settings.CALL_METHOD_REGISTER_MONITOR_CALLBACK_CONFIG: {
                 RemoteCallback callback = args.getParcelable(
                         Settings.CALL_METHOD_MONITOR_CALLBACK_KEY);
                 setMonitorCallback(callback);
+                break;
             }
-            case Settings.CALL_METHOD_UNREGISTER_MONITOR_CALLBACK_CONFIG -> {
+
+            case Settings.CALL_METHOD_UNREGISTER_MONITOR_CALLBACK_CONFIG: {
                 clearMonitorCallback();
+                break;
             }
-            case Settings.CALL_METHOD_LIST_GLOBAL -> {
+
+            case Settings.CALL_METHOD_LIST_GLOBAL: {
                 Bundle result = new Bundle();
                 result.putStringArrayList(RESULT_SETTINGS_LIST,
                         buildSettingsList(getAllGlobalSettings(null)));
                 return result;
             }
-            case Settings.CALL_METHOD_LIST_SECURE -> {
+
+            case Settings.CALL_METHOD_LIST_SECURE: {
                 Bundle result = new Bundle();
                 result.putStringArrayList(RESULT_SETTINGS_LIST,
                         buildSettingsList(getAllSecureSettings(requestingUserId, null)));
                 return result;
             }
-            case Settings.CALL_METHOD_LIST_SYSTEM -> {
+
+            case Settings.CALL_METHOD_LIST_SYSTEM: {
                 Bundle result = new Bundle();
                 result.putStringArrayList(RESULT_SETTINGS_LIST,
                         buildSettingsList(getAllSystemSettings(requestingUserId, null)));
                 return result;
             }
-            default -> {
+
+            default: {
                 Slog.w(LOG_TAG, "call() with invalid method: " + method);
-            }
+            } break;
         }
 
         return null;
@@ -604,7 +638,7 @@ public class SettingsProvider extends ContentProvider {
         }
 
         switch (args.table) {
-            case TABLE_GLOBAL -> {
+            case TABLE_GLOBAL: {
                 if (args.name != null) {
                     Setting setting = getGlobalSetting(args.name);
                     return packageSettingForQuery(setting, normalizedProjection);
@@ -612,7 +646,8 @@ public class SettingsProvider extends ContentProvider {
                     return getAllGlobalSettings(projection);
                 }
             }
-            case TABLE_SECURE -> {
+
+            case TABLE_SECURE: {
                 final int userId = UserHandle.getCallingUserId();
                 if (args.name != null) {
                     Setting setting = getSecureSetting(args.name, userId);
@@ -621,7 +656,8 @@ public class SettingsProvider extends ContentProvider {
                     return getAllSecureSettings(userId, projection);
                 }
             }
-            case TABLE_SYSTEM -> {
+
+            case TABLE_SYSTEM: {
                 final int userId = UserHandle.getCallingUserId();
                 if (args.name != null) {
                     Setting setting = getSystemSetting(args.name, userId);
@@ -630,7 +666,8 @@ public class SettingsProvider extends ContentProvider {
                     return getAllSystemSettings(userId, projection);
                 }
             }
-            default -> {
+
+            default: {
                 throw new IllegalArgumentException("Invalid Uri path:" + uri);
             }
         }
@@ -671,27 +708,30 @@ public class SettingsProvider extends ContentProvider {
         String value = values.getAsString(Settings.Secure.VALUE);
 
         switch (table) {
-            case TABLE_GLOBAL -> {
+            case TABLE_GLOBAL: {
                 if (insertGlobalSetting(name, value, null, false,
                         UserHandle.getCallingUserId(), false,
                         /* overrideableByRestore */ false)) {
-                    return Uri.withAppendedPath(Global.CONTENT_URI, name);
+                    return Uri.withAppendedPath(Settings.Global.CONTENT_URI, name);
                 }
-            }
-            case TABLE_SECURE -> {
+            } break;
+
+            case TABLE_SECURE: {
                 if (insertSecureSetting(name, value, null, false,
                         UserHandle.getCallingUserId(), false,
                         /* overrideableByRestore */ false)) {
-                    return Uri.withAppendedPath(Secure.CONTENT_URI, name);
+                    return Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name);
                 }
-            }
-            case TABLE_SYSTEM -> {
+            } break;
+
+            case TABLE_SYSTEM: {
                 if (insertSystemSetting(name, value, UserHandle.getCallingUserId(),
                         /* overridableByRestore */ false)) {
                     return Uri.withAppendedPath(Settings.System.CONTENT_URI, name);
                 }
-            }
-            default -> {
+            } break;
+
+            default: {
                 throw new IllegalArgumentException("Bad Uri path:" + uri);
             }
         }
@@ -735,19 +775,22 @@ public class SettingsProvider extends ContentProvider {
         }
 
         switch (args.table) {
-            case TABLE_GLOBAL -> {
+            case TABLE_GLOBAL: {
                 final int userId = UserHandle.getCallingUserId();
                 return deleteGlobalSetting(args.name, userId, false) ? 1 : 0;
             }
-            case TABLE_SECURE -> {
+
+            case TABLE_SECURE: {
                 final int userId = UserHandle.getCallingUserId();
                 return deleteSecureSetting(args.name, userId, false) ? 1 : 0;
             }
-            case TABLE_SYSTEM -> {
+
+            case TABLE_SYSTEM: {
                 final int userId = UserHandle.getCallingUserId();
                 return deleteSystemSetting(args.name, userId) ? 1 : 0;
             }
-            default -> {
+
+            default: {
                 throw new IllegalArgumentException("Bad Uri path:" + uri);
             }
         }
@@ -773,21 +816,24 @@ public class SettingsProvider extends ContentProvider {
         String value = values.getAsString(Settings.Secure.VALUE);
 
         switch (args.table) {
-            case TABLE_GLOBAL -> {
+            case TABLE_GLOBAL: {
                 final int userId = UserHandle.getCallingUserId();
                 return updateGlobalSetting(args.name, value, null, false,
                         userId, false) ? 1 : 0;
             }
-            case TABLE_SECURE -> {
+
+            case TABLE_SECURE: {
                 final int userId = UserHandle.getCallingUserId();
                 return updateSecureSetting(args.name, value, null, false,
                         userId, false) ? 1 : 0;
             }
-            case TABLE_SYSTEM -> {
+
+            case TABLE_SYSTEM: {
                 final int userId = UserHandle.getCallingUserId();
                 return updateSystemSetting(args.name, value, userId) ? 1 : 0;
             }
-            default -> {
+
+            default: {
                 throw new IllegalArgumentException("Invalid Uri path:" + uri);
             }
         }
@@ -988,38 +1034,27 @@ public class SettingsProvider extends ContentProvider {
 
     private void registerBroadcastReceivers() {
         IntentFilter userFilter = new IntentFilter();
-        userFilter.addAction(Intent.ACTION_USER_ADDED);
         userFilter.addAction(Intent.ACTION_USER_REMOVED);
         userFilter.addAction(Intent.ACTION_USER_STOPPED);
 
         getContext().registerReceiver(new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
-                if (intent.getAction() == null) {
-                    return;
-                }
                 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
-                        UserHandle.USER_NULL);
-                if (userId == UserHandle.USER_NULL) {
-                    return;
-                }
+                        UserHandle.USER_SYSTEM);
 
                 switch (intent.getAction()) {
-                    case Intent.ACTION_USER_ADDED -> {
-                        synchronized (mLock) {
-                            mSettingsRegistry.ensureSettingsForUserLocked(userId);
-                        }
-                    }
-                    case Intent.ACTION_USER_REMOVED -> {
+                    case Intent.ACTION_USER_REMOVED: {
                         synchronized (mLock) {
                             mSettingsRegistry.removeUserStateLocked(userId, true);
                         }
-                    }
-                    case Intent.ACTION_USER_STOPPED -> {
+                    } break;
+
+                    case Intent.ACTION_USER_STOPPED: {
                         synchronized (mLock) {
                             mSettingsRegistry.removeUserStateLocked(userId, false);
                         }
-                    }
+                    } break;
                 }
             }
         }, userFilter);
@@ -1315,24 +1350,26 @@ public class SettingsProvider extends ContentProvider {
         // Perform the mutation.
         synchronized (mLock) {
             switch (operation) {
-                case MUTATION_OPERATION_INSERT -> {
+                case MUTATION_OPERATION_INSERT: {
                     enforceDeviceConfigWritePermission(getContext(), Collections.singleton(name));
                     return mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_CONFIG,
                             UserHandle.USER_SYSTEM, name, value, null, makeDefault, true,
                             callingPackage, false, null,
                             /* overrideableByRestore */ false);
                 }
-                case MUTATION_OPERATION_DELETE -> {
+
+                case MUTATION_OPERATION_DELETE: {
                     enforceDeviceConfigWritePermission(getContext(), Collections.singleton(name));
                     return mSettingsRegistry.deleteSettingLocked(SETTINGS_TYPE_CONFIG,
                             UserHandle.USER_SYSTEM, name, false, null);
                 }
-                case MUTATION_OPERATION_RESET -> {
+
+                case MUTATION_OPERATION_RESET: {
                     enforceDeviceConfigWritePermission(getContext(),
                             getAllConfigFlags(prefix).keySet());
-                    return mSettingsRegistry.resetSettingsLocked(SETTINGS_TYPE_CONFIG,
+                    mSettingsRegistry.resetSettingsLocked(SETTINGS_TYPE_CONFIG,
                             UserHandle.USER_SYSTEM, callingPackage, mode, null, prefix);
-                }
+                } return true;
             }
         }
 
@@ -1486,7 +1523,7 @@ public class SettingsProvider extends ContentProvider {
         enforceHasAtLeastOnePermission(Manifest.permission.WRITE_SECURE_SETTINGS);
 
         // Resolve the userId on whose behalf the call is made.
-        final int callingUserId = resolveCallingUserIdEnforcingPermissions(requestingUserId);
+        final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);
 
         // If this is a setting that is currently restricted for this user, do not allow
         // unrestricting changes.
@@ -1499,25 +1536,28 @@ public class SettingsProvider extends ContentProvider {
         // Perform the mutation.
         synchronized (mLock) {
             switch (operation) {
-                case MUTATION_OPERATION_INSERT -> {
+                case MUTATION_OPERATION_INSERT: {
                     return mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_GLOBAL,
                             UserHandle.USER_SYSTEM, name, value, tag, makeDefault,
                             callingPackage, forceNotify,
                             CRITICAL_GLOBAL_SETTINGS, overrideableByRestore);
                 }
-                case MUTATION_OPERATION_DELETE -> {
+
+                case MUTATION_OPERATION_DELETE: {
                     return mSettingsRegistry.deleteSettingLocked(SETTINGS_TYPE_GLOBAL,
                             UserHandle.USER_SYSTEM, name, forceNotify, CRITICAL_GLOBAL_SETTINGS);
                 }
-                case MUTATION_OPERATION_UPDATE -> {
+
+                case MUTATION_OPERATION_UPDATE: {
                     return mSettingsRegistry.updateSettingLocked(SETTINGS_TYPE_GLOBAL,
                             UserHandle.USER_SYSTEM, name, value, tag, makeDefault,
                             callingPackage, forceNotify, CRITICAL_GLOBAL_SETTINGS);
                 }
-                case MUTATION_OPERATION_RESET -> {
-                    return mSettingsRegistry.resetSettingsLocked(SETTINGS_TYPE_GLOBAL,
+
+                case MUTATION_OPERATION_RESET: {
+                    mSettingsRegistry.resetSettingsLocked(SETTINGS_TYPE_GLOBAL,
                             UserHandle.USER_SYSTEM, callingPackage, mode, tag);
-                }
+                } return true;
             }
         }
 
@@ -1540,12 +1580,12 @@ public class SettingsProvider extends ContentProvider {
         }
 
         // Resolve the userId on whose behalf the call is made.
-        final int callingUserId = resolveCallingUserIdEnforcingPermissions(userId);
+        final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(userId);
 
         // The relevant "calling package" userId will be the owning userId for some
         // profiles, and we can't do the lookup inside our [lock held] loop, so work out
         // up front who the effective "new SSAID" user ID for that settings name will be.
-        final int ssaidUserId = resolveOwningUserIdForSecureSetting(callingUserId,
+        final int ssaidUserId = resolveOwningUserIdForSecureSettingLocked(callingUserId,
                 Settings.Secure.ANDROID_ID);
         final PackageInfo ssaidCallingPkg = getCallingPackageInfo(ssaidUserId);
 
@@ -1560,7 +1600,7 @@ public class SettingsProvider extends ContentProvider {
             for (int i = 0; i < nameCount; i++) {
                 String name = names.get(i);
                 // Determine the owning user as some profile settings are cloned from the parent.
-                final int owningUserId = resolveOwningUserIdForSecureSetting(callingUserId,
+                final int owningUserId = resolveOwningUserIdForSecureSettingLocked(callingUserId,
                         name);
 
                 if (!isSecureSettingAccessible(name)) {
@@ -1598,13 +1638,13 @@ public class SettingsProvider extends ContentProvider {
         }
 
         // Resolve the userId on whose behalf the call is made.
-        final int callingUserId = resolveCallingUserIdEnforcingPermissions(requestingUserId);
+        final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);
 
         // Ensure the caller can access the setting.
         enforceSettingReadable(name, SETTINGS_TYPE_SECURE, UserHandle.getCallingUserId());
 
         // Determine the owning user as some profile settings are cloned from the parent.
-        final int owningUserId = resolveOwningUserIdForSecureSetting(callingUserId, name);
+        final int owningUserId = resolveOwningUserIdForSecureSettingLocked(callingUserId, name);
 
         if (!isSecureSettingAccessible(name)) {
             // This caller is not permitted to access this setting. Pretend the setting doesn't
@@ -1771,7 +1811,7 @@ public class SettingsProvider extends ContentProvider {
         enforceHasAtLeastOnePermission(Manifest.permission.WRITE_SECURE_SETTINGS);
 
         // Resolve the userId on whose behalf the call is made.
-        final int callingUserId = resolveCallingUserIdEnforcingPermissions(requestingUserId);
+        final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);
 
         // If this is a setting that is currently restricted for this user, do not allow
         // unrestricting changes.
@@ -1780,7 +1820,7 @@ public class SettingsProvider extends ContentProvider {
         }
 
         // Determine the owning user as some profile settings are cloned from the parent.
-        final int owningUserId = resolveOwningUserIdForSecureSetting(callingUserId, name);
+        final int owningUserId = resolveOwningUserIdForSecureSettingLocked(callingUserId, name);
 
         // Only the owning user can change the setting.
         if (owningUserId != callingUserId) {
@@ -1792,25 +1832,28 @@ public class SettingsProvider extends ContentProvider {
         // Mutate the value.
         synchronized (mLock) {
             switch (operation) {
-                case MUTATION_OPERATION_INSERT -> {
+                case MUTATION_OPERATION_INSERT: {
                     return mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_SECURE,
                             owningUserId, name, value, tag, makeDefault,
                             callingPackage, forceNotify, CRITICAL_SECURE_SETTINGS,
                             overrideableByRestore);
                 }
-                case MUTATION_OPERATION_DELETE -> {
+
+                case MUTATION_OPERATION_DELETE: {
                     return mSettingsRegistry.deleteSettingLocked(SETTINGS_TYPE_SECURE,
                             owningUserId, name, forceNotify, CRITICAL_SECURE_SETTINGS);
                 }
-                case MUTATION_OPERATION_UPDATE -> {
+
+                case MUTATION_OPERATION_UPDATE: {
                     return mSettingsRegistry.updateSettingLocked(SETTINGS_TYPE_SECURE,
                             owningUserId, name, value, tag, makeDefault,
                             callingPackage, forceNotify, CRITICAL_SECURE_SETTINGS);
                 }
-                case MUTATION_OPERATION_RESET -> {
-                    return mSettingsRegistry.resetSettingsLocked(SETTINGS_TYPE_SECURE,
+
+                case MUTATION_OPERATION_RESET: {
+                    mSettingsRegistry.resetSettingsLocked(SETTINGS_TYPE_SECURE,
                             UserHandle.USER_SYSTEM, callingPackage, mode, tag);
-                }
+                } return true;
             }
         }
 
@@ -1823,7 +1866,7 @@ public class SettingsProvider extends ContentProvider {
         }
 
         // Resolve the userId on whose behalf the call is made.
-        final int callingUserId = resolveCallingUserIdEnforcingPermissions(userId);
+        final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(userId);
 
         synchronized (mLock) {
             List<String> names = getSettingsNamesLocked(SETTINGS_TYPE_SYSTEM, callingUserId);
@@ -1860,7 +1903,7 @@ public class SettingsProvider extends ContentProvider {
         }
 
         // Resolve the userId on whose behalf the call is made.
-        final int callingUserId = resolveCallingUserIdEnforcingPermissions(requestingUserId);
+        final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);
 
         // Ensure the caller can access the setting.
         enforceSettingReadable(name, SETTINGS_TYPE_SYSTEM, UserHandle.getCallingUserId());
@@ -1935,7 +1978,7 @@ public class SettingsProvider extends ContentProvider {
         }
 
         // Resolve the userId on whose behalf the call is made.
-        final int callingUserId = resolveCallingUserIdEnforcingPermissions(runAsUserId);
+        final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(runAsUserId);
 
         if (isSettingRestrictedForUser(name, callingUserId, value, Binder.getCallingUid())) {
             Slog.e(LOG_TAG, "UserId: " + callingUserId + " is disallowed to change system "
@@ -1969,30 +2012,37 @@ public class SettingsProvider extends ContentProvider {
         // Mutate the value.
         synchronized (mLock) {
             switch (operation) {
-                case MUTATION_OPERATION_INSERT -> {
+                case MUTATION_OPERATION_INSERT: {
                     validateSystemSettingValue(name, value);
                     success = mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_SYSTEM,
                             owningUserId, name, value, null, false, callingPackage,
                             false, null, overrideableByRestore);
+                    break;
                 }
-                case MUTATION_OPERATION_DELETE -> {
+
+                case MUTATION_OPERATION_DELETE: {
                     success = mSettingsRegistry.deleteSettingLocked(SETTINGS_TYPE_SYSTEM,
                             owningUserId, name, false, null);
+                    break;
                 }
-                case MUTATION_OPERATION_UPDATE -> {
+
+                case MUTATION_OPERATION_UPDATE: {
                     validateSystemSettingValue(name, value);
                     success = mSettingsRegistry.updateSettingLocked(SETTINGS_TYPE_SYSTEM,
                             owningUserId, name, value, null, false, callingPackage,
                             false, null);
+                    break;
                 }
-                case MUTATION_OPERATION_RESET -> {
+
+                case MUTATION_OPERATION_RESET: {
                     success = mSettingsRegistry.resetSettingsLocked(SETTINGS_TYPE_SYSTEM,
                             runAsUserId, callingPackage, mode, tag);
+                    break;
                 }
-                default -> {
+
+                default:
                     success = false;
                     Slog.e(LOG_TAG, "Unknown operation code: " + operation);
-                }
             }
         }
 
@@ -2063,8 +2113,8 @@ public class SettingsProvider extends ContentProvider {
      * Returns {@code true} if the specified secure setting should be accessible to the caller.
      */
     private boolean isSecureSettingAccessible(String name) {
-        return switch (name) {
-            case "bluetooth_address" ->
+        switch (name) {
+            case "bluetooth_address":
                 // BluetoothManagerService for some reason stores the Android's Bluetooth MAC
                 // address in this secure setting. Secure settings can normally be read by any app,
                 // which thus enables them to bypass the recently introduced restrictions on access
@@ -2072,23 +2122,22 @@ public class SettingsProvider extends ContentProvider {
                 // To mitigate this we make this setting available only to callers privileged to see
                 // this device's MAC addresses, same as through public API
                 // BluetoothAdapter.getAddress() (see BluetoothManagerService for details).
-                    getContext().checkCallingOrSelfPermission(Manifest.permission.LOCAL_MAC_ADDRESS)
-                            == PackageManager.PERMISSION_GRANTED;
-            default -> true;
-        };
+                return getContext().checkCallingOrSelfPermission(
+                        Manifest.permission.LOCAL_MAC_ADDRESS) == PackageManager.PERMISSION_GRANTED;
+            default:
+                return true;
+        }
     }
 
-    private int resolveOwningUserIdForSecureSetting(int userId, String setting) {
-        // no need to lock because sSecureCloneToManagedSettings is never modified
-        return resolveOwningUserId(userId, sSecureCloneToManagedSettings, setting);
+    private int resolveOwningUserIdForSecureSettingLocked(int userId, String setting) {
+        return resolveOwningUserIdLocked(userId, sSecureCloneToManagedSettings, setting);
     }
 
-    @GuardedBy("mLock")
     private int resolveOwningUserIdForSystemSettingLocked(int userId, String setting) {
         final int parentId;
         // Resolves dependency if setting has a dependency and the calling user has a parent
         if (sSystemCloneFromParentOnDependency.containsKey(setting)
-                && (parentId = getGroupParent(userId)) != userId) {
+                && (parentId = getGroupParentLocked(userId)) != userId) {
             // The setting has a dependency and the profile has a parent
             String dependency = sSystemCloneFromParentOnDependency.get(setting);
             // Lookup the dependency setting as ourselves, some callers may not have access to it.
@@ -2102,11 +2151,11 @@ public class SettingsProvider extends ContentProvider {
                 Binder.restoreCallingIdentity(token);
             }
         }
-        return resolveOwningUserId(userId, sSystemCloneToManagedSettings, setting);
+        return resolveOwningUserIdLocked(userId, sSystemCloneToManagedSettings, setting);
     }
 
-    private int resolveOwningUserId(int userId, Set<String> keys, String name) {
-        final int parentId = getGroupParent(userId);
+    private int resolveOwningUserIdLocked(int userId, Set<String> keys, String name) {
+        final int parentId = getGroupParentLocked(userId);
         if (parentId != userId && keys.contains(name)) {
             return parentId;
         }
@@ -2125,8 +2174,9 @@ public class SettingsProvider extends ContentProvider {
         }
 
         switch (operation) {
-            // Insert updates.
-            case MUTATION_OPERATION_INSERT, MUTATION_OPERATION_UPDATE -> {
+            case MUTATION_OPERATION_INSERT:
+                // Insert updates.
+            case MUTATION_OPERATION_UPDATE: {
                 if (Settings.System.PUBLIC_SETTINGS.contains(name)) {
                     return;
                 }
@@ -2142,8 +2192,9 @@ public class SettingsProvider extends ContentProvider {
 
                 warnOrThrowForUndesiredSecureSettingsMutationForTargetSdk(
                         packageInfo.applicationInfo.targetSdkVersion, name);
-            }
-            case MUTATION_OPERATION_DELETE -> {
+            } break;
+
+            case MUTATION_OPERATION_DELETE: {
                 if (Settings.System.PUBLIC_SETTINGS.contains(name)
                         || Settings.System.PRIVATE_SETTINGS.contains(name)) {
                     throw new IllegalArgumentException("You cannot delete system defined"
@@ -2161,26 +2212,34 @@ public class SettingsProvider extends ContentProvider {
 
                 warnOrThrowForUndesiredSecureSettingsMutationForTargetSdk(
                         packageInfo.applicationInfo.targetSdkVersion, name);
-            }
+            } break;
         }
     }
 
-    private static Set<String> getInstantAppAccessibleSettings(int settingsType) {
-        return switch (settingsType) {
-            case SETTINGS_TYPE_GLOBAL -> Global.INSTANT_APP_SETTINGS;
-            case SETTINGS_TYPE_SECURE -> Secure.INSTANT_APP_SETTINGS;
-            case SETTINGS_TYPE_SYSTEM -> Settings.System.INSTANT_APP_SETTINGS;
-            default -> throw new IllegalArgumentException("Invalid settings type: " + settingsType);
-        };
+    private Set<String> getInstantAppAccessibleSettings(int settingsType) {
+        switch (settingsType) {
+            case SETTINGS_TYPE_GLOBAL:
+                return Settings.Global.INSTANT_APP_SETTINGS;
+            case SETTINGS_TYPE_SECURE:
+                return Settings.Secure.INSTANT_APP_SETTINGS;
+            case SETTINGS_TYPE_SYSTEM:
+                return Settings.System.INSTANT_APP_SETTINGS;
+            default:
+                throw new IllegalArgumentException("Invalid settings type: " + settingsType);
+        }
     }
 
-    private static Set<String> getOverlayInstantAppAccessibleSettings(int settingsType) {
-        return switch (settingsType) {
-            case SETTINGS_TYPE_GLOBAL -> OVERLAY_ALLOWED_GLOBAL_INSTANT_APP_SETTINGS;
-            case SETTINGS_TYPE_SYSTEM -> OVERLAY_ALLOWED_SYSTEM_INSTANT_APP_SETTINGS;
-            case SETTINGS_TYPE_SECURE -> OVERLAY_ALLOWED_SECURE_INSTANT_APP_SETTINGS;
-            default -> throw new IllegalArgumentException("Invalid settings type: " + settingsType);
-        };
+    private Set<String> getOverlayInstantAppAccessibleSettings(int settingsType) {
+        switch (settingsType) {
+            case SETTINGS_TYPE_GLOBAL:
+                return OVERLAY_ALLOWED_GLOBAL_INSTANT_APP_SETTINGS;
+            case SETTINGS_TYPE_SYSTEM:
+                return OVERLAY_ALLOWED_SYSTEM_INSTANT_APP_SETTINGS;
+            case SETTINGS_TYPE_SECURE:
+                return OVERLAY_ALLOWED_SECURE_INSTANT_APP_SETTINGS;
+            default:
+                throw new IllegalArgumentException("Invalid settings type: " + settingsType);
+        }
     }
 
     @GuardedBy("mLock")
@@ -2211,7 +2270,7 @@ public class SettingsProvider extends ContentProvider {
         switch (settingName) {
             // missing READ_PRIVILEGED_PHONE_STATE permission protection
             // see alternative API {@link SubscriptionManager#getPreferredDataSubscriptionId()
-            case Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION -> {
+            case Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION:
                 // app-compat handling, not break apps targeting on previous SDKs.
                 if (CompatChanges.isChangeEnabled(
                         ENFORCE_READ_PERMISSION_FOR_MULTI_SIM_DATA_CALL)) {
@@ -2219,7 +2278,7 @@ public class SettingsProvider extends ContentProvider {
                             Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
                             "access global settings MULTI_SIM_DATA_CALL_SUBSCRIPTION");
                 }
-            }
+                break;
         }
         if (!ai.isInstantApp()) {
             return;
@@ -2247,22 +2306,23 @@ public class SettingsProvider extends ContentProvider {
         final Set<String> readableFields;
         final ArrayMap<String, Integer> readableFieldsWithMaxTargetSdk;
         switch (settingsType) {
-            case SETTINGS_TYPE_GLOBAL -> {
+            case SETTINGS_TYPE_GLOBAL:
                 allFields = sAllGlobalSettings;
                 readableFields = sReadableGlobalSettings;
                 readableFieldsWithMaxTargetSdk = sReadableGlobalSettingsWithMaxTargetSdk;
-            }
-            case SETTINGS_TYPE_SYSTEM -> {
+                break;
+            case SETTINGS_TYPE_SYSTEM:
                 allFields = sAllSystemSettings;
                 readableFields = sReadableSystemSettings;
                 readableFieldsWithMaxTargetSdk = sReadableSystemSettingsWithMaxTargetSdk;
-            }
-            case SETTINGS_TYPE_SECURE -> {
+                break;
+            case SETTINGS_TYPE_SECURE:
                 allFields = sAllSecureSettings;
                 readableFields = sReadableSecureSettings;
                 readableFieldsWithMaxTargetSdk = sReadableSecureSettingsWithMaxTargetSdk;
-            }
-            default -> throw new IllegalArgumentException("Invalid settings type: " + settingsType);
+                break;
+            default:
+                throw new IllegalArgumentException("Invalid settings type: " + settingsType);
         }
 
         if (allFields.contains(settingName)) {
@@ -2320,7 +2380,7 @@ public class SettingsProvider extends ContentProvider {
         throw new IllegalStateException("Calling package doesn't exist");
     }
 
-    private int getGroupParent(int userId) {
+    private int getGroupParentLocked(int userId) {
         // Most frequent use case.
         if (userId == UserHandle.USER_SYSTEM) {
             return userId;
@@ -2420,7 +2480,7 @@ public class SettingsProvider extends ContentProvider {
         }
     }
 
-    private static int resolveCallingUserIdEnforcingPermissions(int requestingUserId) {
+    private static int resolveCallingUserIdEnforcingPermissionsLocked(int requestingUserId) {
         if (requestingUserId == UserHandle.getCallingUserId()) {
             return requestingUserId;
         }
@@ -2594,28 +2654,28 @@ public class SettingsProvider extends ContentProvider {
     private static int getResetModeEnforcingPermission(Bundle args) {
         final int mode = (args != null) ? args.getInt(Settings.CALL_METHOD_RESET_MODE_KEY) : 0;
         switch (mode) {
-            case Settings.RESET_MODE_UNTRUSTED_DEFAULTS -> {
+            case Settings.RESET_MODE_UNTRUSTED_DEFAULTS: {
                 if (!isCallerSystemOrShellOrRootOnDebuggableBuild()) {
                     throw new SecurityException("Only system, shell/root on a "
                             + "debuggable build can reset to untrusted defaults");
                 }
                 return mode;
             }
-            case Settings.RESET_MODE_UNTRUSTED_CHANGES -> {
+            case Settings.RESET_MODE_UNTRUSTED_CHANGES: {
                 if (!isCallerSystemOrShellOrRootOnDebuggableBuild()) {
                     throw new SecurityException("Only system, shell/root on a "
                             + "debuggable build can reset untrusted changes");
                 }
                 return mode;
             }
-            case Settings.RESET_MODE_TRUSTED_DEFAULTS -> {
+            case Settings.RESET_MODE_TRUSTED_DEFAULTS: {
                 if (!isCallerSystemOrShellOrRootOnDebuggableBuild()) {
                     throw new SecurityException("Only system, shell/root on a "
                             + "debuggable build can reset to trusted defaults");
                 }
                 return mode;
             }
-            case Settings.RESET_MODE_PACKAGE_DEFAULTS -> {
+            case Settings.RESET_MODE_PACKAGE_DEFAULTS: {
                 return mode;
             }
         }
@@ -2676,18 +2736,21 @@ public class SettingsProvider extends ContentProvider {
             String column = cursor.getColumnName(i);
 
             switch (column) {
-                case Settings.NameValueTable._ID -> {
+                case Settings.NameValueTable._ID: {
                     values[i] = setting.getId();
-                }
-                case Settings.NameValueTable.NAME -> {
+                } break;
+
+                case Settings.NameValueTable.NAME: {
                     values[i] = setting.getName();
-                }
-                case Settings.NameValueTable.VALUE -> {
+                } break;
+
+                case Settings.NameValueTable.VALUE: {
                     values[i] = setting.getValue();
-                }
-                case Settings.NameValueTable.IS_PRESERVED_IN_RESTORE -> {
+                } break;
+
+                case Settings.NameValueTable.IS_PRESERVED_IN_RESTORE: {
                     values[i] = String.valueOf(setting.isValuePreservedInRestore());
-                }
+                } break;
             }
         }
 
@@ -2699,11 +2762,19 @@ public class SettingsProvider extends ContentProvider {
     }
 
     private String resolveCallingPackage() {
-        return switch (Binder.getCallingUid()) {
-            case Process.ROOT_UID -> "root";
-            case Process.SHELL_UID -> "com.android.shell";
-            default -> getCallingPackage();
-        };
+        switch (Binder.getCallingUid()) {
+            case Process.ROOT_UID: {
+                return "root";
+            }
+
+            case Process.SHELL_UID: {
+                return "com.android.shell";
+            }
+
+            default: {
+                return getCallingPackage();
+            }
+        }
     }
 
     private static final class Arguments {
@@ -2725,17 +2796,17 @@ public class SettingsProvider extends ContentProvider {
         public Arguments(Uri uri, String where, String[] whereArgs, boolean supportAll) {
             final int segmentSize = uri.getPathSegments().size();
             switch (segmentSize) {
-                case 1 -> {
+                case 1: {
                     if (where != null
                             && (WHERE_PATTERN_WITH_PARAM_NO_BRACKETS.matcher(where).matches()
-                            || WHERE_PATTERN_WITH_PARAM_IN_BRACKETS.matcher(where).matches())
+                                || WHERE_PATTERN_WITH_PARAM_IN_BRACKETS.matcher(where).matches())
                             && whereArgs.length == 1) {
                         name = whereArgs[0];
                         table = computeTableForSetting(uri, name);
                         return;
                     } else if (where != null
                             && (WHERE_PATTERN_NO_PARAM_NO_BRACKETS.matcher(where).matches()
-                            || WHERE_PATTERN_NO_PARAM_IN_BRACKETS.matcher(where).matches())) {
+                                || WHERE_PATTERN_NO_PARAM_IN_BRACKETS.matcher(where).matches())) {
                         final int startIndex = Math.max(where.indexOf("'"),
                                 where.indexOf("\"")) + 1;
                         final int endIndex = Math.max(where.lastIndexOf("'"),
@@ -2748,14 +2819,15 @@ public class SettingsProvider extends ContentProvider {
                         table = computeTableForSetting(uri, null);
                         return;
                     }
-                }
-                case 2 -> {
+                } break;
+
+                case 2: {
                     if (where == null && whereArgs == null) {
                         name = uri.getPathSegments().get(1);
                         table = computeTableForSetting(uri, name);
                         return;
                     }
-                }
+                } break;
             }
 
             EventLogTags.writeUnsupportedSettingsQuery(
@@ -2888,7 +2960,6 @@ public class SettingsProvider extends ContentProvider {
             mBackupManager = new BackupManager(getContext());
         }
 
-        @GuardedBy("mLock")
         private void generateUserKeyLocked(int userId) {
             // Generate a random key for each user used for creating a new ssaid.
             final byte[] keyBytes = new byte[32];
@@ -2912,7 +2983,6 @@ public class SettingsProvider extends ContentProvider {
             return ByteBuffer.allocate(4).putInt(data.length).array();
         }
 
-        @GuardedBy("mLock")
         public Setting generateSsaidLocked(PackageInfo callingPkg, int userId) {
             // Read the user's key from the ssaid table.
             Setting userKeySetting = getSettingLocked(SETTINGS_TYPE_SSAID, userId, SSAID_USER_KEY);
@@ -2974,7 +3044,6 @@ public class SettingsProvider extends ContentProvider {
             return getSettingLocked(SETTINGS_TYPE_SSAID, userId, uid);
         }
 
-        @GuardedBy("mLock")
         private void syncSsaidTableOnStartLocked() {
             // Verify that each user's packages and ssaid's are in sync.
             for (UserInfo user : mUserManager.getAliveUsers()) {
@@ -3009,17 +3078,15 @@ public class SettingsProvider extends ContentProvider {
             }
         }
 
-        @GuardedBy("mLock")
         public List<String> getSettingsNamesLocked(int type, int userId) {
             final int key = makeKey(type, userId);
-            SettingsState settingsState = mSettingsStates.get(key);
+            SettingsState settingsState = peekSettingsStateLocked(key);
             if (settingsState == null) {
                 return new ArrayList<>();
             }
             return settingsState.getSettingNamesLocked();
         }
 
-        @GuardedBy("mLock")
         public SparseBooleanArray getKnownUsersLocked() {
             SparseBooleanArray users = new SparseBooleanArray();
             for (int i = mSettingsStates.size()-1; i >= 0; i--) {
@@ -3028,19 +3095,17 @@ public class SettingsProvider extends ContentProvider {
             return users;
         }
 
-        @GuardedBy("mLock")
         @Nullable
         public SettingsState getSettingsLocked(int type, int userId) {
             final int key = makeKey(type, userId);
-            return mSettingsStates.get(key);
+            return peekSettingsStateLocked(key);
         }
 
-        @GuardedBy("mLock")
-        public void ensureSettingsForUserLocked(int userId) {
+        public boolean ensureSettingsForUserLocked(int userId) {
             // First make sure this user actually exists.
             if (mUserManager.getUserInfo(userId) == null) {
                 Slog.wtf(LOG_TAG, "Requested user " + userId + " does not exist");
-                return;
+                return false;
             }
 
             // Migrate the setting for this user if needed.
@@ -3078,9 +3143,9 @@ public class SettingsProvider extends ContentProvider {
             // Upgrade the settings to the latest version.
             UpgradeController upgrader = new UpgradeController(userId);
             upgrader.upgradeIfNeededLocked();
+            return true;
         }
 
-        @GuardedBy("mLock")
         private void ensureSettingsStateLocked(int key) {
             if (mSettingsStates.get(key) == null) {
                 final int maxBytesPerPackage = getMaxBytesPerPackageForType(getTypeFromKey(key));
@@ -3090,7 +3155,6 @@ public class SettingsProvider extends ContentProvider {
             }
         }
 
-        @GuardedBy("mLock")
         public void removeUserStateLocked(int userId, boolean permanently) {
             // We always keep the global settings in memory.
 
@@ -3102,7 +3166,12 @@ public class SettingsProvider extends ContentProvider {
                     mSettingsStates.remove(systemKey);
                     systemSettingsState.destroyLocked(null);
                 } else {
-                    systemSettingsState.destroyLocked(() -> mSettingsStates.remove(systemKey));
+                    systemSettingsState.destroyLocked(new Runnable() {
+                        @Override
+                        public void run() {
+                            mSettingsStates.remove(systemKey);
+                        }
+                    });
                 }
             }
 
@@ -3114,7 +3183,12 @@ public class SettingsProvider extends ContentProvider {
                     mSettingsStates.remove(secureKey);
                     secureSettingsState.destroyLocked(null);
                 } else {
-                    secureSettingsState.destroyLocked(() -> mSettingsStates.remove(secureKey));
+                    secureSettingsState.destroyLocked(new Runnable() {
+                        @Override
+                        public void run() {
+                            mSettingsStates.remove(secureKey);
+                        }
+                    });
                 }
             }
 
@@ -3126,7 +3200,12 @@ public class SettingsProvider extends ContentProvider {
                     mSettingsStates.remove(ssaidKey);
                     ssaidSettingsState.destroyLocked(null);
                 } else {
-                    ssaidSettingsState.destroyLocked(() -> mSettingsStates.remove(ssaidKey));
+                    ssaidSettingsState.destroyLocked(new Runnable() {
+                        @Override
+                        public void run() {
+                            mSettingsStates.remove(ssaidKey);
+                        }
+                    });
                 }
             }
 
@@ -3134,7 +3213,6 @@ public class SettingsProvider extends ContentProvider {
             mGenerationRegistry.onUserRemoved(userId);
         }
 
-        @GuardedBy("mLock")
         public boolean insertSettingLocked(int type, int userId, String name, String value,
                 String tag, boolean makeDefault, String packageName, boolean forceNotify,
                 Set<String> criticalSettings, boolean overrideableByRestore) {
@@ -3142,7 +3220,6 @@ public class SettingsProvider extends ContentProvider {
                     packageName, forceNotify, criticalSettings, overrideableByRestore);
         }
 
-        @GuardedBy("mLock")
         public boolean insertSettingLocked(int type, int userId, String name, String value,
                 String tag, boolean makeDefault, boolean forceNonSystemPackage, String packageName,
                 boolean forceNotify, Set<String> criticalSettings, boolean overrideableByRestore) {
@@ -3155,7 +3232,7 @@ public class SettingsProvider extends ContentProvider {
 
             boolean success = false;
             boolean wasUnsetNonPredefinedSetting = false;
-            SettingsState settingsState = mSettingsStates.get(key);
+            SettingsState settingsState = peekSettingsStateLocked(key);
             if (settingsState != null) {
                 if (!isSettingPreDefined(name, type) && !settingsState.hasSetting(name)) {
                     wasUnsetNonPredefinedSetting = true;
@@ -3187,10 +3264,9 @@ public class SettingsProvider extends ContentProvider {
          * Set Config Settings using consumed keyValues, returns true if the keyValues can be set,
          * false otherwise.
          */
-        @GuardedBy("mLock")
         public boolean setConfigSettingsLocked(int key, String prefix,
                 Map<String, String> keyValues, String packageName) {
-            SettingsState settingsState = mSettingsStates.get(key);
+            SettingsState settingsState = peekSettingsStateLocked(key);
             if (settingsState != null) {
                 if (settingsState.isNewConfigBannedLocked(prefix, keyValues)) {
                     return false;
@@ -3207,13 +3283,12 @@ public class SettingsProvider extends ContentProvider {
             return true;
         }
 
-        @GuardedBy("mLock")
         public boolean deleteSettingLocked(int type, int userId, String name, boolean forceNotify,
                 Set<String> criticalSettings) {
             final int key = makeKey(type, userId);
 
             boolean success = false;
-            SettingsState settingsState = mSettingsStates.get(key);
+            SettingsState settingsState = peekSettingsStateLocked(key);
             if (settingsState != null) {
                 success = settingsState.deleteSettingLocked(name);
             }
@@ -3231,14 +3306,13 @@ public class SettingsProvider extends ContentProvider {
             return success;
         }
 
-        @GuardedBy("mLock")
         public boolean updateSettingLocked(int type, int userId, String name, String value,
                 String tag, boolean makeDefault, String packageName, boolean forceNotify,
                 Set<String> criticalSettings) {
             final int key = makeKey(type, userId);
 
             boolean success = false;
-            SettingsState settingsState = mSettingsStates.get(key);
+            SettingsState settingsState = peekSettingsStateLocked(key);
             if (settingsState != null) {
                 success = settingsState.updateSettingLocked(name, value, tag,
                         makeDefault, packageName);
@@ -3257,11 +3331,10 @@ public class SettingsProvider extends ContentProvider {
             return success;
         }
 
-        @GuardedBy("mLock")
         public Setting getSettingLocked(int type, int userId, String name) {
             final int key = makeKey(type, userId);
 
-            SettingsState settingsState = mSettingsStates.get(key);
+            SettingsState settingsState = peekSettingsStateLocked(key);
             if (settingsState == null) {
                 return null;
             }
@@ -3279,18 +3352,16 @@ public class SettingsProvider extends ContentProvider {
             return Global.SECURE_FRP_MODE.equals(setting.getName());
         }
 
-        @GuardedBy("mLock")
         public boolean resetSettingsLocked(int type, int userId, String packageName, int mode,
                 String tag) {
             return resetSettingsLocked(type, userId, packageName, mode, tag, /*prefix=*/
                     null);
         }
 
-        @GuardedBy("mLock")
         public boolean resetSettingsLocked(int type, int userId, String packageName, int mode,
                 String tag, @Nullable String prefix) {
             final int key = makeKey(type, userId);
-            SettingsState settingsState = mSettingsStates.get(key);
+            SettingsState settingsState = peekSettingsStateLocked(key);
             if (settingsState == null) {
                 return false;
             }
@@ -3298,7 +3369,7 @@ public class SettingsProvider extends ContentProvider {
             boolean success = false;
             banConfigurationIfNecessary(type, prefix, settingsState);
             switch (mode) {
-                case Settings.RESET_MODE_PACKAGE_DEFAULTS -> {
+                case Settings.RESET_MODE_PACKAGE_DEFAULTS: {
                     for (String name : settingsState.getSettingNamesLocked()) {
                         boolean someSettingChanged = false;
                         Setting setting = settingsState.getSettingLocked(name);
@@ -3318,8 +3389,9 @@ public class SettingsProvider extends ContentProvider {
                             success = true;
                         }
                     }
-                }
-                case Settings.RESET_MODE_UNTRUSTED_DEFAULTS -> {
+                } break;
+
+                case Settings.RESET_MODE_UNTRUSTED_DEFAULTS: {
                     for (String name : settingsState.getSettingNamesLocked()) {
                         boolean someSettingChanged = false;
                         Setting setting = settingsState.getSettingLocked(name);
@@ -3339,8 +3411,9 @@ public class SettingsProvider extends ContentProvider {
                             success = true;
                         }
                     }
-                }
-                case Settings.RESET_MODE_UNTRUSTED_CHANGES -> {
+                } break;
+
+                case Settings.RESET_MODE_UNTRUSTED_CHANGES: {
                     for (String name : settingsState.getSettingNamesLocked()) {
                         boolean someSettingChanged = false;
                         Setting setting = settingsState.getSettingLocked(name);
@@ -3366,8 +3439,9 @@ public class SettingsProvider extends ContentProvider {
                             success = true;
                         }
                     }
-                }
-                case Settings.RESET_MODE_TRUSTED_DEFAULTS -> {
+                } break;
+
+                case Settings.RESET_MODE_TRUSTED_DEFAULTS: {
                     for (String name : settingsState.getSettingNamesLocked()) {
                         Setting setting = settingsState.getSettingLocked(name);
                         boolean someSettingChanged = false;
@@ -3390,12 +3464,11 @@ public class SettingsProvider extends ContentProvider {
                             success = true;
                         }
                     }
-                }
+                } break;
             }
             return success;
         }
 
-        @GuardedBy("mLock")
         public void removeSettingsForPackageLocked(String packageName, int userId) {
             // Global and secure settings are signature protected. Apps signed
             // by the platform certificate are generally not uninstalled  and
@@ -3409,7 +3482,6 @@ public class SettingsProvider extends ContentProvider {
             }
         }
 
-        @GuardedBy("mLock")
         public void onUidRemovedLocked(int uid) {
             final SettingsState ssaidSettings = getSettingsLocked(SETTINGS_TYPE_SSAID,
                     UserHandle.getUserId(uid));
@@ -3418,7 +3490,19 @@ public class SettingsProvider extends ContentProvider {
             }
         }
 
-        @GuardedBy("mLock")
+        @Nullable
+        private SettingsState peekSettingsStateLocked(int key) {
+            SettingsState settingsState = mSettingsStates.get(key);
+            if (settingsState != null) {
+                return settingsState;
+            }
+
+            if (!ensureSettingsForUserLocked(getUserIdFromKey(key))) {
+                return null;
+            }
+            return mSettingsStates.get(key);
+        }
+
         private void migrateAllLegacySettingsIfNeededLocked() {
             final int key = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
             File globalFile = getSettingsFile(key);
@@ -3454,7 +3538,6 @@ public class SettingsProvider extends ContentProvider {
             }
         }
 
-        @GuardedBy("mLock")
         private void migrateLegacySettingsForUserIfNeededLocked(int userId) {
             // Every user has secure settings and if no file we need to migrate.
             final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
@@ -3469,7 +3552,6 @@ public class SettingsProvider extends ContentProvider {
             migrateLegacySettingsForUserLocked(dbHelper, database, userId);
         }
 
-        @GuardedBy("mLock")
         private void migrateLegacySettingsForUserLocked(DatabaseHelper dbHelper,
                 SQLiteDatabase database, int userId) {
             // Move over the system settings.
@@ -3514,7 +3596,6 @@ public class SettingsProvider extends ContentProvider {
             }
         }
 
-        @GuardedBy("mLock")
         private void migrateLegacySettingsLocked(SettingsState settingsState,
                 SQLiteDatabase database, String table) {
             SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
@@ -3549,7 +3630,7 @@ public class SettingsProvider extends ContentProvider {
             }
         }
 
-        @GuardedBy("mLock")
+        @GuardedBy("secureSettings.mLock")
         private void ensureSecureSettingAndroidIdSetLocked(SettingsState secureSettings) {
             Setting value = secureSettings.getSettingLocked(Settings.Secure.ANDROID_ID);
 
@@ -3625,7 +3706,6 @@ public class SettingsProvider extends ContentProvider {
                     name, type, changeType);
         }
 
-        @GuardedBy("mLock")
         private void notifyForConfigSettingsChangeLocked(int key, String prefix,
                 List<String> changedSettings) {
 
@@ -3707,18 +3787,30 @@ public class SettingsProvider extends ContentProvider {
             }
         }
 
-        private static File getSettingsFile(int key) {
-            final int userId = getUserIdFromKey(key);
-            final int type = getTypeFromKey(key);
-            final File userSystemDirectory = Environment.getUserSystemDirectory(userId);
-            return switch (type) {
-                case SETTINGS_TYPE_CONFIG -> new File(userSystemDirectory, SETTINGS_FILE_CONFIG);
-                case SETTINGS_TYPE_GLOBAL -> new File(userSystemDirectory, SETTINGS_FILE_GLOBAL);
-                case SETTINGS_TYPE_SYSTEM -> new File(userSystemDirectory, SETTINGS_FILE_SYSTEM);
-                case SETTINGS_TYPE_SECURE -> new File(userSystemDirectory, SETTINGS_FILE_SECURE);
-                case SETTINGS_TYPE_SSAID -> new File(userSystemDirectory, SETTINGS_FILE_SSAID);
-                default -> throw new IllegalArgumentException("Invalid settings key:" + key);
-            };
+        private File getSettingsFile(int key) {
+            if (isConfigSettingsKey(key)) {
+                final int userId = getUserIdFromKey(key);
+                return new File(Environment.getUserSystemDirectory(userId),
+                        SETTINGS_FILE_CONFIG);
+            } else if (isGlobalSettingsKey(key)) {
+                final int userId = getUserIdFromKey(key);
+                return new File(Environment.getUserSystemDirectory(userId),
+                        SETTINGS_FILE_GLOBAL);
+            } else if (isSystemSettingsKey(key)) {
+                final int userId = getUserIdFromKey(key);
+                return new File(Environment.getUserSystemDirectory(userId),
+                        SETTINGS_FILE_SYSTEM);
+            } else if (isSecureSettingsKey(key)) {
+                final int userId = getUserIdFromKey(key);
+                return new File(Environment.getUserSystemDirectory(userId),
+                        SETTINGS_FILE_SECURE);
+            } else if (isSsaidSettingsKey(key)) {
+                final int userId = getUserIdFromKey(key);
+                return new File(Environment.getUserSystemDirectory(userId),
+                        SETTINGS_FILE_SSAID);
+            } else {
+                throw new IllegalArgumentException("Invalid settings key:" + key);
+            }
         }
 
         private Uri getNotificationUriFor(int key, String name) {
@@ -3741,11 +3833,14 @@ public class SettingsProvider extends ContentProvider {
 
         private int getMaxBytesPerPackageForType(int type) {
             switch (type) {
-                case SETTINGS_TYPE_CONFIG, SETTINGS_TYPE_GLOBAL, SETTINGS_TYPE_SECURE,
-                        SETTINGS_TYPE_SSAID -> {
+                case SETTINGS_TYPE_CONFIG:
+                case SETTINGS_TYPE_GLOBAL:
+                case SETTINGS_TYPE_SECURE:
+                case SETTINGS_TYPE_SSAID: {
                     return SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED;
                 }
-                default -> {
+
+                default: {
                     return SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED;
                 }
             }
@@ -3762,7 +3857,7 @@ public class SettingsProvider extends ContentProvider {
             @Override
             public void handleMessage(Message msg) {
                 switch (msg.what) {
-                    case MSG_NOTIFY_URI_CHANGED -> {
+                    case MSG_NOTIFY_URI_CHANGED: {
                         final int userId = msg.arg1;
                         Uri uri = (Uri) msg.obj;
                         try {
@@ -3773,11 +3868,12 @@ public class SettingsProvider extends ContentProvider {
                         if (DEBUG) {
                             Slog.v(LOG_TAG, "Notifying for " + userId + ": " + uri);
                         }
-                    }
-                    case MSG_NOTIFY_DATA_CHANGED -> {
+                    } break;
+
+                    case MSG_NOTIFY_DATA_CHANGED: {
                         mBackupManager.dataChanged();
                         scheduleWriteFallbackFilesJob();
-                    }
+                    } break;
                 }
             }
         }
@@ -3791,7 +3887,6 @@ public class SettingsProvider extends ContentProvider {
                 mUserId = userId;
             }
 
-            @GuardedBy("mLock")
             public void upgradeIfNeededLocked() {
                 // The version of all settings for a user is the same (all users have secure).
                 SettingsState secureSettings = getSettingsLocked(
@@ -3849,22 +3944,18 @@ public class SettingsProvider extends ContentProvider {
                 systemSettings.setVersionLocked(newVersion);
             }
 
-            @GuardedBy("mLock")
             private SettingsState getGlobalSettingsLocked() {
                 return getSettingsLocked(SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
             }
 
-            @GuardedBy("mLock")
             private SettingsState getSecureSettingsLocked(int userId) {
                 return getSettingsLocked(SETTINGS_TYPE_SECURE, userId);
             }
 
-            @GuardedBy("mLock")
             private SettingsState getSsaidSettingsLocked(int userId) {
                 return getSettingsLocked(SETTINGS_TYPE_SSAID, userId);
             }
 
-            @GuardedBy("mLock")
             private SettingsState getSystemSettingsLocked(int userId) {
                 return getSettingsLocked(SETTINGS_TYPE_SYSTEM, userId);
             }
@@ -5308,7 +5399,7 @@ public class SettingsProvider extends ContentProvider {
                     // next version step.
                     // If this is a new profile, check if a secure setting exists for the
                     // owner of the profile and use that value for the work profile.
-                    int owningId = resolveOwningUserIdForSecureSetting(userId,
+                    int owningId = resolveOwningUserIdForSecureSettingLocked(userId,
                             NOTIFICATION_BUBBLES);
                     Setting previous = getGlobalSettingsLocked()
                             .getSettingLocked("notification_bubbles");
@@ -5977,22 +6068,18 @@ public class SettingsProvider extends ContentProvider {
                 return currentVersion;
             }
 
-            @GuardedBy("mLock")
             private void initGlobalSettingsDefaultValLocked(String key, boolean val) {
                 initGlobalSettingsDefaultValLocked(key, val ? "1" : "0");
             }
 
-            @GuardedBy("mLock")
             private void initGlobalSettingsDefaultValLocked(String key, int val) {
                 initGlobalSettingsDefaultValLocked(key, String.valueOf(val));
             }
 
-            @GuardedBy("mLock")
             private void initGlobalSettingsDefaultValLocked(String key, long val) {
                 initGlobalSettingsDefaultValLocked(key, String.valueOf(val));
             }
 
-            @GuardedBy("mLock")
             private void initGlobalSettingsDefaultValLocked(String key, String val) {
                 final SettingsState globalSettings = getGlobalSettingsLocked();
                 Setting currentSetting = globalSettings.getSettingLocked(key);
@@ -6111,7 +6198,6 @@ public class SettingsProvider extends ContentProvider {
             }
         }
 
-        @GuardedBy("mLock")
         private void ensureLegacyDefaultValueAndSystemSetUpdatedLocked(SettingsState settings,
                 int userId) {
             List<String> names = settings.getSettingNamesLocked();
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 9d3200dc340daa9ad987db3dacc04658520ed37d..e6a82e83433ba37505083035e7a4875a44469a62 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -214,6 +214,7 @@ android_library {
 
     lint: {
         extra_check_modules: ["SystemUILintChecker"],
+        warning_checks: ["MissingApacheLicenseDetector"],
     },
 }
 
@@ -254,7 +255,6 @@ filegroup {
     srcs: [
         /* Keyguard converted tests */
         // data
-        "tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt",
         "tests/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfigTest.kt",
         "tests/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfigTest.kt",
         "tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt",
@@ -402,10 +402,19 @@ filegroup {
         "tests/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractorTest.kt",
         "tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt",
         "tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt",
+
     ],
     path: "tests/src",
 }
 
+filegroup {
+    name: "SystemUI-tests-multivalent",
+    srcs: [
+        "multivalentTests/src/**/*.kt",
+    ],
+    path: "multivalentTests/src",
+}
+
 java_library {
     name: "SystemUI-tests-concurrency",
     srcs: [
@@ -494,6 +503,7 @@ android_library {
         "src/**/*.java",
         "src/**/I*.aidl",
         ":ReleaseJavaFiles",
+        ":SystemUI-tests-multivalent",
         ":SystemUI-tests-utils",
     ],
     static_libs: [
@@ -572,6 +582,7 @@ android_robolectric_test {
         ":SystemUI-tests-utils",
         ":SystemUI-test-fakes",
         ":SystemUI-tests-robolectric-pilots",
+        ":SystemUI-tests-multivalent",
     ],
     static_libs: [
         "androidx.test.uiautomator_uiautomator",
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 4ea57a8cc0071aa6aeb82830e2a14907cc48ee59..ab4db451406d8a558f69bef02464b853618b2f0c 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -290,9 +290,10 @@ class ActivityLaunchAnimator(
         controller: Controller?,
         animate: Boolean = true,
         packageName: String? = null,
+        showOverLockscreen: Boolean = false,
         intentStarter: PendingIntentStarter
     ) {
-        startIntentWithAnimation(controller, animate, packageName) {
+        startIntentWithAnimation(controller, animate, packageName, showOverLockscreen) {
             intentStarter.startPendingIntent(it)
         }
     }
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/MissingApacheLicenseDetector.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/MissingApacheLicenseDetector.kt
new file mode 100644
index 0000000000000000000000000000000000000000..46125bee1523238f3f04130f772743c8ff6a5e11
--- /dev/null
+++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/MissingApacheLicenseDetector.kt
@@ -0,0 +1,126 @@
+/*
+ * 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.systemui.lint
+
+import com.android.ide.common.blame.SourcePosition
+import com.android.tools.lint.client.api.UElementHandler
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.Location
+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.time.Year
+import org.jetbrains.uast.UComment
+import org.jetbrains.uast.UFile
+
+/**
+ * Checks if every AOSP Java/Kotlin source code file is starting with Apache license information.
+ */
+class MissingApacheLicenseDetector : Detector(), SourceCodeScanner {
+
+    override fun getApplicableUastTypes() = listOf(UFile::class.java)
+
+    override fun createUastHandler(context: JavaContext): UElementHandler? {
+        return object : UElementHandler() {
+            override fun visitFile(node: UFile) {
+                val firstComment = node.allCommentsInFile.firstOrNull()
+                // Normally we don't need to explicitly handle suppressing case and just return
+                // error as usual with indicating node and lint will ignore it for us. But here
+                // suppressing will be applied on top of comment that doesn't exist so we don't have
+                // node to return - it's a bit of corner case
+                if (firstComment != null && firstComment.isSuppressingComment()) {
+                    return
+                }
+                if (firstComment == null || !firstComment.isLicenseComment()) {
+                    val firstLineOfFile =
+                        Location.create(
+                            context.file,
+                            SourcePosition(/* lineNumber= */ 1, /* column= */ 1, /* offset= */ 0)
+                        )
+                    context.report(
+                        issue = ISSUE,
+                        location = firstLineOfFile,
+                        message =
+                            "License header is missing\n" +
+                                "Please add the following copyright and license header to the" +
+                                " beginning of the file:\n\n" +
+                                copyrightHeader
+                    )
+                }
+            }
+        }
+    }
+
+    private fun UComment.isSuppressingComment(): Boolean {
+        val suppressingComment =
+            "//noinspection ${MissingApacheLicenseDetector::class.java.simpleName}"
+        return text.contains(suppressingComment)
+    }
+
+    private fun UComment.isLicenseComment(): Boolean {
+        // We probably don't want to compare full copyright header in case there are some small
+        // discrepancies in already existing files, e.g. year. We could do regexp but it should be
+        // good enough if this detector deals with missing
+        // license header instead of incorrect license header
+        return text.contains("Apache License")
+    }
+
+    private val copyrightHeader: String
+        get() =
+            """
+            /*
+             * Copyright (C) ${Year.now().value} The Android Open Source Project
+             *
+             * Licensed under the Apache License, Version 2.0 (the "License");
+             * you may not use this file except in compliance with the License.
+             * You may obtain a copy of the License at
+             *
+             *     http://www.apache.org/licenses/LICENSE-2.0
+             *
+             * Unless required by applicable law or agreed to in writing, software
+             * distributed under the License is distributed on an "AS IS" BASIS,
+             * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+             * See the License for the specific language governing permissions and
+             * limitations under the License.
+             */
+            """
+                .trimIndent()
+                .trim()
+
+    companion object {
+        @JvmField
+        val ISSUE: Issue =
+            Issue.create(
+                id = "MissingApacheLicenseDetector",
+                briefDescription = "File is missing Apache license information",
+                explanation =
+                    """
+                        Every source code file should have copyright and license information \
+                        attached at the beginning.""",
+                category = Category.COMPLIANCE,
+                priority = 8,
+                // ignored by default and then explicitly overridden in SysUI's soong configuration
+                severity = Severity.IGNORE,
+                implementation =
+                    Implementation(MissingApacheLicenseDetector::class.java, Scope.JAVA_FILE_SCOPE),
+            )
+    }
+}
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
index 520c8882b4280bd0649baed8b6f6bebd6dbab2f2..e09aa421c68af6558fe1dc6d4c24bf30674a0899 100644
--- a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
+++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
@@ -42,6 +42,7 @@ class SystemUIIssueRegistry : IssueRegistry() {
                 StaticSettingsProviderDetector.ISSUE,
                 DemotingTestWithoutBugDetector.ISSUE,
                 TestFunctionNameViolationDetector.ISSUE,
+                MissingApacheLicenseDetector.ISSUE,
             )
 
     override val api: Int
diff --git a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/MissingApacheLicenseDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/MissingApacheLicenseDetectorTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..78e133fda3d6daf3de020b2f989330e834e340bb
--- /dev/null
+++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/MissingApacheLicenseDetectorTest.kt
@@ -0,0 +1,92 @@
+/*
+ * 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.systemui.lint
+
+import com.android.tools.lint.checks.infrastructure.TestMode
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+import java.time.Year
+import org.junit.Test
+
+class MissingApacheLicenseDetectorTest : SystemUILintDetectorTest() {
+    override fun getDetector(): Detector {
+        return MissingApacheLicenseDetector()
+    }
+
+    override fun getIssues(): List<Issue> {
+        return listOf(
+            MissingApacheLicenseDetector.ISSUE,
+        )
+    }
+
+    @Test
+    fun testHasCopyright() {
+        lint()
+            .files(
+                kotlin(
+                    """
+                    /*
+                     * Copyright (C) ${Year.now().value} The Android Open Source Project
+                     *
+                     * Licensed under the Apache License, Version 2.0 (the "License");
+                     * you may not use this file except in compliance with the License.
+                     * You may obtain a copy of the License at
+                     *
+                     *     http://www.apache.org/licenses/LICENSE-2.0
+                     *
+                     * Unless required by applicable law or agreed to in writing, software
+                     * distributed under the License is distributed on an "AS IS" BASIS,
+                     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+                     * See the License for the specific language governing permissions and
+                     * limitations under the License.
+                     */
+
+                    package test.pkg.name
+
+                    class MyTest
+                    """
+                        .trimIndent()
+                )
+            )
+            .issues(MissingApacheLicenseDetector.ISSUE)
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun testDoesntHaveCopyright() {
+        lint()
+            .files(
+                kotlin(
+                    """
+                    package test.pkg.name
+
+                    class MyTest
+                    """
+                        .trimIndent()
+                )
+            )
+            // skipping mode SUPPRESSIBLE because lint tries to add @Suppress to class which
+            // probably doesn't make much sense for license header (which is far above it) and for
+            // kotlin files that can have several classes. If someone really wants to omit header
+            // they can do it with //noinspection
+            .skipTestModes(TestMode.SUPPRESSIBLE)
+            .issues(MissingApacheLicenseDetector.ISSUE)
+            .run()
+            .expectContains("License header is missing")
+    }
+}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
index 6496507218a5493387de6b1e3d4ad073b5793325..2dc53ab8bf76e4ae91fa9a6892f20f508de42b6e 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
@@ -16,6 +16,7 @@
 
 package com.android.compose.animation.scene
 
+import android.util.Log
 import androidx.annotation.VisibleForTesting
 import androidx.compose.animation.core.Animatable
 import androidx.compose.animation.core.Spring
@@ -36,7 +37,7 @@ import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.input.nestedscroll.nestedScroll
 import androidx.compose.ui.unit.Velocity
 import androidx.compose.ui.unit.dp
-import com.android.compose.nestedscroll.PriorityPostNestedScrollConnection
+import com.android.compose.nestedscroll.PriorityNestedScrollConnection
 import kotlin.math.absoluteValue
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Job
@@ -130,10 +131,12 @@ class SceneGestureHandler(
     internal val currentScene: Scene
         get() = layoutImpl.scene(transitionState.currentScene)
 
-    internal val isDrivingTransition
+    @VisibleForTesting
+    val isDrivingTransition
         get() = transitionState == swipeTransition
 
-    internal var isAnimatingOffset
+    @VisibleForTesting
+    var isAnimatingOffset
         get() = swipeTransition.isAnimatingOffset
         private set(value) {
             swipeTransition.isAnimatingOffset = value
@@ -154,20 +157,26 @@ class SceneGestureHandler(
      */
     private val positionalThreshold = with(layoutImpl.density) { 56.dp.toPx() }
 
+    internal var gestureWithPriority: Any? = null
+
     internal fun onDragStarted() {
         if (isDrivingTransition) {
             // This [transition] was already driving the animation: simply take over it.
-            if (isAnimatingOffset) {
-                // Stop animating and start from where the current offset. Setting the animation job
-                // to `null` will effectively cancel the animation.
-                swipeTransition.stopOffsetAnimation()
-                swipeTransition.dragOffset = swipeTransition.offsetAnimatable.value
-            }
-
+            // Stop animating and start from where the current offset.
+            swipeTransition.stopOffsetAnimation()
             return
         }
 
-        // TODO(b/290184746): Better handle interruptions here if state != idle.
+        val transition = transitionState
+        if (transition is TransitionState.Transition) {
+            // TODO(b/290184746): Better handle interruptions here if state != idle.
+            Log.w(
+                TAG,
+                "start from TransitionState.Transition is not fully supported: from" +
+                    " ${transition.fromScene} to ${transition.toScene} " +
+                    "(progress ${transition.progress})"
+            )
+        }
 
         val fromScene = currentScene
 
@@ -196,6 +205,8 @@ class SceneGestureHandler(
     }
 
     internal fun onDrag(delta: Float) {
+        if (delta == 0f) return
+
         swipeTransition.dragOffset += delta
 
         // First check transition.fromScene should be changed for the case where the user quickly
@@ -293,48 +304,77 @@ class SceneGestureHandler(
             return
         }
 
-        // We were not animating.
-        if (swipeTransition._fromScene == swipeTransition._toScene) {
-            transitionState = TransitionState.Idle(swipeTransition._fromScene.key)
-            return
+        fun animateTo(targetScene: Scene, targetOffset: Float) {
+            // If the effective current scene changed, it should be reflected right now in the
+            // current scene state, even before the settle animation is ongoing. That way all the
+            // swipeables and back handlers will be refreshed and the user can for instance quickly
+            // swipe vertically from A => B then horizontally from B => C, or swipe from A => B then
+            // immediately go back B => A.
+            if (targetScene != swipeTransition._currentScene) {
+                swipeTransition._currentScene = targetScene
+                layoutImpl.onChangeScene(targetScene.key)
+            }
+
+            animateOffset(
+                initialVelocity = velocity,
+                targetOffset = targetOffset,
+                targetScene = targetScene.key
+            )
         }
 
-        // Compute the destination scene (and therefore offset) to settle in.
-        val targetOffset: Float
-        val targetScene: Scene
-        val offset = swipeTransition.dragOffset
-        val distance = swipeTransition.distance
-        if (
-            canChangeScene &&
+        val fromScene = swipeTransition._fromScene
+        if (canChangeScene) {
+            // If we are halfway between two scenes, we check what the target will be based on the
+            // velocity and offset of the transition, then we launch the animation.
+
+            val toScene = swipeTransition._toScene
+            if (fromScene == toScene) {
+                // We were not animating.
+                transitionState = TransitionState.Idle(fromScene.key)
+                return
+            }
+
+            // Compute the destination scene (and therefore offset) to settle in.
+            val offset = swipeTransition.dragOffset
+            val distance = swipeTransition.distance
+            if (
                 shouldCommitSwipe(
                     offset,
                     distance,
                     velocity,
-                    wasCommitted = swipeTransition._currentScene == swipeTransition._toScene,
+                    wasCommitted = swipeTransition._currentScene == toScene,
                 )
-        ) {
-            targetOffset = distance
-            targetScene = swipeTransition._toScene
+            ) {
+                // Animate to the next scene
+                animateTo(targetScene = toScene, targetOffset = distance)
+            } else {
+                // Animate to the initial scene
+                animateTo(targetScene = fromScene, targetOffset = 0f)
+            }
         } else {
-            targetOffset = 0f
-            targetScene = swipeTransition._fromScene
-        }
-
-        // If the effective current scene changed, it should be reflected right now in the current
-        // scene state, even before the settle animation is ongoing. That way all the swipeables and
-        // back handlers will be refreshed and the user can for instance quickly swipe vertically
-        // from A => B then horizontally from B => C, or swipe from A => B then immediately go back
-        // B => A.
-        if (targetScene != swipeTransition._currentScene) {
-            swipeTransition._currentScene = targetScene
-            layoutImpl.onChangeScene(targetScene.key)
+            // We are doing an overscroll animation between scenes. In this case, we can also start
+            // from the idle position.
+
+            val startFromIdlePosition = swipeTransition.dragOffset == 0f
+
+            if (startFromIdlePosition) {
+                // If there is a next scene, we start the overscroll animation.
+                val target = fromScene.findTargetSceneAndDistance(velocity)
+                val isValidTarget = target.distance != 0f && target.sceneKey != fromScene.key
+                if (isValidTarget) {
+                    swipeTransition._toScene = layoutImpl.scene(target.sceneKey)
+                    swipeTransition._distance = target.distance
+
+                    animateTo(targetScene = fromScene, targetOffset = 0f)
+                } else {
+                    // We will not animate
+                    transitionState = TransitionState.Idle(fromScene.key)
+                }
+            } else {
+                // We were between two scenes: animate to the initial scene.
+                animateTo(targetScene = fromScene, targetOffset = 0f)
+            }
         }
-
-        animateOffset(
-            initialVelocity = velocity,
-            targetOffset = targetOffset,
-            targetScene = targetScene.key
-        )
     }
 
     /**
@@ -378,74 +418,33 @@ class SceneGestureHandler(
         targetScene: SceneKey,
     ) {
         swipeTransition.startOffsetAnimation {
-            coroutineScope
-                .launch {
-                    if (!isAnimatingOffset) {
-                        swipeTransition.offsetAnimatable.snapTo(swipeTransition.dragOffset)
-                    }
-                    isAnimatingOffset = true
-
-                    swipeTransition.offsetAnimatable.animateTo(
-                        targetOffset,
-                        // TODO(b/290184746): Make this spring spec configurable.
-                        spring(
-                            stiffness = Spring.StiffnessMediumLow,
-                            visibilityThreshold = OffsetVisibilityThreshold
-                        ),
-                        initialVelocity = initialVelocity,
-                    )
-
-                    // Now that the animation is done, the state should be idle. Note that if the
-                    // state was changed since this animation started, some external code changed it
-                    // and we shouldn't do anything here. Note also that this job will be cancelled
-                    // in the case where the user intercepts this swipe.
-                    if (isDrivingTransition) {
-                        transitionState = TransitionState.Idle(targetScene)
-                    }
+            coroutineScope.launch {
+                if (!isAnimatingOffset) {
+                    swipeTransition.offsetAnimatable.snapTo(swipeTransition.dragOffset)
                 }
-                .also { it.invokeOnCompletion { isAnimatingOffset = false } }
-        }
-    }
-
-    internal fun animateOverscroll(velocity: Velocity): Velocity {
-        val velocityAmount =
-            when (orientation) {
-                Orientation.Vertical -> velocity.y
-                Orientation.Horizontal -> velocity.x
-            }
-
-        if (velocityAmount == 0f) {
-            // There is no remaining velocity
-            return Velocity.Zero
-        }
+                isAnimatingOffset = true
+
+                swipeTransition.offsetAnimatable.animateTo(
+                    targetOffset,
+                    // TODO(b/290184746): Make this spring spec configurable.
+                    spring(
+                        stiffness = Spring.StiffnessMediumLow,
+                        visibilityThreshold = OffsetVisibilityThreshold
+                    ),
+                    initialVelocity = initialVelocity,
+                )
 
-        val fromScene = currentScene
-        val target = fromScene.findTargetSceneAndDistance(velocityAmount)
-        val isValidTarget = target.distance != 0f && target.sceneKey != fromScene.key
+                isAnimatingOffset = false
 
-        if (!isValidTarget || isDrivingTransition) {
-            // We have not found a valid target or we are already in a transition
-            return Velocity.Zero
+                // Now that the animation is done, the state should be idle. Note that if the state
+                // was changed since this animation started, some external code changed it and we
+                // shouldn't do anything here. Note also that this job will be cancelled in the case
+                // where the user intercepts this swipe.
+                if (isDrivingTransition) {
+                    transitionState = TransitionState.Idle(targetScene)
+                }
+            }
         }
-
-        swipeTransition._currentScene = fromScene
-        swipeTransition._fromScene = fromScene
-        swipeTransition._toScene = layoutImpl.scene(target.sceneKey)
-        swipeTransition._distance = target.distance
-        swipeTransition.absoluteDistance = target.distance.absoluteValue
-        swipeTransition.stopOffsetAnimation()
-        swipeTransition.dragOffset = 0f
-
-        transitionState = swipeTransition
-
-        animateOffset(
-            initialVelocity = velocityAmount,
-            targetOffset = 0f,
-            targetScene = fromScene.key
-        )
-
-        // The animateOffset animation consumes any remaining velocity.
-        return velocity
     }
 
     private class SwipeTransition(initialScene: Scene) : TransitionState.Transition {
@@ -500,6 +499,11 @@ class SceneGestureHandler(
         /** Stops any ongoing offset animation. */
         fun stopOffsetAnimation() {
             offsetAnimationJob?.cancel()
+
+            if (isAnimatingOffset) {
+                isAnimatingOffset = false
+                dragOffset = offsetAnimatable.value
+            }
         }
 
         /** The absolute distance between [fromScene] and [toScene]. */
@@ -513,21 +517,31 @@ class SceneGestureHandler(
         val distance: Float
             get() = _distance
     }
+
+    companion object {
+        private const val TAG = "SceneGestureHandler"
+    }
 }
 
 private class SceneDraggableHandler(
     private val gestureHandler: SceneGestureHandler,
 ) : DraggableHandler {
     override suspend fun onDragStarted(coroutineScope: CoroutineScope, startedPosition: Offset) {
+        gestureHandler.gestureWithPriority = this
         gestureHandler.onDragStarted()
     }
 
     override fun onDelta(pixels: Float) {
-        gestureHandler.onDrag(delta = pixels)
+        if (gestureHandler.gestureWithPriority == this) {
+            gestureHandler.onDrag(delta = pixels)
+        }
     }
 
     override suspend fun onDragStopped(coroutineScope: CoroutineScope, velocity: Float) {
-        gestureHandler.onDragStopped(velocity = velocity, canChangeScene = true)
+        if (gestureHandler.gestureWithPriority == this) {
+            gestureHandler.gestureWithPriority = null
+            gestureHandler.onDragStopped(velocity = velocity, canChangeScene = true)
+        }
     }
 }
 
@@ -535,7 +549,7 @@ private class SceneDraggableHandler(
 class SceneNestedScrollHandler(
     private val gestureHandler: SceneGestureHandler,
 ) : NestedScrollHandler {
-    override val connection: PriorityPostNestedScrollConnection = nestedScrollConnection()
+    override val connection: PriorityNestedScrollConnection = nestedScrollConnection()
 
     private fun Offset.toAmount() =
         when (gestureHandler.orientation) {
@@ -555,7 +569,7 @@ class SceneNestedScrollHandler(
             Orientation.Vertical -> Offset(x = 0f, y = this)
         }
 
-    private fun nestedScrollConnection(): PriorityPostNestedScrollConnection {
+    private fun nestedScrollConnection(): PriorityNestedScrollConnection {
         // The next potential scene is calculated during the canStart
         var nextScene: SceneKey? = null
 
@@ -566,29 +580,58 @@ class SceneNestedScrollHandler(
         // moving on to the next scene.
         var gestureStartedOnNestedChild = false
 
-        return PriorityPostNestedScrollConnection(
-            canStart = { offsetAvailable, offsetBeforeStart ->
-                val amount = offsetAvailable.toAmount()
-                if (amount == 0f) return@PriorityPostNestedScrollConnection false
+        fun findNextScene(amount: Float): SceneKey? {
+            val fromScene = gestureHandler.currentScene
+            return when {
+                amount < 0f -> fromScene.upOrLeft(gestureHandler.orientation)
+                amount > 0f -> fromScene.downOrRight(gestureHandler.orientation)
+                else -> null
+            }
+        }
 
+        return PriorityNestedScrollConnection(
+            canStartPreScroll = { offsetAvailable, offsetBeforeStart ->
                 gestureStartedOnNestedChild = offsetBeforeStart != Offset.Zero
 
-                val fromScene = gestureHandler.currentScene
-                nextScene =
-                    when {
-                        amount < 0f -> fromScene.upOrLeft(gestureHandler.orientation)
-                        amount > 0f -> fromScene.downOrRight(gestureHandler.orientation)
-                        else -> null
-                    }
+                val canInterceptPreScroll =
+                    gestureHandler.isDrivingTransition &&
+                        !gestureStartedOnNestedChild &&
+                        offsetAvailable.toAmount() != 0f
+
+                if (!canInterceptPreScroll) return@PriorityNestedScrollConnection false
+
+                nextScene = gestureHandler.swipeTransitionToScene.key
 
+                true
+            },
+            canStartPostScroll = { offsetAvailable, offsetBeforeStart ->
+                val amount = offsetAvailable.toAmount()
+                if (amount == 0f) return@PriorityNestedScrollConnection false
+
+                gestureStartedOnNestedChild = offsetBeforeStart != Offset.Zero
+                nextScene = findNextScene(amount)
+                nextScene != null
+            },
+            canStartPostFling = { velocityAvailable ->
+                val amount = velocityAvailable.toAmount()
+                if (amount == 0f) return@PriorityNestedScrollConnection false
+
+                // We could start an overscroll animation
+                gestureStartedOnNestedChild = true
+                nextScene = findNextScene(amount)
                 nextScene != null
             },
             canContinueScroll = { priorityScene == gestureHandler.swipeTransitionToScene.key },
             onStart = {
+                gestureHandler.gestureWithPriority = this
                 priorityScene = nextScene
                 gestureHandler.onDragStarted()
             },
             onScroll = { offsetAvailable ->
+                if (gestureHandler.gestureWithPriority != this) {
+                    return@PriorityNestedScrollConnection Offset.Zero
+                }
+
                 val amount = offsetAvailable.toAmount()
 
                 // TODO(b/297842071) We should handle the overscroll or slow drag if the gesture is
@@ -598,6 +641,10 @@ class SceneNestedScrollHandler(
                 amount.toOffset()
             },
             onStop = { velocityAvailable ->
+                if (gestureHandler.gestureWithPriority != this) {
+                    return@PriorityNestedScrollConnection Velocity.Zero
+                }
+
                 priorityScene = null
 
                 gestureHandler.onDragStopped(
@@ -608,11 +655,6 @@ class SceneNestedScrollHandler(
                 // The onDragStopped animation consumes any remaining velocity.
                 velocityAvailable
             },
-            onPostFling = { velocityAvailable ->
-                // If there is any velocity left, we can try running an overscroll animation between
-                // scenes.
-                gestureHandler.animateOverscroll(velocity = velocityAvailable)
-            },
         )
     }
 }
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityPostNestedScrollConnection.kt b/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt
similarity index 74%
rename from packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityPostNestedScrollConnection.kt
rename to packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt
index 793a9a59405a26aaf238ac1422f096d3895b447b..824c10b88a9bd4d0c7d53e4216bbe4346dfbd779 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityPostNestedScrollConnection.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt
@@ -22,22 +22,23 @@ import androidx.compose.ui.input.nestedscroll.NestedScrollSource
 import androidx.compose.ui.unit.Velocity
 
 /**
- * This [NestedScrollConnection] waits for a child to scroll ([onPostScroll]), and then decides (via
- * [canStart]) if it should take over scrolling. If it does, it will scroll before its children,
- * until [canContinueScroll] allows it.
+ * This [NestedScrollConnection] waits for a child to scroll ([onPreScroll] or [onPostScroll]), and
+ * then decides (via [canStartPreScroll] or [canStartPostScroll]) if it should take over scrolling.
+ * If it does, it will scroll before its children, until [canContinueScroll] allows it.
  *
  * Note: Call [reset] before destroying this object to make sure you always get a call to [onStop]
  * after [onStart].
  *
  * @sample com.android.compose.animation.scene.rememberSwipeToSceneNestedScrollConnection
  */
-class PriorityPostNestedScrollConnection(
-    private val canStart: (offsetAvailable: Offset, offsetBeforeStart: Offset) -> Boolean,
+class PriorityNestedScrollConnection(
+    private val canStartPreScroll: (offsetAvailable: Offset, offsetBeforeStart: Offset) -> Boolean,
+    private val canStartPostScroll: (offsetAvailable: Offset, offsetBeforeStart: Offset) -> Boolean,
+    private val canStartPostFling: (velocityAvailable: Velocity) -> Boolean,
     private val canContinueScroll: () -> Boolean,
     private val onStart: () -> Unit,
     private val onScroll: (offsetAvailable: Offset) -> Offset,
     private val onStop: (velocityAvailable: Velocity) -> Velocity,
-    private val onPostFling: suspend (velocityAvailable: Velocity) -> Velocity,
 ) : NestedScrollConnection {
 
     /** In priority mode [onPreScroll] events are first consumed by the parent, via [onScroll]. */
@@ -57,26 +58,21 @@ class PriorityPostNestedScrollConnection(
         if (
             isPriorityMode ||
                 source == NestedScrollSource.Fling ||
-                !canStart(available, offsetBeforeStart)
+                !canStartPostScroll(available, offsetBeforeStart)
         ) {
             // The priority mode cannot start so we won't consume the available offset.
             return Offset.Zero
         }
 
-        // Step 1: It's our turn! We start capturing scroll events when one of our children has an
-        // available offset following a scroll event.
-        isPriorityMode = true
-
-        // Note: onStop will be called if we cannot continue to scroll (step 3a), or the finger is
-        // lifted (step 3b), or this object has been destroyed (step 3c).
-        onStart()
-
-        return onScroll(available)
+        return onPriorityStart(available)
     }
 
     override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
         if (!isPriorityMode) {
             if (source != NestedScrollSource.Fling) {
+                if (canStartPreScroll(available, offsetScrolledBeforePriorityMode)) {
+                    return onPriorityStart(available)
+                }
                 // We want to track the amount of offset consumed before entering priority mode
                 offsetScrolledBeforePriorityMode += available
             }
@@ -87,6 +83,11 @@ class PriorityPostNestedScrollConnection(
         if (!canContinueScroll()) {
             // Step 3a: We have lost priority and we no longer need to intercept scroll events.
             onPriorityStop(velocity = Velocity.Zero)
+
+            // We've just reset offsetScrolledBeforePriorityMode to Offset.Zero
+            // We want to track the amount of offset consumed before entering priority mode
+            offsetScrolledBeforePriorityMode += available
+
             return Offset.Zero
         }
 
@@ -101,7 +102,14 @@ class PriorityPostNestedScrollConnection(
     }
 
     override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity {
-        return onPostFling(available)
+        if (!canStartPostFling(available)) {
+            return Velocity.Zero
+        }
+
+        onPriorityStart(available = Offset.Zero)
+
+        // This is the last event of a scroll gesture.
+        return onPriorityStop(available)
     }
 
     /** Method to call before destroying the object or to reset the initial state. */
@@ -110,8 +118,23 @@ class PriorityPostNestedScrollConnection(
         onPriorityStop(velocity = Velocity.Zero)
     }
 
-    private fun onPriorityStop(velocity: Velocity): Velocity {
+    private fun onPriorityStart(available: Offset): Offset {
+        if (isPriorityMode) {
+            error("This should never happen, onPriorityStart() was called when isPriorityMode")
+        }
+
+        // Step 1: It's our turn! We start capturing scroll events when one of our children has an
+        // available offset following a scroll event.
+        isPriorityMode = true
+
+        // Note: onStop will be called if we cannot continue to scroll (step 3a), or the finger is
+        // lifted (step 3b), or this object has been destroyed (step 3c).
+        onStart()
 
+        return onScroll(available)
+    }
+
+    private fun onPriorityStop(velocity: Velocity): Velocity {
         // We can restart tracking the consumed offsets from scratch.
         offsetScrolledBeforePriorityMode = Offset.Zero
 
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt
index 3e0f7ba1bf789bb89c797948b610865d9552b0cc..6791a85ff21c2e41dc348ff3311171af5f70bb6b 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt
@@ -47,7 +47,7 @@ class SceneGestureHandlerTest {
             scene(SceneC) { Text("SceneC") }
         }
 
-        private val sceneGestureHandler =
+        val sceneGestureHandler =
             SceneGestureHandler(
                 layoutImpl =
                     SceneTransitionLayoutImpl(
@@ -81,6 +81,10 @@ class SceneGestureHandlerTest {
             coroutineScope.testScheduler.advanceUntilIdle()
         }
 
+        fun runCurrent() {
+            coroutineScope.testScheduler.runCurrent()
+        }
+
         fun assertScene(currentScene: SceneKey, isIdle: Boolean) {
             val idleMsg = if (isIdle) "MUST" else "MUST NOT"
             assertWithMessage("transitionState $idleMsg be Idle")
@@ -164,6 +168,33 @@ class SceneGestureHandlerTest {
         assertScene(currentScene = SceneA, isIdle = true)
     }
 
+    @Test
+    fun startGestureDuringAnimatingOffset_shouldImmediatelyStopTheAnimation() = runGestureTest {
+        draggable.onDragStarted(coroutineScope = coroutineScope, startedPosition = Offset.Zero)
+        assertScene(currentScene = SceneA, isIdle = false)
+
+        draggable.onDelta(pixels = deltaInPixels10)
+        assertScene(currentScene = SceneA, isIdle = false)
+
+        draggable.onDragStopped(
+            coroutineScope = coroutineScope,
+            velocity = velocityThreshold,
+        )
+
+        // The stop animation is not started yet
+        assertThat(sceneGestureHandler.isAnimatingOffset).isFalse()
+
+        runCurrent()
+
+        assertThat(sceneGestureHandler.isAnimatingOffset).isTrue()
+        assertThat(sceneGestureHandler.isDrivingTransition).isTrue()
+        assertScene(currentScene = SceneC, isIdle = false)
+
+        // Start a new gesture while the offset is animating
+        draggable.onDragStarted(coroutineScope = coroutineScope, startedPosition = Offset.Zero)
+        assertThat(sceneGestureHandler.isAnimatingOffset).isFalse()
+    }
+
     @Test
     fun onInitialPreScroll_doNotChangeState() = runGestureTest {
         nestedScroll.onPreScroll(available = offsetY10, source = NestedScrollSource.Drag)
@@ -281,4 +312,52 @@ class SceneGestureHandlerTest {
         advanceUntilIdle()
         assertScene(currentScene = SceneA, isIdle = true)
     }
+
+    @Test
+    fun beforeDraggableStart_drag_shouldBeIgnored() = runGestureTest {
+        draggable.onDelta(deltaInPixels10)
+        assertScene(currentScene = SceneA, isIdle = true)
+    }
+    @Test
+    fun beforeDraggableStart_stop_shouldBeIgnored() = runGestureTest {
+        draggable.onDragStopped(coroutineScope, velocityThreshold)
+        assertScene(currentScene = SceneA, isIdle = true)
+    }
+
+    @Test
+    fun beforeNestedScrollStart_stop_shouldBeIgnored() = runGestureTest {
+        nestedScroll.onPreFling(Velocity(0f, velocityThreshold))
+        assertScene(currentScene = SceneA, isIdle = true)
+    }
+
+    @Test
+    fun startNestedScrollWhileDragging() = runGestureTest {
+        draggable.onDragStarted(coroutineScope, Offset.Zero)
+        assertScene(currentScene = SceneA, isIdle = false)
+        val transition = transitionState as Transition
+
+        draggable.onDelta(deltaInPixels10)
+        assertThat(transition.progress).isEqualTo(0.1f)
+
+        // now we can intercept the scroll events
+        nestedScrollEvents(available = offsetY10)
+        assertThat(transition.progress).isEqualTo(0.2f)
+
+        // this should be ignored, we are scrolling now!
+        draggable.onDragStopped(coroutineScope, velocityThreshold)
+        assertScene(currentScene = SceneA, isIdle = false)
+
+        nestedScrollEvents(available = offsetY10)
+        assertThat(transition.progress).isEqualTo(0.3f)
+
+        nestedScrollEvents(available = offsetY10)
+        assertThat(transition.progress).isEqualTo(0.4f)
+
+        nestedScroll.onPreFling(available = Velocity(0f, velocityThreshold))
+        assertScene(currentScene = SceneC, isIdle = false)
+
+        // wait for the stop animation
+        advanceUntilIdle()
+        assertScene(currentScene = SceneC, isIdle = true)
+    }
 }
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityPostNestedScrollConnectionTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityNestedScrollConnectionTest.kt
similarity index 66%
rename from packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityPostNestedScrollConnectionTest.kt
rename to packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityNestedScrollConnectionTest.kt
index 8e2b77a2f2a0d45d55b1e868ad20fefd9dec16d8..122774bb28fe139e0950f113fb9a9ec2d7c214ff 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityPostNestedScrollConnectionTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityNestedScrollConnectionTest.kt
@@ -29,20 +29,22 @@ import org.junit.Test
 import org.junit.runner.RunWith
 
 @RunWith(AndroidJUnit4::class)
-class PriorityPostNestedScrollConnectionTest {
-    private var canStart = false
+class PriorityNestedScrollConnectionTest {
+    private var canStartPreScroll = false
+    private var canStartPostScroll = false
+    private var canStartPostFling = false
     private var canContinueScroll = false
     private var isStarted = false
     private var lastScroll: Offset? = null
     private var returnOnScroll = Offset.Zero
     private var lastStop: Velocity? = null
     private var returnOnStop = Velocity.Zero
-    private var lastOnPostFling: Velocity? = null
-    private var returnOnPostFling = Velocity.Zero
 
     private val scrollConnection =
-        PriorityPostNestedScrollConnection(
-            canStart = { _, _ -> canStart },
+        PriorityNestedScrollConnection(
+            canStartPreScroll = { _, _ -> canStartPreScroll },
+            canStartPostScroll = { _, _ -> canStartPostScroll },
+            canStartPostFling = { canStartPostFling },
             canContinueScroll = { canContinueScroll },
             onStart = { isStarted = true },
             onScroll = {
@@ -53,10 +55,6 @@ class PriorityPostNestedScrollConnectionTest {
                 lastStop = it
                 returnOnStop
             },
-            onPostFling = {
-                lastOnPostFling = it
-                returnOnPostFling
-            },
         )
 
     private val offset1 = Offset(1f, 1f)
@@ -64,8 +62,29 @@ class PriorityPostNestedScrollConnectionTest {
     private val velocity1 = Velocity(1f, 1f)
     private val velocity2 = Velocity(2f, 2f)
 
-    private fun startPriorityMode() {
-        canStart = true
+    @Test
+    fun step1_priorityModeShouldStartOnlyOnPreScroll() = runTest {
+        canStartPreScroll = true
+
+        scrollConnection.onPostScroll(
+            consumed = Offset.Zero,
+            available = Offset.Zero,
+            source = NestedScrollSource.Drag
+        )
+        assertThat(isStarted).isEqualTo(false)
+
+        scrollConnection.onPreFling(available = Velocity.Zero)
+        assertThat(isStarted).isEqualTo(false)
+
+        scrollConnection.onPostFling(consumed = Velocity.Zero, available = Velocity.Zero)
+        assertThat(isStarted).isEqualTo(false)
+
+        scrollConnection.onPreScroll(available = Offset.Zero, source = NestedScrollSource.Drag)
+        assertThat(isStarted).isEqualTo(true)
+    }
+
+    private fun startPriorityModePostScroll() {
+        canStartPostScroll = true
         scrollConnection.onPostScroll(
             consumed = Offset.Zero,
             available = Offset.Zero,
@@ -75,7 +94,7 @@ class PriorityPostNestedScrollConnectionTest {
 
     @Test
     fun step1_priorityModeShouldStartOnlyOnPostScroll() = runTest {
-        canStart = true
+        canStartPostScroll = true
 
         scrollConnection.onPreScroll(available = Offset.Zero, source = NestedScrollSource.Drag)
         assertThat(isStarted).isEqualTo(false)
@@ -86,7 +105,7 @@ class PriorityPostNestedScrollConnectionTest {
         scrollConnection.onPostFling(consumed = Velocity.Zero, available = Velocity.Zero)
         assertThat(isStarted).isEqualTo(false)
 
-        startPriorityMode()
+        startPriorityModePostScroll()
         assertThat(isStarted).isEqualTo(true)
     }
 
@@ -99,13 +118,13 @@ class PriorityPostNestedScrollConnectionTest {
         )
         assertThat(isStarted).isEqualTo(false)
 
-        startPriorityMode()
+        startPriorityModePostScroll()
         assertThat(isStarted).isEqualTo(true)
     }
 
     @Test
     fun step1_onPriorityModeStarted_receiveAvailableOffset() {
-        canStart = true
+        canStartPostScroll = true
 
         scrollConnection.onPostScroll(
             consumed = offset1,
@@ -118,7 +137,7 @@ class PriorityPostNestedScrollConnectionTest {
 
     @Test
     fun step2_onPriorityMode_shouldContinueIfAllowed() {
-        startPriorityMode()
+        startPriorityModePostScroll()
         canContinueScroll = true
 
         scrollConnection.onPreScroll(available = offset1, source = NestedScrollSource.Drag)
@@ -132,7 +151,7 @@ class PriorityPostNestedScrollConnectionTest {
 
     @Test
     fun step3a_onPriorityMode_shouldStopIfCannotContinue() {
-        startPriorityMode()
+        startPriorityModePostScroll()
         canContinueScroll = false
 
         scrollConnection.onPreScroll(available = Offset.Zero, source = NestedScrollSource.Drag)
@@ -142,7 +161,7 @@ class PriorityPostNestedScrollConnectionTest {
 
     @Test
     fun step3b_onPriorityMode_shouldStopOnFling() = runTest {
-        startPriorityMode()
+        startPriorityModePostScroll()
         canContinueScroll = true
 
         scrollConnection.onPreFling(available = Velocity.Zero)
@@ -152,7 +171,7 @@ class PriorityPostNestedScrollConnectionTest {
 
     @Test
     fun step3c_onPriorityMode_shouldStopOnReset() {
-        startPriorityMode()
+        startPriorityModePostScroll()
         canContinueScroll = true
 
         scrollConnection.reset()
@@ -162,11 +181,34 @@ class PriorityPostNestedScrollConnectionTest {
 
     @Test
     fun receive_onPostFling() = runTest {
+        canStartPostFling = true
+
         scrollConnection.onPostFling(
             consumed = velocity1,
             available = velocity2,
         )
 
-        assertThat(lastOnPostFling).isEqualTo(velocity2)
+        assertThat(lastStop).isEqualTo(velocity2)
+    }
+
+    @Test
+    fun step1_priorityModeShouldStartOnlyOnPostFling() = runTest {
+        canStartPostFling = true
+
+        scrollConnection.onPreScroll(available = Offset.Zero, source = NestedScrollSource.Drag)
+        assertThat(isStarted).isEqualTo(false)
+
+        scrollConnection.onPostScroll(
+            consumed = Offset.Zero,
+            available = Offset.Zero,
+            source = NestedScrollSource.Drag
+        )
+        assertThat(isStarted).isEqualTo(false)
+
+        scrollConnection.onPreFling(available = Velocity.Zero)
+        assertThat(isStarted).isEqualTo(false)
+
+        scrollConnection.onPostFling(consumed = Velocity.Zero, available = Velocity.Zero)
+        assertThat(isStarted).isEqualTo(true)
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt
diff --git a/packages/SystemUI/multivalentTestsForDevice b/packages/SystemUI/multivalentTestsForDevice
new file mode 120000
index 0000000000000000000000000000000000000000..20ee34ada103e06db73c8bee179207299f17e032
--- /dev/null
+++ b/packages/SystemUI/multivalentTestsForDevice
@@ -0,0 +1 @@
+multivalentTests
\ No newline at end of file
diff --git a/packages/SystemUI/multivalentTestsForDeviceless b/packages/SystemUI/multivalentTestsForDeviceless
new file mode 120000
index 0000000000000000000000000000000000000000..20ee34ada103e06db73c8bee179207299f17e032
--- /dev/null
+++ b/packages/SystemUI/multivalentTestsForDeviceless
@@ -0,0 +1 @@
+multivalentTests
\ No newline at end of file
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
index 9cc87fde122f82345a69179c790f7fd2083cfee7..f0e3c99b007d68f4424fd78efff3c5360f57328f 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
@@ -56,6 +56,16 @@ public interface ActivityStarter {
             Runnable intentSentUiThreadCallback,
             @Nullable ActivityLaunchAnimator.Controller animationController);
 
+    /**
+     * Similar to {@link #startPendingIntentDismissingKeyguard}, except that it supports launching
+     * activities on top of the keyguard. If the activity supports {@code showOverLockscreen}, it
+     * will show over keyguard without first dimissing it. If it doesn't support it, calling this
+     * method is exactly the same as calling {@link #startPendingIntentDismissingKeyguard}.
+     */
+    void startPendingIntentMaybeDismissingKeyguard(PendingIntent intent,
+            @Nullable Runnable intentSentUiThreadCallback,
+            @Nullable ActivityLaunchAnimator.Controller animationController);
+
     /**
      * The intent flag can be specified in startActivity().
      */
diff --git a/packages/SystemUI/res-keyguard/values-af/strings.xml b/packages/SystemUI/res-keyguard/values-af/strings.xml
index 2eb1bb5dd941b8be597b89215fec971b3ab1f7b6..a6a81222a8cbb63248320126ec5476a830dafb60 100644
--- a/packages/SystemUI/res-keyguard/values-af/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-af/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Laai tans stadig"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Laaiproses word geoptimeer om battery te beskerm"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Kwessie met laaibykomstigheid"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Druk Kieslys om te ontsluit."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Netwerk is gesluit"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Geen SIM nie"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Voeg ’n SIM by."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"Die SIM is weg of nie leesbaar nie. Voeg ’n SIM by."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Onbruikbare SIM."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"Jou SIM is permanent gedeaktiveer.\n Kontak jou draadlose diensverskaffer vir ’n ander SIM."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM is gesluit."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM is PUK-gesluit."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Ontsluit tans SIM …"</string>
diff --git a/packages/SystemUI/res-keyguard/values-am/strings.xml b/packages/SystemUI/res-keyguard/values-am/strings.xml
index 5fd946b1f188f98e9c4010c0e0d69857cde98b19..fb84414c19df332b4d7ad3c6f506ca15fc9d28c2 100644
--- a/packages/SystemUI/res-keyguard/values-am/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-am/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"ምንም SIM የለም"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"ሲም ያክሉ።"</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"ሲሙ ጠፍቷል ወይም አይነበብም። ሲም ያክሉ።"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"ጥቅም ላይ የማይውል ሲም።"</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"ሲምዎ በቋሚነት ቦዝኗል።\n ለሌላ ሲም የእርስዎን አገልግሎት ሰጪ ያግኙ።"</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"ሲም ተቆልፏል።"</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"ሲም በPUK የተቆለፈ ነው።"</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"ሲምን በመክፈት ላይ…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ar/strings.xml b/packages/SystemUI/res-keyguard/values-ar/strings.xml
index b6479f456a2fb65013a46db57eb169091314ec59..fb330929f4d37b6ea533a5d0a076267639d1cf89 100644
--- a/packages/SystemUI/res-keyguard/values-ar/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ar/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"‫<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="685029586173458728">"‏لا تتوفر شريحة SIM."</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"‏يجب إضافة شريحة SIM."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"‏شريحة SIM مفقودة أو غير قابلة للقراءة. يجب إضافة شريحة SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"‏شريحة SIM غير قابلة للاستخدام."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"‏تم إيقاف شريحة SIM نهائيًا.\n عليك التواصل مع مقدم خدمة اللاسلكي للحصول على شريحة SIM أخرى."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"‏شريحة SIM مُقفَلة."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"‏شريحة SIM مُقفَلة برمز PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"‏جارٍ إلغاء قفل شريحة SIM…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-as/strings.xml b/packages/SystemUI/res-keyguard/values-as/strings.xml
index a41a704f345ac853d1c3fc90c16dbae294f686fa..a123bb7957088db0c01302f23f6e90f0a30dba9a 100644
--- a/packages/SystemUI/res-keyguard/values-as/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-as/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"কোনো ছিম নাই"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"এখন ছিম যোগ দিয়ক।"</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"ছিম নাই অথবা সেইখন পঢ়িব নোৱাৰি। এখন ছিম যোগ দিয়ক।"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"ব্যৱহাৰ কৰিব নোৱৰা ছিম।"</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"আপোনাৰ ছিমখন স্থায়ীভাৱে নিষ্ক্ৰিয় কৰা হৈছে।\n অন্য এখন ছিমৰ বাবে আপোনাৰ ৱায়াৰলেছ সেৱা প্ৰদানকাৰীৰ সৈতে যোগাযোগ কৰক।"</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"ছিমখন লক হৈ আছে।"</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"ছিমখন PUKৰ দ্বাৰা লক হৈ আছে।"</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"ছিম আনলক কৰি থকা হৈছে…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-az/strings.xml b/packages/SystemUI/res-keyguard/values-az/strings.xml
index ed969c7c8e292288e1ad73be3ded2e2a7703fd9d..b133b30a657c3e5ba209ea0ebe3ef09d283f18ae 100644
--- a/packages/SystemUI/res-keyguard/values-az/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-az/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Yavaş enerji yığır"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Batareyanı qorumaq üçün şarj optimallaşdırılıb"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Şarj aksesuarı ilə bağlı problem"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Kilidi açmaq üçün Menyu düyməsinə basın."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Şəbəkə kilidlidir"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM yoxdur"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"SIM əlavə edin."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM kart yoxdur və ya oxuna bilinmir. SIM əlavə edin."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"İstifadəyə yararsız SIM."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"SIM kartınız həmişəlik deaktiv edilib.\n Başqa SIM kart üçün simsiz xidmət provayderinizə müraciət edin."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM kilidlənib."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM kart PUK ilə kilidlənib."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"SIM kiliddən çıxarılır…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
index b0a6471994160a4c21bec182a18dfe135a51c757..9a919624c4fac147110570ecb13125bda0fb903e 100644
--- a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Sporo se puni"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Punjenje je optimizovano da bi se zaštitila baterija"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Problem sa dodatnim priborom za punjenje"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Pritisnite Meni da biste otključali."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Mreža je zaključana"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Nema SIM-a"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Dodajte SIM."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM nedostaje ili ne može da se pročita. Dodajte SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Neupotrebljiv SIM."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"SIM je trajno deaktiviran.\n Obratite se dobavljaču usluge bežične telefonije da biste dobili drugi SIM."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM je zaključan."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM je zaključan PUK-om."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Otključava se SIM…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-be/strings.xml b/packages/SystemUI/res-keyguard/values-be/strings.xml
index 11cc77dca5daaf314357c28b847127c2156867c9..5e46b715c0e3f67402212db37340bec5cdcfeb43 100644
--- a/packages/SystemUI/res-keyguard/values-be/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-be/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"Няма SIM-карты"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Дадайце SIM-карту."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM-карта адсутнічае ці не чытаецца. Дадайце SIM-карту."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Непрыдатная для выкарыстання SIM-карта."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"Ваша SIM-карта адключана назаўсёды.\n Звяжыцеся з аператарам бесправадной сувязі, каб атрымаць іншую SIM-карту."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM-карта заблакіравана."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM-карта заблакіравана PUK-кодам."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Разблакіраванне SIM-карты…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-bg/strings.xml b/packages/SystemUI/res-keyguard/values-bg/strings.xml
index c554a274f4665e570ca9195edd4ab11ffe92f5cc..ab931ede75b04e2ffe635730e7a0fad7939d9da9 100644
--- a/packages/SystemUI/res-keyguard/values-bg/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bg/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"Няма SIM карта"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Добавете SIM карта."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM картата липсва или е нечетлива. Добавете SIM карта."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Неизползваема SIM карта."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"SIM картата ви е деактивирана за постоянно.\nЗа да получите друга, се свържете с доставчика си на безжична услуга."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM картата е заключена."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM картата е заключена с PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"SIM картата се отключва…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-bn/strings.xml b/packages/SystemUI/res-keyguard/values-bn/strings.xml
index 67b4e4bc322b875fb3f46d8af821654f9d304698..e25de9318f5dd69ad192a52ae5499db836136e90 100644
--- a/packages/SystemUI/res-keyguard/values-bn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bn/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"কোনও সিম নেই"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"সিম যোগ করুন।"</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"সিম নেই অথবা সেটি রিড করা যাচ্ছে না। সিম যোগ করুন।"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"ব্যবহারযোগ্য নয় এমন সিম।"</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"আপনার সিম স্থায়ীভাবে বন্ধ করে দেওয়া হয়েছে।\n অন্য একটি সিমের জন্য আপনার ওয়্যারলেস পরিষেবা প্রদানকারীর সাথে যোগাযোগ করুন।"</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"সিম লক করা হয়েছে।"</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"সিম PUK লক করা হয়েছে।"</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"সিম আনলক করা হচ্ছে…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-bs/strings.xml b/packages/SystemUI/res-keyguard/values-bs/strings.xml
index 4c519c8d53628f20b1e194e233bc6531c04c793a..cd7aaeb8117a4b59981907d19d03b854c09b81b9 100644
--- a/packages/SystemUI/res-keyguard/values-bs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bs/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Sporo punjenje"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Punjenje je optimizirano radi zaštite baterije"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Problem s opremom za punjenje"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Pritisnite meni da otključate."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Mreža je zaključana"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Nema SIM-a"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Dodajte SIM."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM nedostaje ili se ne može čitati. Dodajte SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Neupotrebljiv SIM."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"SIM je trajno deaktiviran.\n Kontaktirajte pružaoca bežičnih usluga za drugi SIM"</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM je zaključan."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM je zaključan PUK-om."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Otključavanje SIM-a…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ca/strings.xml b/packages/SystemUI/res-keyguard/values-ca/strings.xml
index 3bd65083d810cd7e7017df652815b71aa0d6e47c..bf8a592c27b9855e3b99bdce4e37f22032847188 100644
--- a/packages/SystemUI/res-keyguard/values-ca/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ca/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • S\'està carregant lentament"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Càrrega optimitzada per protegir la bateria"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Problema relacionat amb l\'accessori de càrrega"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Prem Menú per desbloquejar."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"La xarxa està bloquejada"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"No hi ha cap SIM"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Afegeix una SIM."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"Falta la SIM o no es pot llegir. Afegeix una SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"La SIM no es pot utilitzar."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"La SIM s\'ha desactivat permanentment.\n Contacta amb el proveïdor de serveis sense fil per obtenir-ne una altra."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"La SIM està bloquejada."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"La SIM està bloquejada pel PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"S\'està desbloquejant la targeta SIM…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-cs/strings.xml b/packages/SystemUI/res-keyguard/values-cs/strings.xml
index 573638bcc135242d35e5124c2a6c2595d22ba25a..bedafd8dd3b8fd07f72dd35e44ccd3f34c534b1c 100644
--- a/packages/SystemUI/res-keyguard/values-cs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-cs/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Pomalé nabíjení"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Optimalizované nabíjení za účelem ochrany baterie"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Problém s nabíjecím příslušenstvím"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Klávesy odemknete stisknutím tlačítka nabídky."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Síť je blokována"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Žádná SIM karta"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Přidejte SIM kartu."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM karta chybí nebo je nečitelná. Přidejte SIM kartu."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM kartu nelze použít."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"SIM karta byla natrvalo deaktivována.\n Požádejte svého poskytovatele bezdrátových služeb o další SIM kartu."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM karta je zablokována."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM karta je blokována pomocí kódu PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Odblokování SIM karty…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-da/strings.xml b/packages/SystemUI/res-keyguard/values-da/strings.xml
index c7c863b70336cb92e38f45084511cc6296cf90fa..93f505e8bbf295af08dc6da2281e61418c6b4dc2 100644
--- a/packages/SystemUI/res-keyguard/values-da/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-da/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Oplader langsomt"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Opladning er optimeret for at beskytte batteriet"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Problem med opladertilbehør"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Tryk på menuen for at låse op."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Netværket er låst"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Intet SIM-kort"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Tilføj et SIM-kort."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM-kortet mangler eller kan ikke læses. Tilføj et SIM-kort."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Deaktiveret SIM-kort."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"Dit SIM-kort er permanent deaktiveret.\n Kontakt din tjenesteudbyder for at få et nyt SIM-kort."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM-kortet er låst."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM-kortet er låst med PUK-koden."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"SIM-kortet låses op…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-de/strings.xml b/packages/SystemUI/res-keyguard/values-de/strings.xml
index 5c5f264fe508f5132b936281c725217802fffb70..01e166e36559600eaaab7479ad82ce7a06dc08c1 100644
--- a/packages/SystemUI/res-keyguard/values-de/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-de/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Wird langsam geladen"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Optimiertes Laden zur Akkuschonung"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Problem mit dem Ladezubehör"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Zum Entsperren die Menütaste drücken."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Netzwerk gesperrt"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Keine SIM-Karte"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Lege eine SIM-Karte ein."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM-Karte fehlt oder ist nicht lesbar. Lege eine SIM-Karte ein."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM-Karte ist nicht nutzbar."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"Deine SIM-Karte wurde dauerhaft deaktiviert.\n Wende dich an deinen Mobilfunkanbieter, um eine andere SIM-Karte zu erhalten."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM-Karte ist gesperrt."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM-Karte ist mit einem PUK gesperrt."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"SIM-Karte wird entsperrt…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-el/strings.xml b/packages/SystemUI/res-keyguard/values-el/strings.xml
index 3a01da53dfce03e55b92f95c29da0251a2739d1d..97692424cf2cc4b68132c21317d4b36b3bc7a11b 100644
--- a/packages/SystemUI/res-keyguard/values-el/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-el/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"Δεν υπάρχει SIM"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Προσθέστε μια SIM."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"Η SIM λείπει ή δεν είναι δυνατή η ανάγνωσή της. Προσθέστε μια SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Η SIM δεν μπορεί να χρησιμοποιηθεί."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"Η SIM απενεργοποιήθηκε οριστικά.\n Επικοινωνήστε με τον πάροχο υπηρεσιών ασύρματου δικτύου για μια νέα SIM."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"Η SIM είναι κλειδωμένη."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"Η SIM έχει κλειδωθεί με κωδικό PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Ξεκλείδωμα SIM…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
index a4b13487b3e1d85bc2e2591d0009e531f8f58fc7..087ab3a793584fd83a77d85f2dcba7d6c3cb9e7d 100644
--- a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Charging slowly"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Charging optimised to protect battery"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Issue with charging accessory"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Press Menu to unlock."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Network locked"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"No SIM"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Add a SIM."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"The SIM is missing or not readable. Add a SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Unusable SIM."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"Your SIM has been permanently deactivated.\n Contact your wireless service provider for another SIM."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM is locked."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM is PUK-locked."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Unlocking SIM…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
index 480bcbb61954044d8c186a6dd7dae530565da746..7297cf929e2fd49fc05f78198e8557069ab28d67 100644
--- a/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Charging slowly"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Charging optimized to protect battery"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Issue with charging accessory"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Press Menu to unlock."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Network locked"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"No SIM"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Add a SIM."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"The SIM is missing or not readable. Add a SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Unusable SIM."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"Your SIM has been permanently deactivated.\n Contact your wireless service provider for another SIM."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM is locked."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM is PUK-locked."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Unlocking SIM…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
index a4b13487b3e1d85bc2e2591d0009e531f8f58fc7..087ab3a793584fd83a77d85f2dcba7d6c3cb9e7d 100644
--- a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Charging slowly"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Charging optimised to protect battery"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Issue with charging accessory"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Press Menu to unlock."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Network locked"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"No SIM"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Add a SIM."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"The SIM is missing or not readable. Add a SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Unusable SIM."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"Your SIM has been permanently deactivated.\n Contact your wireless service provider for another SIM."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM is locked."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM is PUK-locked."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Unlocking SIM…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
index a4b13487b3e1d85bc2e2591d0009e531f8f58fc7..087ab3a793584fd83a77d85f2dcba7d6c3cb9e7d 100644
--- a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Charging slowly"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Charging optimised to protect battery"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Issue with charging accessory"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Press Menu to unlock."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Network locked"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"No SIM"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Add a SIM."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"The SIM is missing or not readable. Add a SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Unusable SIM."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"Your SIM has been permanently deactivated.\n Contact your wireless service provider for another SIM."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM is locked."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM is PUK-locked."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Unlocking SIM…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml b/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml
index b8e89f4e334f72f91c2da2c0808aa43f1535880d..ead8bce626b82db0fa79bd1bbce8928f2e79fe80 100644
--- a/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‎‎‎‎‏‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‏‏‎‏‎‏‏‎‎‎‏‎‎‏‎‎‏‎‏‏‏‏‎‏‏‏‎‏‎‎‏‎‎‎‏‎‎‏‏‎<xliff:g id="PERCENTAGE">%s</xliff:g>‎‏‎‎‏‏‏‎ • Charging slowly‎‏‎‎‏‎"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‎‎‏‏‏‎‏‎‏‏‏‏‎‎‎‏‎‏‎‎‎‎‎‏‎‏‏‎‎‏‎‎‏‎‏‎‎‎‏‎‎‎‏‏‏‎‎‎‎‎‏‎‏‏‎‎‎‏‎‎‏‏‎<xliff:g id="PERCENTAGE">%s</xliff:g>‎‏‎‎‏‏‏‎ • Charging optimized to protect battery‎‏‎‎‏‎"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‎‏‏‏‎‎‏‎‎‎‏‎‏‏‎‏‏‏‎‎‎‎‎‎‏‏‏‏‎‎‏‎‎‏‏‏‏‎‎‏‎‏‏‎‎‎‏‎‎‎‏‎‎‎‎‏‎‎‏‏‎<xliff:g id="PERCENTAGE">%s</xliff:g>‎‏‎‎‏‏‏‎ • Issue with charging accessory‎‏‎‎‏‎"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‎‎‎‎‎‏‎‏‏‏‎‏‎‏‎‎‎‏‏‎‏‎‏‏‎‏‏‎‎‎‏‏‎‎‎‏‎‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎Press Menu to unlock.‎‏‎‎‏‎"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‏‏‎‏‎‎‏‏‎‎‏‎‎‏‎‏‏‏‏‏‎‏‎‏‏‏‏‏‎‎‏‎‎‎‏‏‎‎‏‎‏‏‎‎‏‎‏‎‎‎‎‎‎‎‎‎‎‎Network locked‎‏‎‎‏‎"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‏‎‎‎‎‎‎‏‏‎‏‏‎‏‏‎‏‏‎‎‎‏‏‏‎‏‏‏‏‎‎‎‏‎‎‎‎‎‎‎‎‏‏‏‏‎‎‏‎‎‏‎‏‎‎‎‎No SIM‎‏‎‎‏‎"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‎‏‏‎‎‏‏‎‎‎‎‏‎‏‎‎‎‎‏‎‎‎‎‎‎‏‏‎‏‎‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‏‎‏‏‏‏‏‎‎Add a SIM.‎‏‎‎‏‎"</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‏‏‏‏‎‎‏‏‎‎‎‎‏‎‎‏‏‎‏‎‎‎‎‏‎‎‎‎‏‎‎‏‏‏‏‎‏‎‏‎‏‏‏‎‎‎‏‏‎‏‎‎‏‏‏‎‎‎The SIM is missing or not readable. Add a SIM.‎‏‎‎‏‎"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‎‏‏‏‎‎‎‏‏‎‎‏‎‏‎‏‏‎‏‎‎‎‎‎‎‏‎‎‏‏‎‎‏‏‎‎‏‎‏‎‏‏‎‎‏‎‏‏‎‎‎‎‏‎‏‎‎‎Unusable SIM.‎‏‎‎‏‎"</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‎‏‏‏‏‎‏‎‎‏‏‏‎‏‏‏‏‎‎‏‎‎‏‏‏‎‏‏‏‎‎‎‏‎‏‎‏‎‏‏‏‎‎‎‏‎‎‏‏‏‎‏‎‎‎Your SIM has been permanently deactivated.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎ Contact your wireless service provider for another SIM.‎‏‎‎‏‎"</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‏‎‏‏‏‏‎‎‎‏‎‏‏‏‎‎‏‏‏‏‏‎‏‏‎‎‎‎‎‏‏‏‎‏‎‏‎‏‏‏‎‏‎‏‏‏‏‏‎‎‏‏‎‎SIM is locked.‎‏‎‎‏‎"</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‎‏‎‏‏‏‏‎‏‏‏‏‏‎‏‏‎‏‏‎‎‏‎‏‎‎‎‎‎‏‎‏‏‎‎‏‎‎‎‏‏‏‏‏‎‎‏‏‎‎‎‎‏‏‏‏‎‎SIM is PUK-locked.‎‏‎‎‏‎"</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‎‏‏‏‏‎‏‎‏‎‎‎‎‏‏‎‎‏‎‎‎‏‏‎‎‏‏‏‏‎‎‎‏‎‏‎‏‎‎‏‏‏‏‏‎‏‏‏‎‏‎‏‏‎Unlocking SIM…‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
index debbeb127c2f2916b5ca18820b7ba304b566bc51..5b82c443ff6250d54621c61927807b8463a40aec 100644
--- a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando lentamente"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carga optimizada para proteger la batería"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Problema con el accesorio de carga"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Presiona Menú para desbloquear."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Bloqueada para la red"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"No hay ninguna tarjeta SIM"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Introduce una tarjeta SIM."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"Falta la tarjeta SIM o no se puede leer. Introduce una tarjeta SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Tarjeta SIM inutilizable."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"Tu tarjeta SIM se desactivó permanentemente.\n Ponte en contacto con tu proveedor de servicios inalámbricos para obtener otra tarjeta SIM."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"La tarjeta SIM está bloqueada."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"La tarjeta SIM está bloqueada con el código PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Desbloqueando tarjeta SIM…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-es/strings.xml b/packages/SystemUI/res-keyguard/values-es/strings.xml
index 0ea98a8be752f01d66d21de3b51f90e25559a9cc..cf7f3d220443ec63bb814f141c368fc8640c89b1 100644
--- a/packages/SystemUI/res-keyguard/values-es/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-es/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando lentamente"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carga optimizada para proteger la batería"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Problema con el accesorio de carga"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Pulsa el menú para desbloquear la pantalla."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Bloqueada para la red"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"No hay ninguna SIM."</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Añade una SIM."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"Falta la SIM o no se puede leer. Añade una SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"No se puede usar la SIM."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"Tu SIM se ha desactivado de forma permanente.\n Para obtener otra SIM, ponte en contacto con tu proveedor de servicios inalámbricos."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"La SIM está bloqueada."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"La SIM está bloqueada con el código PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Desbloqueando SIM…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-et/strings.xml b/packages/SystemUI/res-keyguard/values-et/strings.xml
index 722a02237b3d1e17a2d0cbbc051462e5dc8c16c3..6335ca84c75dfbba5cde3b461f113445f340dcc3 100644
--- a/packages/SystemUI/res-keyguard/values-et/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-et/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Aeglane laadimine"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Laadimine on aku kaitsmiseks optimeeritud"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • probleem laadimistarvikuga"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Vajutage avamiseks menüüklahvi."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Võrk on lukus"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM-i pole"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Lisage SIM."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM puudub või pole loetav. Lisage SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM-i ei saa kasutada."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"Teie SIM on jäädavalt inaktiveeritud.\n Teise SIM-i saamiseks võtke ühendust oma traadita side teenusepakkujaga."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM on lukustatud."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM on PUK-koodiga lukustatud."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"SIM-i avamine …"</string>
diff --git a/packages/SystemUI/res-keyguard/values-eu/strings.xml b/packages/SystemUI/res-keyguard/values-eu/strings.xml
index d3293696ec58efc021c6fb86a68de22825bfad64..b47c58a770aa45c72ae714e52b946dd839aa15f4 100644
--- a/packages/SystemUI/res-keyguard/values-eu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-eu/strings.xml
@@ -35,13 +35,9 @@
     <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> • Bateria ez kaltetzeko, kargatzeko modua optimizatu da"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Arazo bat dago kargatzeko osagarriarekin"</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="685029586173458728">"Ez dago SIMik"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Gehitu SIM bat."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIMa falta da, edo ezin da irakurri. Gehitu SIM bat."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Ezin da erabili SIMa."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"Betiko desaktibatu da SIMa.\n Jarri operadorearekin harremanetan beste SIM bat eskuratzeko."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIMa blokeatuta dago."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIMa PUKaren bidez desblokeatu behar da."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"SIMa desblokeatzen…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-fa/strings.xml b/packages/SystemUI/res-keyguard/values-fa/strings.xml
index ae3f04a290e4348bdcaa8fbbb5353645af5bd4ae..f274f5fd7a5755047453097edc047f1640010ee7 100644
--- a/packages/SystemUI/res-keyguard/values-fa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fa/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"سیم‌کارتی وجود ندارد"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"سیم‌کارت اضافه کنید."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"سیم‌کارت موجود نیست یا قابل‌خواندن نیست. سیم‌کارت اضافه کنید."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"سیم‌کارت قابل‌استفاده نیست."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"سیم‌کارت شما برای همیشه غیرفعال شده است.\n برای دریافت سیم‌کارتی دیگر، با رساننده خدمات بی‌سیم خود تماس بگیرید."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"سیم‌کارت قفل است."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"‏سیم‌کارت با کد PUK قفل شده است."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"درحال باز کردن قفل سیم‌کارت…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-fi/strings.xml b/packages/SystemUI/res-keyguard/values-fi/strings.xml
index 050df9983725d890997b1fdeabacb98c50dd2f19..dd9ce2e4453f39e1b76ac9a59236c01b49241606 100644
--- a/packages/SystemUI/res-keyguard/values-fi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fi/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ladataan hitaasti"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Lataus optimoitu akun suojaamiseksi"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ongelma laturin kanssa"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Poista lukitus painamalla Valikkoa."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Verkko lukittu"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Ei SIM-korttia"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Lisää SIM-kortti."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM-korttia ei löydy tai ei voi lukea. Lisää SIM-kortti."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM-korttia ei voi käyttää."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"Sim-kortti on poistettu käytöstä pysyvästi.\n Ota yhteyttä langattoman palvelun tarjoajaan ja pyydä uusi SIM-kortti."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM-kortti on lukittu."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM-kortti on lukittu PUK-koodilla."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"SIM-kortin lukitusta avataan…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
index fa1a191b8944c4226903592e07114cd1026347fc..742f56e7f214855cb0606df61183669e69366f8e 100644
--- a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"En recharge lente : <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Recharge optimisée pour protéger la pile"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Problème concernant l\'accessoire de recharge"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Appuyez sur la touche Menu pour déverrouiller l\'appareil."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Réseau verrouillé"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Aucune carte SIM"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Ajouter une carte SIM."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"La carte SIM est manquante ou illisible. Ajouter une carte SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"La carte SIM est inutilisable."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"Votre carte SIM a été désactivée de manière permanente.\n Communiquez avec votre fournisseur de services sans fil pour obtenir une autre carte SIM."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"La carte SIM est verrouillée."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"La carte SIM est verrouillée par clé PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Déverrouillage de la carte SIM en cours…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-fr/strings.xml b/packages/SystemUI/res-keyguard/values-fr/strings.xml
index d687a1d7e9a24ff54c0cc5b6eae609851a29afe6..92d24c4bbc2819e4d266768fc6de9ca0d516b74b 100644
--- a/packages/SystemUI/res-keyguard/values-fr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Recharge lente"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Recharge optimisée pour protéger la batterie"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Problème de recharge de l\'accessoire"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Appuyez sur \"Menu\" pour déverrouiller le clavier."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Réseau verrouillé"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Aucune SIM"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Ajoutez une SIM."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"La SIM est absente ou illisible. Ajoutez une SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM inutilisable."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"Votre SIM a été désactivée définitivement.\n Contactez votre opérateur de téléphonie mobile pour en obtenir une autre."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM verrouillée."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM verrouillée par clé PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Déblocage de la SIM…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-gl/strings.xml b/packages/SystemUI/res-keyguard/values-gl/strings.xml
index 68f22cb262f7cd82fdc1e7fc04e6d5414540a08a..4837de2139ac598610570b795e43843e8d2fa462 100644
--- a/packages/SystemUI/res-keyguard/values-gl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gl/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando lentamente"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carga optimizada para protexer a batería"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Problema co accesorio de carga"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Preme Menú para desbloquear."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Bloqueada pola rede"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Non hai ningunha SIM"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Engade unha SIM."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"A SIM falta ou non se pode ler. Engade unha."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"A SIM non se pode usar."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"A SIM desactivouse permanentemente.\n Ponte en contacto co teu fornecedor de servizos sen fíos para conseguir outra."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"A SIM está bloqueada."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"A SIM está bloqueada mediante PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Desbloqueando SIM…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-gu/strings.xml b/packages/SystemUI/res-keyguard/values-gu/strings.xml
index 99c98836325660fea7b79075bc15880e8138a7e8..7f8c6d824f934f2058f7ab549286d66d56cbee65 100644
--- a/packages/SystemUI/res-keyguard/values-gu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gu/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"કોઈ સિમ કાર્ડ નથી"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"સિમ કાર્ડ ઉમેરો."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"સિમ કાર્ડ ખૂટે છે અથવા વાંચી શકાય એવું નથી. સિમ કાર્ડ ઉમેરો."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"ઉપયોગમાં ન લઈ શકાતું સિમ કાર્ડ."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"તમારું સિમ કાર્ડ કાયમ માટે નિષ્ક્રિય કરવામાં આવ્યું છે.\n બીજા સિમ કાર્ડ માટે તમારા વાયરલેસ સેવા પ્રદાતાનો સંપર્ક કરો."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"સિમ કાર્ડ લૉક કરેલું છે."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"સિમ કાર્ડ PUK-લૉક કરેલું છે."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"સિમ કાર્ડ અનલૉક કરી રહ્યાં છીએ…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-hi/strings.xml b/packages/SystemUI/res-keyguard/values-hi/strings.xml
index 9d32f04206dc8395e34174052f0d79daf758e74b..18d63ab35e9444a265b0a71618464f104421126c 100644
--- a/packages/SystemUI/res-keyguard/values-hi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hi/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"कोई सिम नहीं है"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"कोई सिम जोड़ें."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"सिम मौजूद नहीं है या उसे ऐक्सेस नहीं किया जा सकता. कोई सिम जोड़ें."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"सिम को हमेशा के लिए बंद कर दिया गया है."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"आपका सिम हमेशा के लिए बंद कर दिया गया है.\n दूसरा सिम पाने के लिए, वायरलेस सेवा देने वाली कंपनी से संपर्क करें."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"सिम लॉक है."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"सिम में PUK लॉक लगा है."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"सिम अनलॉक हो रहा है…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-hr/strings.xml b/packages/SystemUI/res-keyguard/values-hr/strings.xml
index b4224bfbc497768c3b38e0a5ea10450536b2a459..0206faf7f2ad5d0a8b4abe5891a1100ecae1de0d 100644
--- a/packages/SystemUI/res-keyguard/values-hr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hr/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • sporo punjenje"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Punjenje se optimizira radi zaštite baterije"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Problem s priborom za punjenje"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Pritisnite Izbornik da biste otključali."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Mreža je zaključana"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Nema SIM-a"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Dodajte SIM."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM nedostaje ili nije čitljiv. Dodajte SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM je neupotrebljiv."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"Vaš je SIM trajno deaktiviran.\n Obratite se svom davatelju bežičnih usluga da biste dobili drugi SIM."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM je zaključan."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM je zaključan PUK-om."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Otključavanje SIM-a…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-hu/strings.xml b/packages/SystemUI/res-keyguard/values-hu/strings.xml
index bc712c7cc882a5bcdaa31c1e89eb068355ab4e96..8575e10884ceb68178940c969848a871b4568ac2 100644
--- a/packages/SystemUI/res-keyguard/values-hu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hu/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Lassú töltés"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Optimalizált töltés az akkumulátor védelme érdekében"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Probléma van a töltőtartozékkal"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"A feloldáshoz nyomja meg a Menü gombot."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Hálózat zárolva"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Nincs SIM"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Adjon hozzá egy SIM-et."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"A SIM hiányzik vagy nem olvasható. Adjon hozzá egy SIM-et."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Nem használható SIM."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"SIM véglegesen deaktiválva.\n Forduljon a vezeték nélküli szolgáltatójához másik SIM beszerzése érdekében."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"Zárolt SIM."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"A SIM le van zárva PUK-kóddal."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"SIM zárolásának feloldása…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-hy/strings.xml b/packages/SystemUI/res-keyguard/values-hy/strings.xml
index 4d7bbbef2a084d3aee95cbbf1aab165d62dc42a6..a7c3abab1d842639a878fe192cce340705c6b39d 100644
--- a/packages/SystemUI/res-keyguard/values-hy/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hy/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"SIM Ö„Õ¡Ö€Õ¿ Õ¹Õ¯Õ¡"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Ավելացրեք SIM քարտ։"</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM քարտը բացակայում է կամ ընթեռնելի չէ։ Ավելացրեք SIM քարտ։"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Ô±Õ¶Õ¾Õ¡Õ¾Õ¥Ö€ SIM Ö„Õ¡Ö€Õ¿Ö‰"</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"Ձեր SIM քարտն ընդմիշտ ապակտիվացվել է։\n Նոր SIM քարտ ձեռք բերելու համար կապվեք ձեր բջջային օպերատորի հետ։"</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM Ö„Õ¡Ö€Õ¿Õ¨ Õ¯Õ¸Õ²ÕºÕ¾Õ¡Õ® Õ§Ö‰"</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM Ö„Õ¡Ö€Õ¿Õ¨ Õ¯Õ¸Õ²ÕºÕ¾Õ¡Õ® Õ§ PUK Õ¯Õ¸Õ¤Õ¸Õ¾Ö‰"</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"SIM քարտն ապակողպվում է…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-in/strings.xml b/packages/SystemUI/res-keyguard/values-in/strings.xml
index aa766e963670d1b0b0171a76d1d3ddb1171f40bd..f9a840fc5aa897d0e515f96657d94c74f422bc3b 100644
--- a/packages/SystemUI/res-keyguard/values-in/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-in/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mengisi daya dengan lambat"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Pengisian daya dioptimalkan untuk melindungi baterai"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Masalah dengan aksesori pengisian daya"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Tekan Menu untuk membuka kunci."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Jaringan terkunci"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Tidak ada SIM"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Tambahkan SIM."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM tidak ada atau tidak dapat dibaca. Tambahkan SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM tidak dapat digunakan."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"SIM Anda telah dinonaktifkan secara permanen.\n Hubungi penyedia layanan nirkabel Anda untuk mendapatkan SIM lain."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM dikunci."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM dikunci PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Membuka kunci SIM …"</string>
diff --git a/packages/SystemUI/res-keyguard/values-is/strings.xml b/packages/SystemUI/res-keyguard/values-is/strings.xml
index 99f177939378d55de0007b46b7b005ba5e0dadb1..b7147c2019190203c687a2217837a1e583347bd0 100644
--- a/packages/SystemUI/res-keyguard/values-is/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-is/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Hæg hleðsla"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Hleðsla fínstillt til að vernda rafhlöðuna"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Vandamál með hleðslubúnað"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Ýttu á valmyndarhnappinn til að taka úr lás."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Net læst"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Ekkert SIM-kort"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Bæta við SIM-korti."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM-kort vantar eða er ekki læsilegt. Bæta við SIM-korti."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Ónothæft SIM-kort."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"SIM-kortið þitt var gert varanlega óvirkt.\n Hafðu samband við símafyrirtækið þitt til að fá nýtt SIM-kort."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM-kort er læst."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM-kort er læst með PUK-númeri."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Opnar SIM-kort…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-it/strings.xml b/packages/SystemUI/res-keyguard/values-it/strings.xml
index cc0a1648054755c3c853ffc3d2d152b8cd7f3dcc..9e1b18740750a61b994f970157db703b0dcb5a6b 100644
--- a/packages/SystemUI/res-keyguard/values-it/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-it/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ricarica lenta"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ricarica ottimizzata per proteggere la batteria"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Problema relativo all\'accessorio di ricarica"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Premi Menu per sbloccare."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Rete bloccata"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Nessuna SIM presente"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Aggiungi una SIM."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM mancante o non leggibile. Aggiungi una SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM inutilizzabile."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"La SIM è stata disattivata definitivamente.\n Contatta il tuo fornitore di servizi wireless per richiedere un\'altra SIM."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"La SIM è bloccata."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"La SIM è bloccata tramite PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Sblocco della SIM in corso…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-iw/strings.xml b/packages/SystemUI/res-keyguard/values-iw/strings.xml
index 00c717c3d3c2a9eb5799b3641ef63efbaa919520..16316cebcc7c04e555c6185df5c16d1f30c5de84 100644
--- a/packages/SystemUI/res-keyguard/values-iw/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-iw/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"‏אין כרטיס SIM"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"‏הוספת כרטיס SIM."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"‏כרטיס ה-SIM חסר או שלא ניתן לקרוא אותו. הוספת כרטיס SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"‏לא ניתן להשתמש בכרטיס ה-SIM הזה."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"‏כרטיס ה-SIM שלך הושבת באופן סופי.\n עליך לפנות לספק השירות האלחוטי שלך לקבלת כרטיס SIM אחר."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"‏כרטיס ה-SIM נעול."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"‏כרטיס ה-SIM נעול באמצעות PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"‏מתבצע ביטול נעילה של כרטיס ה-SIM…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ja/strings.xml b/packages/SystemUI/res-keyguard/values-ja/strings.xml
index 1d59a630b8c21e42ced073a33d6eb9b769223ebf..6e8f42369e0a856e1be93ad2de02ef1d0ed512dc 100644
--- a/packages/SystemUI/res-keyguard/values-ja/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ja/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"SIM がありません"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"SIM を追加してください。"</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM が見つからないか読み取れません。SIM を追加してください。"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM が使用できません。"</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"SIM が完全に無効になっています。\n ワイヤレス サービス プロバイダにお問い合わせのうえ、新しい SIM を入手してください。"</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM がロックされています。"</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM が PUK でロックされました。"</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"SIM ロックを解除しています…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ka/strings.xml b/packages/SystemUI/res-keyguard/values-ka/strings.xml
index 5bd6b2e3d883b492c6da1151a52730a897fd1abe..a31243d9f5f9a669a99c87856baa407d26f031cb 100644
--- a/packages/SystemUI/res-keyguard/values-ka/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ka/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"SIM არ არის"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"SIM-ის დამატება."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM აკლია ან არ იკითხება. SIM-ის დამატება."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"გამოუყენებელი SIM."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"თქვენი SIM სამუდამოდ გამორთულია.\n დაუკავშირდით თქვენს უკაბელო სერვისის პროვაიდერს სხვა SIM ბარათისთვის."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM-ბარათი ჩაკეტილია."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM დაბლოკილია PUK-ით."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"SIM-ის განბლოკვა…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-kk/strings.xml b/packages/SystemUI/res-keyguard/values-kk/strings.xml
index 83d270ded60c5d2ed2a4e0b20cd2e224523bd08b..6a777832d07dd708eea9575a4ddd9dd20a55deee 100644
--- a/packages/SystemUI/res-keyguard/values-kk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kk/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"SIM картасы жоқ."</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"SIM картасын қосыңыз."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM картасы жоқ немесе оқылмай тұр. SIM картасын қосыңыз."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM картасын пайдалану мүмкін емес."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"SIM картаңыз біржола өшірілді.\n Сымсыз байланыс провайдеріне хабарласып, басқа SIM картасын алыңыз."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM картасы құлыпталған."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM картасы PUK кодымен құлыпталды."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"SIM картасының құлпы ашылып жатыр…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-km/strings.xml b/packages/SystemUI/res-keyguard/values-km/strings.xml
index 5306cb1ff4e6c1bb75986fe360b73cea6e093525..cda9520862aa48d05d5bb55008cae50d320e20c3 100644
--- a/packages/SystemUI/res-keyguard/values-km/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-km/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"គ្មានស៊ីមទេ"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"បញ្ចូល​ស៊ីម។"</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"បាត់ស៊ីម ឬមិនអាចអានស៊ីមបាន។ បញ្ចូល​ស៊ីម។"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"ស៊ីមមិនអាចប្រើបាន។"</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"ស៊ីមរបស់អ្នកត្រូវបានបិទដំណើរការជាអចិន្ត្រៃយ៍។\n ទាក់ទងទៅក្រុមហ៊ុនផ្ដល់សេវាឥតខ្សែរបស់អ្នក ដើម្បីទទួលបានស៊ីមមួយទៀត។"</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"ស៊ីម​ត្រូវបាន​ចាក់សោ។"</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"ស៊ីមត្រូវបានចាក់សោដោយ PUK។"</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"កំពុងដោះសោស៊ីម…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-kn/strings.xml b/packages/SystemUI/res-keyguard/values-kn/strings.xml
index d609a23d2c87416ae22004645bc7cf47a51957e8..e24005a08fc90d696d3a55795cd3745a3091a2bb 100644
--- a/packages/SystemUI/res-keyguard/values-kn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kn/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"SIM ಇಲ್ಲ"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"SIM ಅನ್ನು ಸೇರಿಸಿ."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM ಕಾಣೆಯಾಗಿದೆ ಅಥವಾ ರೀಡ್ ಆಗುತ್ತಿಲ್ಲ. SIM ಅನ್ನು ಸೇರಿಸಿ."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM ನಿಷ್ಪ್ರಯೋಜಕವಾಗಿದೆ."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"ನಿಮ್ಮ SIM ಅನ್ನು ಶಾಶ್ವತವಾಗಿ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ.\n ಬೇರೊಂದು SIM ಗಾಗಿ ನಿಮ್ಮ ವೈರ್‌ಲೆಸ್ ಸೇವಾ ಪೂರೈಕೆದಾರರನ್ನು ಸಂಪರ್ಕಿಸಿ."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM ಲಾಕ್ ಆಗಿದೆ."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM PUK ಲಾಕ್ ಆಗಿದೆ."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"SIM ಅನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಲಾಗುತ್ತಿದೆ…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ko/strings.xml b/packages/SystemUI/res-keyguard/values-ko/strings.xml
index 0e09fade9d57f05de6ad803daa4f4018ddff7374..7378cc78e5e677484d215dff2a82f4c34c69a424 100644
--- a/packages/SystemUI/res-keyguard/values-ko/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ko/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"SIM 없음"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"SIM을 추가하세요."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM이 없거나 SIM을 읽을 수 없습니다. SIM을 추가하세요."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM을 사용할 수 없습니다."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"SIM이 영구적으로 비활성화되었습니다.\n 다른 SIM을 사용하려면 무선 서비스 제공업체에 문의하시기 바랍니다."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM이 잠김 상태입니다."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM이 PUK 잠김 상태입니다."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"SIM 잠금 해제 중…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ky/strings.xml b/packages/SystemUI/res-keyguard/values-ky/strings.xml
index 1e03c03b1ae4f1334597f68877213de180f1c68a..88f0b97b385b80faff8070d347b1ec0443f6eaa8 100644
--- a/packages/SystemUI/res-keyguard/values-ky/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ky/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"SIM карта жок"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"SIM карта кошуңуз."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM карта жок же окулбайт. SIM карта кошуңуз."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Жараксыз SIM карта."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"SIM картаңыз биротоло өчүрүлдү.\n Башка SIM карта алуу үчүн зымсыз кызмат көрсөтүүчүгө кайрылыңыз."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM карта кулпуланган."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM карта PUK менен кулпуланган."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"SIM картанын кулпусу ачылууда…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-lo/strings.xml b/packages/SystemUI/res-keyguard/values-lo/strings.xml
index 0059d7fbaceedc8d295d139d67f2d02235407aa7..00a382a7cd02a26e89b10530746e84f07752729c 100644
--- a/packages/SystemUI/res-keyguard/values-lo/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lo/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"ບໍ່ມີຊິມ"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"ເພີ່ມຊິມ."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"ບໍ່ມີຊິມ ຫຼື ອ່ານຊິມບໍ່ໄດ້. ເພີ່ມຊິມ."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"ຊິມໃຊ້ບໍ່ໄດ້."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"ຊິມຂອງທ່ານຖືກປິດໃຊ້ຢ່າງຖາວອນແລ້ວ.\n ຕິດຕໍ່ຜູ້ໃຫ້ບໍລິການໂທລະສັບໄຮ້ສາຍຂອງທ່ານເພື່ອຂໍຊິມໃໝ່."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"ຊິມຖືກລັອກຢູ່."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"ຊິມຖືກລັອກດ້ວຍ PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"ກຳລັງປົດລັອກຊິມ…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-lt/strings.xml b/packages/SystemUI/res-keyguard/values-lt/strings.xml
index 01e2f8820700edd35db1aa7c375214abf4702ece..31c4107905568283f5070b3e2f77225ac5a954a3 100644
--- a/packages/SystemUI/res-keyguard/values-lt/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lt/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Lėtai įkraunama"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Įkrovimas optimizuotas siekiant apsaugoti akumuliatorių"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Su įkrovimo priedu susijusi problema"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Paspauskite meniu, jei norite atrakinti."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Tinklas užrakintas"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"NÄ—ra SIM kortelÄ—s"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Įdėkite SIM kortelę."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"Trūksta SIM kortelės arba ji neskaitoma. Įdėkite SIM kortelę."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Nenaudojama SIM kortelÄ—."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"Jūsų SIM kortelė visam laikui išjungta.\n Susisiekite su belaidžio ryšio paslaugos teikėju, kad gautumėte naują SIM kortelę."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM kortelė užrakinta."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM kortelė užrakinta PUK kodu."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Atrakinama SIM…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-lv/strings.xml b/packages/SystemUI/res-keyguard/values-lv/strings.xml
index 2133694f99a855ef4f2f1c6a7339c4cff2bc9a59..ecf223351942c7f30f87fe88ab9f287d82fd92a7 100644
--- a/packages/SystemUI/res-keyguard/values-lv/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lv/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Notiek lēnā uzlāde"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Uzlāde optimizēta, lai saudzētu akumulatoru"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Problēma ar uzlādes ierīci"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Lai atbloķētu, nospiediet izvēlnes ikonu."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"TÄ«kls ir bloÄ·Ä“ts."</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Nav SIM kartes"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Pievienojiet SIM karti."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"Nav SIM kartes, vai arī to nevar nolasīt. Pievienojiet SIM karti."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM karte nav izmantojama."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"Jūsu SIM karte ir neatgriezeniski deaktivizēta.\n Sazinieties ar savu bezvadu pakalpojumu sniedzēju, lai iegūtu citu SIM karti."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM karte ir bloķēta."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM karte ir bloķēta ar PUK kodu."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Notiek SIM kartes atbloķēšana…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-mk/strings.xml b/packages/SystemUI/res-keyguard/values-mk/strings.xml
index 2771c7f5b5d6c5796ee460cee5d6f6d47f8619e1..3f089b991b92fb1f64c6b67a53c711121fc57aaf 100644
--- a/packages/SystemUI/res-keyguard/values-mk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mk/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"Нема SIM-картичка"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Додајте SIM-картичка."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"Нема SIM-картичка или не може да се прочита. Додајте SIM-картичка."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM-картичката е неупотреблива."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"Вашата SIM-картичка е трајно деактивирана.\n Контактирајте со давателот на услуги за безжична мрежа за друга SIM-картичка."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM-картичката е заклучена."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM-картичката е заклучена со PUK-код."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Се отклучува SIM-картичката…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ml/strings.xml b/packages/SystemUI/res-keyguard/values-ml/strings.xml
index 02ee66fc83b42a232009e4b92376e5162929e366..be1ea89688ff01eb44b6a4652559808be30431c1 100644
--- a/packages/SystemUI/res-keyguard/values-ml/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ml/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"സിം ഇല്ല"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"സിം ചേർക്കുക."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"സിം കാണുന്നില്ല അല്ലെങ്കിൽ റീഡ് ചെയ്യാനായില്ല. സിം ചേർക്കുക."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"ഉപയോഗശൂന്യമായ സിം."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"നിങ്ങളുടെ സിം ശാശ്വതമായി നിഷ്ക്രിയമാക്കി.\n മറ്റൊരു സിമ്മിന് നിങ്ങളുടെ വയർലെസ് സേവന ദാതാവിനെ ബന്ധപ്പെടുക."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"സിം ലോക്ക് ചെയ്തു."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"സിം PUK ലോക്ക് ചെയ്തു."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"സിം അൺലോക്ക് ചെയ്യുന്നു…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-mn/strings.xml b/packages/SystemUI/res-keyguard/values-mn/strings.xml
index 2b9f81e9e3589c8349c80fc21c3a13227a947ca2..54fdecd761ac7081f3b2bc2c64614fcbd54b3191 100644
--- a/packages/SystemUI/res-keyguard/values-mn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mn/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"SIM байхгүй"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"SIM нэмнэ үү."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM дутуу эсвэл үүнийг унших боломжгүй байна. SIM нэмнэ үү."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Ашиглах боломжгүй SIM."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"Таны SIM-г бүрмөсөн идэвхгүй болгосон байна.\n Өөр SIM авах бол утасгүй үйлчилгээ үзүүлэгчтэйгээ холбогдоно уу."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM-г түгжсэн байна."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM-г PUK-р түгжсэн байна."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"SIM-н түгжээг тайлж байна…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-mr/strings.xml b/packages/SystemUI/res-keyguard/values-mr/strings.xml
index 7aa7bdd26c081d0026b3603dd7ade5b09cc260bb..eff4c7a9b2d3a9e4f515bb51af9bb4aef5d5dd95 100644
--- a/packages/SystemUI/res-keyguard/values-mr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mr/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"सिम नाही"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"सिम जोडा."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"सिम गहाळ झाले आहे किंवा ते रीड करू शकत नाही. सिम जोडा."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"वापरण्यायोग्य नसलेले सिम."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"तुमचे सिम कायमचे डीॲक्टिव्हेट केले गेले आहे.\n दुसऱ्या सिमसाठी तुमच्या वायरलेस सेवा पुरवठादाराशी संपर्क साधा."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"सिम लॉक केलेले आहे."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"सिम PUK लॉक केलेले आहे."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"सिम अनलॉक करत आहे…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ms/strings.xml b/packages/SystemUI/res-keyguard/values-ms/strings.xml
index bdfa4a77eb8acce1ec181b2949bbfe0fb4875b35..d9eb4ca07c6df2fee195bb15be07214cfa4301f8 100644
--- a/packages/SystemUI/res-keyguard/values-ms/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ms/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mengecas dengan perlahan"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Pengecasan dioptimumkan untuk melindungi bateri"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Isu berkaitan aksesori pengecasan"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Tekan Menu untuk membuka kunci."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Rangkaian dikunci"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Tiada SIM"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Tambah SIM."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM tiada atau tidak boleh dibaca. Tambah SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM tidak boleh digunakan."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"SIM anda telah dinyahaktifkan secara kekal.\n Hubungi penyedia perkhidmatan wayarles anda untuk mendapatkan SIM lain."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM dikunci."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM dikunci PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Membuka kunci SIM…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-my/strings.xml b/packages/SystemUI/res-keyguard/values-my/strings.xml
index 576250b4f157798ef30a9a851083f7777484eaf0..afbce26a945fa7260588435bd3137a0df6e0b840 100644
--- a/packages/SystemUI/res-keyguard/values-my/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-my/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"ဆင်းမ်ကတ် မရှိပါ"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"ဆင်းမ်ကတ်ထည့်ပါ။"</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"ဆင်းမ်မရှိပါ (သို့) သုံး၍မရပါ။ ဆင်းမ်ကတ်ထည့်ပါ။"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"ဆင်းမ်ကတ်ကို သုံး၍မရပါ။"</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"သင်၏ဆင်းမ်ကတ်ကို အပြီးပိတ်လိုက်သည်။\n ဆင်းမ်ကတ်နောက်တစ်ခု ရယူရန် သင်၏ ကြိုးမဲ့ဝန်ဆောင်မှုပေးသူထံ ဆက်သွယ်ပါ။"</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"ဆင်းမ်ကတ်ကို လော့ခ်ချထားသည်။"</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"ဆင်းမ်ကတ်၏ ပင်နံပါတ်ပြန်ဖွင့်သည့် ကုဒ်ကို လော့ခ်ချထားသည်။"</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"ဆင်းမ်ကတ် ဖွင့်နေသည်…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-nb/strings.xml b/packages/SystemUI/res-keyguard/values-nb/strings.xml
index 455d08620fbba5f0359b5686e53c2360469125a1..3098e878f5b6a172e417e914124fea0b119a6f8d 100644
--- a/packages/SystemUI/res-keyguard/values-nb/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-nb/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Lader sakte"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ladingen er optimalisert for å beskytte batteriet"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Problem med ladetilbehøret"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Trykk på menyknappen for å låse opp."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Nettverket er låst"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Ingen SIM-kort"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Legg til et SIM-kort."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM-kortet mangler eller kan ikke leses. Legg til et SIM-kort."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM-kortet kan ikke brukes."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"SIM-kortet er deaktivert permanent.\n Kontakt leverandøren av trådløstjenesten for å få et nytt SIM-kort."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM-kortet er låst."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM-kortet er låst med PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Låser opp SIM-kortet …"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ne/strings.xml b/packages/SystemUI/res-keyguard/values-ne/strings.xml
index f0094a3d427d4d9f108a9c258232e6734620cc0d..45b88197a52d4a8acb2f35d20bc43960009f6ce0 100644
--- a/packages/SystemUI/res-keyguard/values-ne/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ne/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"SIM कार्ड हालिएको छैन"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"SIM कार्ड हाल्नुहोस्।"</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM कार्ड हालिएको छैन वा रिड गर्न मिल्दैन। SIM कार्ड हाल्नुहोस्।"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"यो SIM कार्ड प्रयोग गर्न मिल्दैन।"</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"तपाईंको SIM कार्ड सदाका लागि डिएक्टिभेट गरिएको छ।\n आफ्नो वायरलेस सेवा प्रदायकलाई सम्पर्क गरी अर्को SIM कार्ड प्राप्त गर्नुहोस्।"</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM कार्ड लक गरिएको छ।"</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM कार्ड PUK प्रयोग गरी लक गरिएको छ।"</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"SIM कार्ड अनलक गरिँदै छ…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-nl/strings.xml b/packages/SystemUI/res-keyguard/values-nl/strings.xml
index 1ba4a814ebde84a92c8826928e298ec8e7ac4fa7..af24d4002e0ef517ae593b1f023da984362bed20 100644
--- a/packages/SystemUI/res-keyguard/values-nl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-nl/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Langzaam opladen"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Opladen geoptimaliseerd om de batterij te beschermen"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Probleem met oplaadaccessoire"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Druk op Menu om te ontgrendelen."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Netwerk vergrendeld"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Geen simkaart"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Voeg een simkaart toe."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"De simkaart ontbreekt of kan niet worden gelezen. Voeg een simkaart toe."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Onbruikbare simkaart."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"Je simkaart is permanent gedeactiveerd.\n Neem contact op met je mobiele serviceprovider voor een nieuwe simkaart."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"Simkaart is vergrendeld."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"Simkaart is vergrendeld met pukcode."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Simkaart ontgrendelen…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-or/strings.xml b/packages/SystemUI/res-keyguard/values-or/strings.xml
index b31c9c0c2207973b62a2452675f7146eb7fd8c7b..8cae9874bbf3c12e9d6d4261622e54e88746cea4 100644
--- a/packages/SystemUI/res-keyguard/values-or/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-or/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"କୌଣସି SIM ନାହିଁ"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"ଏକ SIM ଯୋଗ କରନ୍ତୁ।"</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM ଉପଲବ୍ଧ ନାହିଁ କିମ୍ବା ପଢ଼ିପାରିବା ଯୋଗ୍ୟ ନୁହେଁ। ଏକ SIM ଯୋଗ କରନ୍ତୁ।"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"ବ୍ୟବହାର ଅଯୋଗ୍ୟ ଥିବା SIM।"</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"ଆପଣଙ୍କ SIMକୁ ସ୍ଥାୟୀ ଭାବରେ ନିଷ୍କ୍ରିୟ କରାଯାଇଛି।\n ଅନ୍ୟ ଏକ SIM ପାଇଁ ଆପଣଙ୍କ ୱେୟାରଲେସ ସେବା ପ୍ରଦାନକାରୀଙ୍କ ସହ କଣ୍ଟାକ୍ଟ କରନ୍ତୁ।"</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIMକୁ ଲକ କରାଯାଇଛି।"</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIMକୁ PUK-ଲକ କରାଯାଇଛି।"</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"SIMକୁ ଅନଲକ କରାଯାଉଛି…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pa/strings.xml b/packages/SystemUI/res-keyguard/values-pa/strings.xml
index 209b63fbd8f817cdf69e0afb594c78aa7da44073..18959c8fb9e8e54610ac10a2b2147bb76433b939 100644
--- a/packages/SystemUI/res-keyguard/values-pa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pa/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"ਕੋਈ ਸਿਮ ਨਹੀਂ ਹੈ"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"ਸਿਮ ਸ਼ਾਮਲ ਕਰੋ।"</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"ਸਿਮ ਮੌਜੂਦ ਨਹੀਂ ਹੈ ਜਾਂ ਪੜ੍ਹਨਯੋਗ ਨਹੀਂ ਹੈ। ਸਿਮ ਸ਼ਾਮਲ ਕਰੋ।"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"ਬੇਕਾਰ ਸਿਮ।"</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"ਤੁਹਾਡੇ ਸਿਮ ਨੂੰ ਪੱਕੇ ਤੌਰ \'ਤੇ ਅਕਿਰਿਆਸ਼ੀਲ ਕੀਤਾ ਗਿਆ ਹੈ।\n ਦੂਜੇ ਸਿਮ ਲਈ ਆਪਣੇ ਵਾਇਰਲੈੱਸ ਸੇਵਾ ਪ੍ਰਦਾਨਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।"</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"ਸਿਮ ਲਾਕ ਹੈ।"</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"ਸਿਮ PUK-ਲਾਕ ਹੈ।"</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"ਸਿਮ ਨੂੰ ਅਣਲਾਕ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pl/strings.xml b/packages/SystemUI/res-keyguard/values-pl/strings.xml
index 7ec988ecf777219092018cb38f4b8001caf69b12..bd00ba9bb5f6fe2760c8a71dc3860da6384a4693 100644
--- a/packages/SystemUI/res-keyguard/values-pl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pl/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Wolne ładowanie"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ładowanie zoptymalizowane w celu ochrony baterii"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Problem z akcesoriami do ładowania"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Naciśnij Menu, aby odblokować."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Sieć zablokowana"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Brak karty SIM"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Dodaj kartÄ™ SIM."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"Brak karty SIM lub nie można jej odczytać. Dodaj kartę SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Nie można użyć karty SIM."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"Karta SIM została trwale wyłączona.\n Skontaktuj się z dostawcą usług bezprzewodowych, aby uzyskać inną kartę SIM."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"Karta SIM jest zablokowana."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"Karta SIM została zablokowana kodem PUK"</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Odblokowuję kartę SIM…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
index 78a80912e99e68a9939241ae7f2901973b25992f..54e270f8eb2c85ef1fbefe11de5bbc304935a8d7 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregando lentamente"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregamento otimizado para proteger a bateria"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Problema com o acessório de carregamento"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Pressione Menu para desbloquear."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Rede bloqueada"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Sem chip"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Adicione um chip."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"O chip não foi inserido ou não pode ser lido. Adicione um chip."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Chip inutilizável."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"Seu chip foi desativado permanentemente.\n Entre em contato com seu provedor de serviços sem fio para receber outro chip."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"O chip está bloqueado."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"O chip está bloqueado pela PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Desbloqueando chip…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
index 5549b36e504c618780ba8d2ee2bf4720a21a7f21..2e37bde883de160bd5d42f9675bf8e4c2e868db1 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • A carregar lentamente…"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregamento otimizado para proteger a bateria"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Problema com o acessório de carregamento"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Prima Menu para desbloquear."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Rede bloqueada"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Sem SIM"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Adicione um SIM."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"O SIM está em falta ou não é legível. Adicione um SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM inutilizável."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"O SIM foi desativado permanentemente.\n Contacte o seu fornecedor de serviços de rede sem fios para obter outro SIM."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"O SIM está bloqueado."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"O SIM está bloqueado com o PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"A desbloquear SIM…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt/strings.xml b/packages/SystemUI/res-keyguard/values-pt/strings.xml
index 78a80912e99e68a9939241ae7f2901973b25992f..54e270f8eb2c85ef1fbefe11de5bbc304935a8d7 100644
--- a/packages/SystemUI/res-keyguard/values-pt/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregando lentamente"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregamento otimizado para proteger a bateria"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Problema com o acessório de carregamento"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Pressione Menu para desbloquear."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Rede bloqueada"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Sem chip"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Adicione um chip."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"O chip não foi inserido ou não pode ser lido. Adicione um chip."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Chip inutilizável."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"Seu chip foi desativado permanentemente.\n Entre em contato com seu provedor de serviços sem fio para receber outro chip."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"O chip está bloqueado."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"O chip está bloqueado pela PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Desbloqueando chip…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ro/strings.xml b/packages/SystemUI/res-keyguard/values-ro/strings.xml
index df28b8d10101f22ad5aa92f04f7ef0d33d29a2ae..ead092099326198200b82902b0f9f3b13feb9db8 100644
--- a/packages/SystemUI/res-keyguard/values-ro/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ro/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Se încarcă lent"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Încărcarea este optimizată pentru a proteja bateria"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Problemă legată de accesoriul de încărcare"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Apasă pe Meniu pentru a debloca."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Rețea blocată"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Niciun card SIM"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Adaugă un card SIM."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"Cardul SIM lipsește sau nu poate fi citit. Adaugă un card SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Cardul SIM nu se poate folosi."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"Cardul tău SIM a fost dezactivat definitiv.\n Contactează furnizorul de servicii wireless pentru a obține un alt card SIM."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"Cardul SIM este blocat."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"Cardul SIM este blocat prin cod PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Se deblochează cardul SIM…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ru/strings.xml b/packages/SystemUI/res-keyguard/values-ru/strings.xml
index 62249a1a68c734c41830f3febdb8d04935172312..595fba5dfcb23b38f278017dd1b2fad7aad82dfe 100644
--- a/packages/SystemUI/res-keyguard/values-ru/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ru/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"SIM-карта отсутствует"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Добавьте SIM-карту."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM-карта отсутствует или не распознана. Добавьте SIM-карту."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM-карту невозможно использовать."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"SIM-карта была окончательно деактивирована.\n Чтобы получить новую, обратитесь к своему оператору мобильной связи."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM-карта заблокирована."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM-карта заблокирована с помощью PUK-кода."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Разблокировка SIM-карты…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-si/strings.xml b/packages/SystemUI/res-keyguard/values-si/strings.xml
index 17ced75aaf1be22355fe284ada54a86dc0e67ebd..b6a742234fe0dd8cd171d94865c73fdbf1f76cc4 100644
--- a/packages/SystemUI/res-keyguard/values-si/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-si/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"SIM නැත"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"SIM එකක් එක් කරන්න."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM අස්ථානගතයි හෝ කියවිය නොහැක. SIM එකක් එක් කරන්න."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"භාවිත කළ නොහැකි SIM."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"ඔබේ SIM ස්ථිරවම අක්‍රිය කර ඇත.\n වෙනත් SIM පතක් සඳහා ඔබේ රැහැන් රහිත සේවා සපයන්නා අමතන්න."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM අගුළු දමා ඇත."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM PUK-අගුළු දමා ඇත."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"SIM අගුළු අරිමින්…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sk/strings.xml b/packages/SystemUI/res-keyguard/values-sk/strings.xml
index ef08a6cd5258470331143f097fb59fcbfeb02e7b..5e34a94ffccd4173d3cd4e7c6e28aa21aaf883ea 100644
--- a/packages/SystemUI/res-keyguard/values-sk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sk/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Nabíja sa pomaly"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Nabíjanie je optimalizované, aby sa chránila batéria"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Problém s nabíjacím príslušenstvom"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Odomknete stlačením tlačidla ponuky."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Sieť je zablokovaná"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Žiadna SIM karta"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Pridajte SIM kartu."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM karta chýba alebo sa nedá čítať. Pridajte SIM kartu."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Nepoužiteľná SIM karta."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"Vaša SIM karta bola natrvalo deaktivovaná.\n Požiadajte svojho poskytovateľa bezdrôtových služieb o ďalšiu SIM kartu."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM karta je uzamknutá."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM karta je uzamknutá kódom PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"SIM karta sa odomyká…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sl/strings.xml b/packages/SystemUI/res-keyguard/values-sl/strings.xml
index a42989c18ea9ea288092584ada9972e7fd981625..3508f3b3af6e8d9781188be96da4792b5e11f132 100644
--- a/packages/SystemUI/res-keyguard/values-sl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sl/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • počasno polnjenje"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Polnjenje je optimizirano zaradi zaščite baterije"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • težava s pripomočkom za polnjenje"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Če želite odkleniti, pritisnite meni."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Omrežje je zaklenjeno"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Ni kartice SIM."</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Dodajte kartico SIM."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"Ni kartice SIM ali je ni mogoče prebrati. Dodajte kartico SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Kartica SIM je neuporabna."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"Vaša kartica SIM je bila trajno deaktivirana.\n Za drugo kartico SIM se obrnite na ponudnika brezžičnih storitev."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"Kartica SIM je zaklenjena."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"Kartica SIM je zaklenjena s kodo PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Odklepanje kartice SIM …"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sq/strings.xml b/packages/SystemUI/res-keyguard/values-sq/strings.xml
index ce53b7ed3a98d97a61ceaf26d9c9ce5e2d601c27..8d71b0f941b78b7e948274f83ff617a53e5af5ba 100644
--- a/packages/SystemUI/res-keyguard/values-sq/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sq/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Po karikohet ngadalë"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Karikimi u optimizua për të mbrojtur baterinë"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Problem me aksesorin e karikimit"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Shtyp \"Meny\" për të shkyçur."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Rrjeti është i kyçur"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Nuk ka kartë SIM"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Shto një kartë SIM."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"Karta SIM mungon ose është e palexueshme. Shto një kartë SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Kartë SIM e papërdorshme."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"Karta jote SIM është çaktivizuar përgjithmonë.\n Kontakto me ofruesin e shërbimit wireless për një tjetër kartë SIM."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"Karta SIM është e kyçur."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"Karta SIM është e kyçur me PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Karta SIM po shkyçet…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sr/strings.xml b/packages/SystemUI/res-keyguard/values-sr/strings.xml
index 437018d938795e5105c09e2dc8ff4dc71b5a1a22..409395285343cc2517f261f2c1b2bbab2b2ced4d 100644
--- a/packages/SystemUI/res-keyguard/values-sr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sr/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"Нема SIM-а"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Додајте SIM."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM недостаје или не може да се прочита. Додајте SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Неупотребљив SIM."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"SIM је трајно деактивиран.\n Обратите се добављачу услуге бежичне телефоније да бисте добили други SIM."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM је закључан."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM је закључан PUK-ом."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Откључава се SIM…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sv/strings.xml b/packages/SystemUI/res-keyguard/values-sv/strings.xml
index b4b1996094bc14a3cfb49c8a0569bb4991563e53..5b01f39a6a11916053ef9fffeeeb6d3e7b7378f9 100644
--- a/packages/SystemUI/res-keyguard/values-sv/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sv/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Laddas långsamt"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Laddningen har optimerats för att skydda batteriet"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ett problem uppstod med att ladda tillbehöret"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Lås upp genom att trycka på Meny."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Nätverk låst"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Inget SIM-kort"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Lägg till ett SIM-kort."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM-kort saknas eller går inte att läsa. Lägg till ett SIM-kort."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM-kortet går inte att använda."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"Ditt SIM-kort har inaktiverats permanent.\n Kontakta din operatör och be om ett nytt SIM-kort."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM-kortet är låst."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM-kortet har låsts med PUK-kod."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"SIM-kortet låses upp …"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sw/strings.xml b/packages/SystemUI/res-keyguard/values-sw/strings.xml
index 8ca90465ee3a32a9e075535fa3f63500ede99c7e..72f1fc31c3dac645d33fa703ad0b8b1a9b83fbd5 100644
--- a/packages/SystemUI/res-keyguard/values-sw/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sw/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Inachaji pole pole"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Hali ya kuchaji imeboreshwa ili kulinda betri"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Kifuasi cha kuchaji kina hitilafu"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Bonyeza Menyu ili kufungua."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Mtandao umefungwa"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Hakuna SIM"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Weka SIM."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM haipo au haiwezi kusomwa. Weka SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM haiwezi kutumika."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"SIM kadi yako imefungwa kabisa.\n wasiliana na mtoa huduma wako wa pasi waya ili upate SIM nyingine."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM imefungwa."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM imefungwa kwa PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Inafungua SIM…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ta/strings.xml b/packages/SystemUI/res-keyguard/values-ta/strings.xml
index 7671194c3b142871cbdef5549bded19187dcc8d5..20eb8ef3e43e342d3c1164749e582168530933d3 100644
--- a/packages/SystemUI/res-keyguard/values-ta/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ta/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"சிம் இல்லை"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"சிம்மைச் சேருங்கள்."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"சிம் இல்லை அல்லது படிக்கக்கூடியதாக இல்லை. சிம்மைச் சேருங்கள்."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"பயன்படுத்த முடியாத சிம்."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"உங்கள் சிம் நிரந்தரமாக முடக்கப்பட்டுள்ளது.\n மற்றொரு சிம்மிற்கான உங்கள் வயர்லெஸ் சேவை வழங்குநரைத் தொடர்புகொள்ளுங்கள்."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"சிம் லாக் செய்யப்பட்டுள்ளது."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"சிம் PUK-லாக் செய்யப்பட்டுள்ளது."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"சிம்மை அன்லாக் செய்கிறது…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-te/strings.xml b/packages/SystemUI/res-keyguard/values-te/strings.xml
index 623b589861a9b35932baf2e691292d9732b65078..d496944798f9e00d4f2adb4a65b134ead7bac56f 100644
--- a/packages/SystemUI/res-keyguard/values-te/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-te/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"SIM లేదు"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"SIMను జోడించండి."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM మిస్ అయ్యింది లేదా ఆమోదయోగ్యం కాదు. SIMను జోడించండి."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"వినియోగించలేని SIM."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"మీ SIM శాశ్వతంగా డీయాక్టివేట్ చేయబడింది.\n మరో SIMను పొందడం కోసం మీ వైర్‌లెస్ సర్వీస్ ప్రొవైడర్‌ను సంప్రదించండి."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM లాక్ చేయబడింది."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM PUK లాక్ చేయబడింది."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"SIMను అన్‌లాక్ చేస్తోంది…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-th/strings.xml b/packages/SystemUI/res-keyguard/values-th/strings.xml
index c2441075d02db0fc9b245b720e6819793f370481..605d0772ac6e7e355fb2c18bb9634e61d085c32a 100644
--- a/packages/SystemUI/res-keyguard/values-th/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-th/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"ไม่มี SIM"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"โปรดใส่ SIM"</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"ไม่มี SIM หรืออ่านไม่ได้ โปรดใส่ SIM"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM ใช้งานไม่ได้"</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"ปิดใช้งาน SIM อย่างถาวรแล้ว\n ติดต่อผู้ให้บริการไร้สายของคุณเพื่อรับ SIM ใหม่"</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM ถูกล็อก"</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM ถูกล็อกด้วย PUK"</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"กำลังปลดล็อก SIM…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-tl/strings.xml b/packages/SystemUI/res-keyguard/values-tl/strings.xml
index cd8f81046f969c81510ff30656d8c943dcfe5cde..040ec9e9b703aa5758bc3799d827ce28aafdebc0 100644
--- a/packages/SystemUI/res-keyguard/values-tl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-tl/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mabagal na nagcha-charge"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Naka-optimize ang pag-charge para protektahan ang baterya"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Isyu sa pag-charge ng accessory"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Pindutin ang Menu upang i-unlock."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Naka-lock ang network"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Walang SIM"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Magdagdag ng SIM."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"Wala o hindi nababasa ang SIM. Magdagdag ng SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Hindi magagamit na SIM."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"Permanenteng na-deactivate ang iyong SIM.\n Makipag-ugnayan sa iyong service provider ng wireless para sa isa pang SIM."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"Naka-lock ang SIM."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"Naka-PUK lock ang SIM."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Ina-unlock ang SIM…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-tr/strings.xml b/packages/SystemUI/res-keyguard/values-tr/strings.xml
index ddeba67719d7acbfa84ccad70a6c9988d7bba33d..750ba1174fe8b3be2b244d903d5337c806796873 100644
--- a/packages/SystemUI/res-keyguard/values-tr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-tr/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Yavaş şarj oluyor"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Şarj işlemi pili korumak üzere optimize edildi"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Şarj aksesuarı ile ilgili sorun"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Kilidi açmak için Menü\'ye basın."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"AÄŸ kilitli"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM yok"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"SIM ekleyin."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM yok veya okunamıyor. SIM ekleyin."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Kullanılamayan SIM."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"SIM\'iniz kalıcı olarak devre dışı bırakıldı.\n Başka bir SIM için kablosuz servis sağlayıcınızla iletişime geçin."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM kilitli."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM\'in PUK kilidi devrede."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"SIM\'in kilidi açılıyor…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-uk/strings.xml b/packages/SystemUI/res-keyguard/values-uk/strings.xml
index f06d17df9146731ae3eed515c718795b6bcca3bc..169ea1f16eec5754847b73daa20895035be2fd12 100644
--- a/packages/SystemUI/res-keyguard/values-uk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-uk/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"Немає SIM-карти"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Додайте SIM-карту."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM-карта відсутня або недоступна для читання. Додайте SIM-карту."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Непридатна SIM-карта."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"SIM-карту деактивовано назавжди.\n Щоб отримати іншу, зверніться до свого постачальника послуг бездротового зв’язку."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM-карту заблоковано."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM-карту заблоковано PUK-кодом."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Розблокування SIM-карти…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ur/strings.xml b/packages/SystemUI/res-keyguard/values-ur/strings.xml
index 8adbaca955f7dea1ca58e48eb64de938b8887762..d7f7b653e92eadabd7931a9d3f4951d8458fd014 100644
--- a/packages/SystemUI/res-keyguard/values-ur/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ur/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"‏کوئی SIM نہیں ہے"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"‏ایک SIM شامل کریں۔"</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"‏SIM غائب ہے یا پڑھنے لائق نہیں ہے۔ ایک SIM شامل کریں۔"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"‏ناقابل استعمال SIM۔"</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"‏آپ کے SIM کو مستقل طور پر غیر فعال کر دیا گیا ہے۔\n کسی دوسرے SIM کیلئے اپنے وائرلیس سروس فراہم کنندہ سے رابطہ کریں۔"</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"‏SIM مقفل ہے۔"</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"‏آپ کا SIM ‏PUK مقفل ہے۔"</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"‏SIM کو غیر مقفل کیا جا رہا ہے…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-uz/strings.xml b/packages/SystemUI/res-keyguard/values-uz/strings.xml
index 96dfa05a74aaf1e98de22d2807726b333f49f938..40dbaf3142fa2822e91ec39c611d96e4586880c5 100644
--- a/packages/SystemUI/res-keyguard/values-uz/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-uz/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Sekin quvvat olmoqda"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Batareyani himoyalash uchun quvvatlash optimallashtirildi"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Quvvatlash aksessuari bilan muammo"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Qulfdan chiqarish uchun Menyu tugmasini bosing."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Tarmoq qulflangan"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM kartasiz"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"SIM karta qoʻshish."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM karta topilmadi yoki oʻqilmadi. SIM karta qoʻshish."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Ishlamaydigan SIM."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"SIM karta butunlay faolsizlantirildi.\n Boshqa SIM karta olish uchun simsiz aloqa operatoriga murojaat qiling."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM karta qulflandi."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM karta PUK kod bilan qulflangan."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"SIM karta qulfdan chiqarilmoqda…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-vi/strings.xml b/packages/SystemUI/res-keyguard/values-vi/strings.xml
index 41b5a33ba967693af2cb9fa8c8ca66e425f12bb8..d5a33d37bc660b7424ddfea392edf9519aef1557 100644
--- a/packages/SystemUI/res-keyguard/values-vi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-vi/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Đang sạc chậm"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Quá trình sạc được tối ưu hoá để bảo vệ pin"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Có vấn đề với phụ kiện sạc"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Nhấn vào Menu để mở khóa."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Mạng đã bị khóa"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Không có SIM"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"Hãy thêm SIM."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"Không tìm thấy hoặc không đọc được SIM. Hãy thêm SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM không sử dụng được."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"SIM của bạn đã bị vô hiệu hoá vĩnh viễn.\n Hãy liên hệ với nhà cung cấp dịch vụ viễn thông không dây của bạn để yêu cầu cấp SIM khác."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM này đang bị khoá."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM này đang bị khoá PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Đang mở khoá SIM…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
index 4c65832162ba89409fd689039f52bb4be6789267..6de9ff9448820cecccac6c6d3af0fd9b9dfe8158 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"没有 SIM 卡"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"请插入 SIM 卡。"</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"SIM 卡缺失或无法读取。请插入 SIM 卡。"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM 卡无法使用。"</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"您的 SIM 卡已被永久停用。\n请与您的无线服务提供商联系,以便重新获取一张 SIM 卡。"</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM 卡已被锁定。"</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM 卡已用 PUK 码锁定。"</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"正在解锁 SIM 卡…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
index dad6f31ac5531983d95bb98f9ed3a9ac09f4db3a..11966ca08dcefca26c46fa47d6a7dda4006b3ea9 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"沒有 SIM 卡"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"請新增 SIM 卡。"</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"找不到 SIM 卡或 SIM 卡無法讀取,請新增 SIM 卡。"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM 卡無法使用。"</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"SIM 卡已永久停用。\n請向無線服務供應商索取其他 SIM 卡。"</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM 卡已鎖定。"</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM 卡已使用 PUK 鎖定。"</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"正在解鎖 SIM 卡…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
index 88b7e4374ff9228761a2fc7b83d1f15b2bd20b80..e4f868a093d376968d32ccf2298d936e92157065 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
@@ -35,13 +35,9 @@
     <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_incompatible_charger" msgid="3687961801947819076">"<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="685029586173458728">"沒有 SIM 卡"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"請新增 SIM 卡。"</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"找不到 SIM 卡或 SIM 卡無法讀取,請新增 SIM 卡。"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM 卡無法使用。"</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"SIM 卡已永久停用。\n 請向無線服務供應商索取其他 SIM 卡。"</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM 卡已鎖定。"</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM 卡已使用 PUK 碼鎖定。"</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"正在解鎖 SIM 卡…"</string>
diff --git a/packages/SystemUI/res-keyguard/values-zu/strings.xml b/packages/SystemUI/res-keyguard/values-zu/strings.xml
index c5e99abbda54d60c121a2d108711012c625cf713..4fadc2e55ee920ffa1f8236be38be9521264ae91 100644
--- a/packages/SystemUI/res-keyguard/values-zu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zu/strings.xml
@@ -35,13 +35,9 @@
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ishaja kancane"</string>
     <string name="keyguard_plugged_in_charging_limited" msgid="1053130519456324630">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ukushaja kuthuthukisiwe ukuze kuvikelwe ibhethri"</string>
     <string name="keyguard_plugged_in_incompatible_charger" msgid="3687961801947819076">"<xliff:g id="PERCENTAGE">%s</xliff:g> • • Inkinga ngesisekeli sokushaja"</string>
-    <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Chofoza Menyu ukuvula."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Inethiwekhi ivaliwe"</string>
     <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Ayikho i-SIM"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="7735360104844653246">"engeza i-SIM"</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="3451467338947610268">"I-SIM ayitholakali noma ayifundeki. engeza i-SIM"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"I-SIM engasebenziseki."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5034635040020685428">"I-SIM yakho iyekiswe ukusebenza unomphela.\n Xhumana nomhlinzeki wakho wesevisi ngokungenazintambo ukuze uthole enye i-SIM."</string>
     <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"I-SIM ikhiyiwe."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"I-SIM ikhiyiwe nge-PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="8489092646014631659">"Ivula i-SIM…"</string>
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index 28b58703b02de7eb05c18c1b16fbae4129d33ce5..565ed1085fb9dc6a58dcf7a01787bfebaca291f8 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -67,23 +67,13 @@
     <!-- When the lock screen is showing and the phone plugged in with incompatible charger. -->
     <string name="keyguard_plugged_in_incompatible_charger"><xliff:g id="percentage">%s</xliff:g> • Issue with charging accessory</string>
 
-    <!-- On the keyguard screen, when pattern lock is disabled, only tell them to press menu to unlock.  This is shown in small font at the bottom. -->
-    <string name="keyguard_instructions_when_pattern_disabled">Press Menu to unlock.</string>
-
     <!-- SIM messages --><skip />
     <!-- When the user inserts a sim card from an unsupported network, it becomes network locked -->
     <string name="keyguard_network_locked_message">Network locked</string>
     <!-- Shown when there is no SIM. -->
     <string name="keyguard_missing_sim_message_short">No SIM</string>
-    <!-- Shown to ask the user to add a SIM. -->
-    <string name="keyguard_missing_sim_instructions">Add a SIM.</string>
-    <!-- Shown to ask the user to add a SIM when sim is missing or not readable. -->
-    <string name="keyguard_missing_sim_instructions_long">The SIM is missing or not readable. Add a SIM.</string>
     <!-- Shown when SIM is permanently disabled. -->
     <string name="keyguard_permanent_disabled_sim_message_short">Unusable SIM.</string>
-    <!-- Shown to inform the user to SIM is permanently deactivated. -->
-    <string name="keyguard_permanent_disabled_sim_instructions">Your SIM has been permanently deactivated.\n
-    Contact your wireless service provider for another SIM.</string>
     <!-- Shown to tell the user that their SIM is locked and they must unlock it. -->
     <string name="keyguard_sim_locked_message">SIM is locked.</string>
     <!-- When the user enters a wrong sim pin too many times, it becomes PUK locked (Pin Unlock Kode) -->
diff --git a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt b/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
new file mode 100644
index 0000000000000000000000000000000000000000..9b7cd704aa2ffcd4701170ce03d6e123145fc0d8
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
@@ -0,0 +1,20 @@
+/*
+ * 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.dagger.qualifiers
+
+import javax.inject.Qualifier
+
+@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class Tracing
diff --git a/packages/SystemUI/shared/src/com/android/systemui/util/TraceUtils.kt b/packages/SystemUI/shared/src/com/android/systemui/util/TraceUtils.kt
index 7b2e1afda7005ffd394980d8279510fbd4b4266e..e4590342972861c8246f8ffadbb20fb746a863d7 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/util/TraceUtils.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/util/TraceUtils.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.
@@ -18,13 +18,25 @@ package com.android.systemui.util
 
 import android.os.Trace
 import android.os.TraceNameSupplier
+import android.util.Log
+import com.android.systemui.util.tracing.TraceContextElement
+import com.android.systemui.util.tracing.TraceData
+import com.android.systemui.util.tracing.TraceData.Companion.FIRST_VALID_SPAN
+import com.android.systemui.util.tracing.TraceData.Companion.INVALID_SPAN
+import com.android.systemui.util.tracing.threadLocalTrace
 import java.util.concurrent.atomic.AtomicInteger
 import kotlin.coroutines.CoroutineContext
 import kotlin.coroutines.EmptyCoroutineContext
+import kotlin.coroutines.coroutineContext
+import kotlin.random.Random
 import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.CoroutineStart
 import kotlinx.coroutines.Deferred
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.Job
 import kotlinx.coroutines.async
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.withContext
 
 /**
  * Run a block within a [Trace] section. Calls [Trace.beginSection] before and [Trace.endSection]
@@ -44,6 +56,10 @@ inline fun <T> traceSection(tag: String, block: () -> T): T =
 
 class TraceUtils {
     companion object {
+        const val TAG = "TraceUtils"
+        private const val DEBUG_COROUTINE_TRACING = false
+        const val DEFAULT_TRACK_NAME = "AsyncTraces"
+
         inline fun traceRunnable(tag: String, crossinline block: () -> Unit): Runnable {
             return Runnable { traceSection(tag) { block() } }
         }
@@ -73,7 +89,7 @@ class TraceUtils {
          * under a single track.
          */
         inline fun <T> traceAsync(method: String, block: () -> T): T =
-            traceAsync("AsyncTraces", method, block)
+            traceAsync(DEFAULT_TRACK_NAME, method, block)
 
         /**
          * Creates an async slice in a track with [trackName] while [block] runs.
@@ -93,16 +109,313 @@ class TraceUtils {
         }
 
         /**
-         * Convenience method to avoid one indentation level when we want to add a trace when
-         * launching a coroutine
+         * Convenience function for calling [CoroutineScope.launch] with [traceCoroutine] enable
+         * tracing.
+         *
+         * @see traceCoroutine
+         */
+        inline fun CoroutineScope.launch(
+            crossinline spanName: () -> String,
+            context: CoroutineContext = EmptyCoroutineContext,
+            // TODO(b/306457056): DO NOT pass CoroutineStart; doing so will regress .odex size
+            crossinline block: suspend CoroutineScope.() -> Unit
+        ): Job = launch(context) { traceCoroutine(spanName) { block() } }
+
+        /**
+         * Convenience function for calling [CoroutineScope.launch] with [traceCoroutine] enable
+         * tracing.
+         *
+         * @see traceCoroutine
+         */
+        inline fun CoroutineScope.launch(
+            spanName: String,
+            context: CoroutineContext = EmptyCoroutineContext,
+            // TODO(b/306457056): DO NOT pass CoroutineStart; doing so will regress .odex size
+            crossinline block: suspend CoroutineScope.() -> Unit
+        ): Job = launch(context) { traceCoroutine(spanName) { block() } }
+
+        /**
+         * Convenience function for calling [CoroutineScope.async] with [traceCoroutine] enable
+         * tracing
+         *
+         * @see traceCoroutine
+         */
+        inline fun <T> CoroutineScope.async(
+            crossinline spanName: () -> String,
+            context: CoroutineContext = EmptyCoroutineContext,
+            // TODO(b/306457056): DO NOT pass CoroutineStart; doing so will regress .odex size
+            crossinline block: suspend CoroutineScope.() -> T
+        ): Deferred<T> = async(context) { traceCoroutine(spanName) { block() } }
+
+        /**
+         * Convenience function for calling [CoroutineScope.async] with [traceCoroutine] enable
+         * tracing.
+         *
+         * @see traceCoroutine
          */
-        fun <T> CoroutineScope.tracedAsync(
-            method: String,
+        inline fun <T> CoroutineScope.async(
+            spanName: String,
             context: CoroutineContext = EmptyCoroutineContext,
-            start: CoroutineStart = CoroutineStart.DEFAULT,
-            block: suspend () -> T
-        ): Deferred<T> {
-            return async(context, start) { traceAsync(method) { block() } }
+            // TODO(b/306457056): DO NOT pass CoroutineStart; doing so will regress .odex size
+            crossinline block: suspend CoroutineScope.() -> T
+        ): Deferred<T> = async(context) { traceCoroutine(spanName) { block() } }
+
+        /**
+         * Convenience function for calling [runBlocking] with [traceCoroutine] to enable tracing.
+         *
+         * @see traceCoroutine
+         */
+        inline fun <T> runBlocking(
+            crossinline spanName: () -> String,
+            context: CoroutineContext,
+            crossinline block: suspend () -> T
+        ): T = runBlocking(context) { traceCoroutine(spanName) { block() } }
+
+        /**
+         * Convenience function for calling [runBlocking] with [traceCoroutine] to enable tracing.
+         *
+         * @see traceCoroutine
+         */
+        inline fun <T> runBlocking(
+            spanName: String,
+            context: CoroutineContext,
+            crossinline block: suspend CoroutineScope.() -> T
+        ): T = runBlocking(context) { traceCoroutine(spanName) { block() } }
+
+        /**
+         * Convenience function for calling [withContext] with [traceCoroutine] to enable tracing.
+         *
+         * @see traceCoroutine
+         */
+        suspend inline fun <T> withContext(
+            spanName: String,
+            context: CoroutineContext,
+            crossinline block: suspend CoroutineScope.() -> T
+        ): T = withContext(context) { traceCoroutine(spanName) { block() } }
+
+        /**
+         * Convenience function for calling [withContext] with [traceCoroutine] to enable tracing.
+         *
+         * @see traceCoroutine
+         */
+        suspend inline fun <T> withContext(
+            crossinline spanName: () -> String,
+            context: CoroutineContext,
+            crossinline block: suspend CoroutineScope.() -> T
+        ): T = withContext(context) { traceCoroutine(spanName) { block() } }
+
+        /**
+         * A hacky way to propagate the value of the COROUTINE_TRACING flag for static usage in this
+         * file. It should only every be set to true during startup. Once true, it cannot be set to
+         * false again.
+         */
+        var coroutineTracingIsEnabled = false
+            set(v) {
+                if (v) field = true
+            }
+
+        /**
+         * Traces a section of work of a `suspend` [block]. The trace sections will appear on the
+         * thread that is currently executing the [block] of work. If the [block] is suspended, all
+         * trace sections added using this API will end until the [block] is resumed, which could
+         * happen either on this thread or on another thread. If a child coroutine is started, it
+         * will inherit the trace sections of its parent. The child will continue to print these
+         * trace sections whether or not the parent coroutine is still running them.
+         *
+         * The current [CoroutineContext] must have a [TraceContextElement] for this API to work.
+         * Otherwise, the trace sections will be dropped.
+         *
+         * For example, in the following trace, Thread #1 ran some work, suspended, then continued
+         * working on Thread #2. Meanwhile, Thread #2 created a new child coroutine which inherited
+         * its trace sections. Then, the original coroutine resumed on Thread #1 before ending.
+         * Meanwhile Thread #3 is still printing trace sections from its parent because they were
+         * copied when it was created. There is no way for the parent to communicate to the child
+         * that it marked these slices as completed. While this might seem counterintuitive, it
+         * allows us to pinpoint the origin of the child coroutine's work.
+         *
+         * ```
+         * Thread #1 | [==== Slice A ====]                        [==== Slice A ====]
+         *           |       [==== B ====]                        [=== B ===]
+         * --------------------------------------------------------------------------------------
+         * Thread #2 |                    [====== Slice A ======]
+         *           |                    [========= B =========]
+         *           |                        [===== C ======]
+         * --------------------------------------------------------------------------------------
+         * Thread #3 |                            [== Slice A ==]                [== Slice A ==]
+         *           |                            [===== B =====]                [===== B =====]
+         *           |                            [===== C =====]                [===== C =====]
+         *           |                                                               [=== D ===]
+         * ```
+         *
+         * @param name The name of the code section to appear in the trace
+         * @see endSlice
+         * @see traceCoroutine
+         */
+        @OptIn(ExperimentalCoroutinesApi::class)
+        suspend inline fun <T> traceCoroutine(
+            spanName: Lazy<String>,
+            crossinline block: suspend () -> T
+        ): T {
+            // For coroutine tracing to work, trace spans must be added and removed even when
+            // tracing is not active (i.e. when TRACE_TAG_APP is disabled). Otherwise, when the
+            // coroutine resumes when tracing is active, we won't know its name.
+            val tracer = getTraceData(spanName)
+            val coroutineSpanCookie = tracer?.beginSpan(spanName.value) ?: INVALID_SPAN
+
+            // For now, also trace to "AsyncTraces". This will allow us to verify the correctness
+            // of the COROUTINE_TRACING feature flag.
+            val asyncTraceCookie =
+                if (Trace.isTagEnabled(Trace.TRACE_TAG_APP))
+                    Random.nextInt(FIRST_VALID_SPAN, Int.MAX_VALUE)
+                else INVALID_SPAN
+            if (asyncTraceCookie != INVALID_SPAN) {
+                Trace.asyncTraceForTrackBegin(
+                    Trace.TRACE_TAG_APP,
+                    DEFAULT_TRACK_NAME,
+                    spanName.value,
+                    asyncTraceCookie
+                )
+            }
+            try {
+                return block()
+            } finally {
+                if (asyncTraceCookie != INVALID_SPAN) {
+                    Trace.asyncTraceForTrackEnd(
+                        Trace.TRACE_TAG_APP,
+                        DEFAULT_TRACK_NAME,
+                        asyncTraceCookie
+                    )
+                }
+                tracer?.endSpan(coroutineSpanCookie)
+            }
+        }
+
+        @OptIn(ExperimentalCoroutinesApi::class)
+        suspend fun getTraceData(spanName: Lazy<String>): TraceData? {
+            if (!coroutineTracingIsEnabled) {
+                logVerbose("Experimental flag COROUTINE_TRACING is off", spanName)
+            } else if (coroutineContext[TraceContextElement] == null) {
+                logVerbose("Current CoroutineContext is missing TraceContextElement", spanName)
+            } else {
+                return threadLocalTrace.get().also {
+                    if (it == null) logVerbose("ThreadLocal TraceData is null", spanName)
+                }
+            }
+            return null
+        }
+
+        private fun logVerbose(logMessage: String, spanName: Lazy<String>) {
+            if (DEBUG_COROUTINE_TRACING && Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG, "$logMessage. Dropping trace section: \"${spanName.value}\"")
+            }
+        }
+
+        /** @see traceCoroutine */
+        suspend inline fun <T> traceCoroutine(
+            spanName: String,
+            crossinline block: suspend () -> T
+        ): T = traceCoroutine(lazyOf(spanName)) { block() }
+
+        /** @see traceCoroutine */
+        suspend inline fun <T> traceCoroutine(
+            crossinline spanName: () -> String,
+            crossinline block: suspend () -> T
+        ): T = traceCoroutine(lazy(LazyThreadSafetyMode.PUBLICATION) { spanName() }) { block() }
+
+        /**
+         * Writes a trace message to indicate that a given section of code has begun running __on
+         * the current thread__. This must be followed by a corresponding call to [endSlice] in a
+         * reasonably short amount of time __on the same thread__ (i.e. _before_ the thread becomes
+         * idle again and starts running other, unrelated work).
+         *
+         * Calls to [beginSlice] and [endSlice] may be nested, and they will render in Perfetto as
+         * follows:
+         * ```
+         * Thread #1 | [==========================]
+         *           |       [==============]
+         *           |           [====]
+         * ```
+         *
+         * This function is provided for convenience to wrap a call to [Trace.traceBegin], which is
+         * more verbose to call than [Trace.beginSection], but has the added benefit of not throwing
+         * an [IllegalArgumentException] if the provided string is longer than 127 characters. We
+         * use the term "slice" instead of "section" to be consistent with Perfetto.
+         *
+         * # Avoiding malformed traces
+         *
+         * Improper usage of this API will lead to malformed traces with long slices that sometimes
+         * never end. This will look like the following:
+         * ```
+         * Thread #1 | [===================================================================== ...
+         *           |       [==============]         [====================================== ...
+         *           |           [=======]              [======]       [===================== ...
+         *           |                                                       [=======]
+         * ```
+         *
+         * To avoid this, [beginSlice] and [endSlice] should never be called from `suspend` blocks
+         * (instead, use [traceCoroutine] for tracing suspending functions). While it would be
+         * technically okay to call from a suspending function if that function were to only wrap
+         * non-suspending blocks with [beginSlice] and [endSlice], doing so is risky because suspend
+         * calls could be mistakenly added to that block as the code is refactored.
+         *
+         * Additionally, it is _not_ okay to call [beginSlice] when registering a callback and match
+         * it with a call to [endSlice] inside that callback, even if the callback runs on the same
+         * thread. Doing so would cause malformed traces because the [beginSlice] wasn't closed
+         * before the thread became idle and started running unrelated work.
+         *
+         * @param sliceName The name of the code section to appear in the trace
+         * @see endSlice
+         * @see traceCoroutine
+         */
+        fun beginSlice(sliceName: String) {
+            Trace.traceBegin(Trace.TRACE_TAG_APP, sliceName)
+        }
+
+        /**
+         * Writes a trace message to indicate that a given section of code has ended. This call must
+         * be preceded by a corresponding call to [beginSlice]. See [beginSlice] for important
+         * information regarding usage.
+         *
+         * @see beginSlice
+         * @see traceCoroutine
+         */
+        fun endSlice() {
+            Trace.traceEnd(Trace.TRACE_TAG_APP)
+        }
+
+        /**
+         * Writes a trace message indicating that an instant event occurred on the current thread.
+         * Unlike slices, instant events have no duration and do not need to be matched with another
+         * call. Perfetto will display instant events using an arrow pointing to the timestamp they
+         * occurred:
+         * ```
+         * Thread #1 | [==============]               [======]
+         *           |     [====]                        ^
+         *           |        ^
+         * ```
+         *
+         * @param eventName The name of the event to appear in the trace.
+         */
+        fun instant(eventName: String) {
+            Trace.instant(Trace.TRACE_TAG_APP, eventName)
+        }
+
+        /**
+         * Writes a trace message indicating that an instant event occurred on the given track.
+         * Unlike slices, instant events have no duration and do not need to be matched with another
+         * call. Perfetto will display instant events using an arrow pointing to the timestamp they
+         * occurred:
+         * ```
+         * Async  | [==============]               [======]
+         *  Track |     [====]                        ^
+         *   Name |        ^
+         * ```
+         *
+         * @param trackName The track where the event should appear in the trace.
+         * @param eventName The name of the event to appear in the trace.
+         */
+        fun instantForTrack(trackName: String, eventName: String) {
+            Trace.instantForTrack(Trace.TRACE_TAG_APP, trackName, eventName)
         }
     }
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/util/tracing/TraceContextElement.kt b/packages/SystemUI/shared/src/com/android/systemui/util/tracing/TraceContextElement.kt
new file mode 100644
index 0000000000000000000000000000000000000000..4d8c5450d880ec6d3e9850aeb96a03c9859506f0
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/util/tracing/TraceContextElement.kt
@@ -0,0 +1,69 @@
+/*
+ * 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.util.tracing
+
+import com.android.systemui.util.TraceUtils.Companion.instant
+import com.android.systemui.util.TraceUtils.Companion.traceCoroutine
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.CopyableThreadContextElement
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.DelicateCoroutinesApi
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+
+/**
+ * Used for safely persisting [TraceData] state when coroutines are suspended and resumed.
+ *
+ * This is internal machinery for [traceCoroutine]. It cannot be made `internal` or `private`
+ * because [traceCoroutine] is a Public-API inline function.
+ *
+ * @see traceCoroutine
+ */
+@OptIn(DelicateCoroutinesApi::class)
+@ExperimentalCoroutinesApi
+class TraceContextElement(private val traceData: TraceData = TraceData()) :
+    CopyableThreadContextElement<TraceData?> {
+
+    companion object Key : CoroutineContext.Key<TraceContextElement>
+
+    override val key: CoroutineContext.Key<TraceContextElement> = Key
+
+    @OptIn(ExperimentalStdlibApi::class)
+    override fun updateThreadContext(context: CoroutineContext): TraceData? {
+        val oldState = threadLocalTrace.get()
+        oldState?.endAllOnThread()
+        threadLocalTrace.set(traceData)
+        instant("resuming ${context[CoroutineDispatcher]}")
+        traceData.beginAllOnThread()
+        return oldState
+    }
+
+    @OptIn(ExperimentalStdlibApi::class)
+    override fun restoreThreadContext(context: CoroutineContext, oldState: TraceData?) {
+        instant("suspending ${context[CoroutineDispatcher]}")
+        traceData.endAllOnThread()
+        threadLocalTrace.set(oldState)
+        oldState?.beginAllOnThread()
+    }
+
+    override fun copyForChild(): CopyableThreadContextElement<TraceData?> {
+        return TraceContextElement(traceData.copy())
+    }
+
+    override fun mergeForChild(overwritingElement: CoroutineContext.Element): CoroutineContext {
+        return TraceContextElement(traceData.copy())
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/util/tracing/TraceData.kt b/packages/SystemUI/shared/src/com/android/systemui/util/tracing/TraceData.kt
new file mode 100644
index 0000000000000000000000000000000000000000..0ae58fc2c45bc107416f175bce4c29c92eeb5cfb
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/util/tracing/TraceData.kt
@@ -0,0 +1,122 @@
+/*
+ * 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.util.tracing
+
+import android.os.Build
+import android.util.Log
+import com.android.systemui.util.TraceUtils.Companion.beginSlice
+import com.android.systemui.util.TraceUtils.Companion.endSlice
+import com.android.systemui.util.TraceUtils.Companion.traceCoroutine
+import kotlin.random.Random
+
+/**
+ * Used for giving each thread a unique [TraceData] for thread-local storage. `null` by default.
+ * [threadLocalTrace] can only be used when it is paired with a [TraceContextElement].
+ *
+ * This ThreadLocal will be `null` if either 1) we aren't in a coroutine, or 2) the coroutine we are
+ * in does not have a [TraceContextElement].
+ *
+ * This is internal machinery for [traceCoroutine]. It cannot be made `internal` or `private`
+ * because [traceCoroutine] is a Public-API inline function.
+ *
+ * @see traceCoroutine
+ */
+val threadLocalTrace = ThreadLocal<TraceData?>()
+
+/**
+ * Used for storing trace sections so that they can be added and removed from the currently running
+ * thread when the coroutine is suspended and resumed.
+ *
+ * This is internal machinery for [traceCoroutine]. It cannot be made `internal` or `private`
+ * because [traceCoroutine] is a Public-API inline function.
+ *
+ * @see traceCoroutine
+ */
+class TraceData {
+    private var slices = mutableListOf<TraceSection>()
+
+    /** Adds current trace slices back to the current thread. Called when coroutine is resumed. */
+    fun beginAllOnThread() {
+        slices.forEach { beginSlice(it.name) }
+    }
+
+    /**
+     * Removes all current trace slices from the current thread. Called when coroutine is suspended.
+     */
+    fun endAllOnThread() {
+        for (i in 0..slices.size) {
+            endSlice()
+        }
+    }
+
+    /**
+     * Creates a new trace section with a unique ID and adds it to the current trace data. The slice
+     * will also be added to the current thread immediately. This slice will not propagate to parent
+     * coroutines, or to child coroutines that have already started. The unique ID is used to verify
+     * that the [endSpan] is corresponds to a [beginSpan].
+     */
+    fun beginSpan(name: String): Int {
+        val newSlice = TraceSection(name, Random.nextInt(FIRST_VALID_SPAN, Int.MAX_VALUE))
+        slices.add(newSlice)
+        beginSlice(name)
+        return newSlice.id
+    }
+
+    /**
+     * Used by [TraceContextElement] when launching a child coroutine so that the child coroutine's
+     * state is isolated from the parent.
+     */
+    fun copy(): TraceData {
+        return TraceData().also { it.slices.addAll(slices) }
+    }
+
+    /**
+     * Ends the trace section and validates it corresponds with an earlier call to [beginSpan]. The
+     * trace slice will immediately be removed from the current thread. This information will not
+     * propagate to parent coroutines, or to child coroutines that have already started.
+     */
+    fun endSpan(id: Int) {
+        val v = slices.removeLast()
+        if (v.id != id) {
+            if (STRICT_MODE) {
+                throw IllegalArgumentException(errorMsg)
+            } else if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG, errorMsg)
+            }
+        }
+        endSlice()
+    }
+
+    companion object {
+        private const val TAG = "TraceData"
+        const val INVALID_SPAN = -1
+        const val FIRST_VALID_SPAN = 1
+
+        /**
+         * If true, throw an exception instead of printing a warning when trace sections beginnings
+         * and ends are mismatched.
+         */
+        private val STRICT_MODE = Build.IS_ENG
+
+        private const val errorMsg =
+            "Mismatched trace section. This likely means you are accessing the trace local " +
+                "storage (threadLocalTrace) without a corresponding CopyableThreadContextElement." +
+                " This could happen if you are using a global dispatcher like Dispatchers.IO." +
+                " To fix this, use one of the coroutine contexts provided by the dagger scope " +
+                "(e.g. \"@Main CoroutineContext\")."
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/util/tracing/TraceSection.kt b/packages/SystemUI/shared/src/com/android/systemui/util/tracing/TraceSection.kt
new file mode 100644
index 0000000000000000000000000000000000000000..b70c4977614a9704a5ab21e64f46c419ce315ca9
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/util/tracing/TraceSection.kt
@@ -0,0 +1,35 @@
+/*
+ * 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.util.tracing
+
+import com.android.systemui.util.TraceUtils.Companion.traceCoroutine
+
+/**
+ * Represents a section of code executing in a coroutine. This can be split up into multiple slices
+ * on different threads as the coroutine is suspended and resumed.
+ *
+ * This is internal machinery for [traceCoroutine]. It cannot be made `internal` or `private`
+ * because [traceCoroutine] is a Public-API inline function.
+ *
+ * @param name the name of the slice to appear on the current thread's track.
+ * @param id used for matching the beginning and end of trace sections and validating correctness
+ * @see traceCoroutine
+ */
+data class TraceSection(
+    val name: String,
+    val id: Int,
+)
diff --git a/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt b/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt
index b186018ba78a22d26a67ce9a0e087476178f1144..375727437b8b8bf78b603f3c82c558374b817a66 100644
--- a/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt
@@ -318,9 +318,8 @@ class ActiveUnlockConfig @Inject constructor(
 
         keyguardUpdateMonitor?.let {
             val anyFaceEnrolled = it.isFaceEnrolled
-            val anyFingerprintEnrolled =
-                    it.getCachedIsUnlockWithFingerprintPossible(
-                            selectedUserInteractor.getSelectedUserId())
+            val anyFingerprintEnrolled = it.isUnlockWithFingerprintPossible(
+                    selectedUserInteractor.getSelectedUserId())
             val udfpsEnrolled = it.isUdfpsEnrolled
 
             if (!anyFaceEnrolled && !anyFingerprintEnrolled) {
@@ -374,9 +373,8 @@ class ActiveUnlockConfig @Inject constructor(
             pw.println("   shouldRequestActiveUnlockOnUnlockIntentFromBiometricEnrollment=" +
                     "${shouldRequestActiveUnlockOnUnlockIntentFromBiometricEnrollment()}")
             pw.println("   faceEnrolled=${it.isFaceEnrolled}")
-            pw.println("   fpEnrolled=${
-                    it.getCachedIsUnlockWithFingerprintPossible(
-                            selectedUserInteractor.getSelectedUserId())}")
+            pw.println("   fpUnlockPossible=${
+                it.isUnlockWithFingerprintPossible(selectedUserInteractor.getSelectedUserId())}")
             pw.println("   udfpsEnrolled=${it.isUdfpsEnrolled}")
         } ?: pw.println("   keyguardUpdateMonitor is uninitialized")
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
index 873c3d9105db853feebef046110fe72c5fd060c0..1cfa816f46122c412e987f6038222b7bd4e43fe3 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
@@ -39,10 +39,10 @@ import androidx.annotation.VisibleForTesting;
 
 import com.android.keyguard.logging.CarrierTextManagerLogger;
 import com.android.settingslib.WirelessUtils;
-import com.android.systemui.res.R;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.res.R;
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository;
 import com.android.systemui.telephony.TelephonyListenerManager;
 
@@ -612,36 +612,6 @@ public class CarrierTextManager {
         return list;
     }
 
-    private CharSequence getCarrierHelpTextForSimState(int simState,
-            String plmn, String spn) {
-        int carrierHelpTextId = 0;
-        CarrierTextManager.StatusMode status = getStatusForIccState(simState);
-        switch (status) {
-            case NetworkLocked:
-                carrierHelpTextId = R.string.keyguard_instructions_when_pattern_disabled;
-                break;
-
-            case SimMissing:
-                carrierHelpTextId = R.string.keyguard_missing_sim_instructions_long;
-                break;
-
-            case SimPermDisabled:
-                carrierHelpTextId = R.string.keyguard_permanent_disabled_sim_instructions;
-                break;
-
-            case SimMissingLocked:
-                carrierHelpTextId = R.string.keyguard_missing_sim_instructions;
-                break;
-
-            case Normal:
-            case SimLocked:
-            case SimPukLocked:
-                break;
-        }
-
-        return mContext.getText(carrierHelpTextId);
-    }
-
     /** Injectable Buildeer for {@#link CarrierTextManager}. */
     public static class Builder {
         private final Context mContext;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 7101ed599b868482f7c5e7dd060845466b50e35f..1b6112f52082831e4510500e2b6d7f777955d4fa 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -755,7 +755,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
         }
         mView.onResume(
                 mSecurityModel.getSecurityMode(mSelectedUserInteractor.getSelectedUserId()),
-                mKeyguardStateController.isFaceAuthEnabled());
+                mKeyguardStateController.isFaceEnrolled());
     }
 
     /** Sets an initial message that would override the default message */
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
index 13f9d3e1038ef8d781e099e469454ad8305cb0f2..05fb5fa75e9ef55610f5cb9af5dceceed3e4288c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
@@ -246,7 +246,7 @@ public class KeyguardSimPukViewController
 
     private boolean checkPuk() {
         // make sure the puk is at least 8 digits long.
-        if (mPasswordEntry.getText().length() == 8) {
+        if (mPasswordEntry.getText().length() >= 8) {
             mPukText = mPasswordEntry.getText();
             return true;
         }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 7d6240b0dc2c045852c78b4b59711126da12b4b1..f19a9ed5546fca9831259a1b060fe0b27c6f65b2 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -441,7 +441,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
     private int mFaceRunningState = BIOMETRIC_STATE_STOPPED;
     private boolean mIsDreaming;
     private boolean mLogoutEnabled;
-    private boolean mIsFaceEnrolled;
     private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
     private int mPostureState = DEVICE_POSTURE_UNKNOWN;
     private FingerprintInteractiveToAuthProvider mFingerprintInteractiveToAuthProvider;
@@ -2083,7 +2082,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
     private boolean mFingerprintLockedOut;
     private boolean mFingerprintLockedOutPermanent;
     private boolean mFaceLockedOutPermanent;
-    private final HashMap<Integer, Boolean> mIsUnlockWithFingerprintPossible = new HashMap<>();
 
     /**
      * When we receive a {@link android.content.Intent#ACTION_SIM_STATE_CHANGED} broadcast,
@@ -2701,16 +2699,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
         }
     }
 
-    private void updateFaceEnrolled(int userId) {
-        final Boolean isFaceEnrolled = isFaceSupported()
-                && mBiometricEnabledForUser.get(userId)
-                && mAuthController.isFaceAuthEnrolled(userId);
-        if (mIsFaceEnrolled != isFaceEnrolled) {
-            mLogger.logFaceEnrolledUpdated(mIsFaceEnrolled, isFaceEnrolled);
-        }
-        mIsFaceEnrolled = isFaceEnrolled;
-    }
-
     private boolean isFaceSupported() {
         return mFaceManager != null && !mFaceSensorProperties.isEmpty();
     }
@@ -2749,11 +2737,18 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
         return mAuthController.isSfpsSupported();
     }
 
+    /**
+     * @return true if there's at least one face enrolled for the given user.
+     */
+    public boolean isFaceEnrolled(int userId) {
+        return mAuthController.isFaceAuthEnrolled(userId);
+    }
+
     /**
      * @return true if there's at least one face enrolled
      */
     public boolean isFaceEnrolled() {
-        return mIsFaceEnrolled;
+        return isFaceEnrolled(mSelectedUserInteractor.getSelectedUserId());
     }
 
     private final UserTracker.Callback mUserChangedCallback = new UserTracker.Callback() {
@@ -3442,49 +3437,22 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
     }
 
     @SuppressLint("MissingPermission")
-    @VisibleForTesting
-    boolean isUnlockWithFingerprintPossible(int userId) {
-        // TODO (b/242022358), make this rely on onEnrollmentChanged event and update it only once.
-        boolean newFpEnrolled = isFingerprintSupported()
-                && !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);
-    }
-
-    /**
-     * Cached value for whether fingerprint is enrolled and possible to use for authentication.
-     * Note: checking fingerprint enrollment directly with the AuthController requires an IPC.
-     */
-    public boolean getCachedIsUnlockWithFingerprintPossible(int userId) {
-        return mIsUnlockWithFingerprintPossible.getOrDefault(userId, false);
+    public boolean isUnlockWithFingerprintPossible(int userId) {
+        return isFingerprintSupported()
+                && !isFingerprintDisabled(userId) && mAuthController.isFingerprintEnrolled(userId);
     }
 
     /**
      * @deprecated This is being migrated to use modern architecture.
      */
+    @VisibleForTesting
     @Deprecated
-    private boolean isUnlockWithFacePossible(int userId) {
+    public boolean isUnlockWithFacePossible(int userId) {
         if (isFaceAuthInteractorEnabled()) {
             return getFaceAuthInteractor() != null
                     && getFaceAuthInteractor().isFaceAuthEnabledAndEnrolled();
         }
-        return isFaceAuthEnabledForUser(userId) && !isFaceDisabled(userId);
-    }
-
-    /**
-     * If face hardware is available, user has enrolled and enabled auth via setting.
-     *
-     * @deprecated This is being migrated to use modern architecture.
-     */
-    @Deprecated
-    public boolean isFaceAuthEnabledForUser(int userId) {
-        // TODO (b/242022358), make this rely on onEnrollmentChanged event and update it only once.
-        updateFaceEnrolled(userId);
-        return mIsFaceEnrolled;
+        return isFaceSupported() && isFaceEnrolled(userId) && !isFaceDisabled(userId);
     }
 
     private void notifyAboutEnrollmentChange(@BiometricAuthenticator.Modality int modality) {
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
index fa07072b7fe1ccdc8f81a74bb93001bb3154e20a..5bf8d635f8ee862f8973f0de6043b2dec950c71c 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
@@ -660,19 +660,6 @@ constructor(@KeyguardUpdateMonitorLog private val logBuffer: LogBuffer) {
         )
     }
 
-    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,
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
index 453a7a6d3536db6ae53a1ab14f485ba4e44f7dde..8ea867bbf3fccef11a3421a01d0bd997716784fe 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
@@ -28,6 +28,8 @@ import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.deviceentry.data.repository.DeviceEntryRepository
 import com.android.systemui.user.data.repository.UserRepository
+import com.android.systemui.util.TraceUtils.Companion.async
+import com.android.systemui.util.TraceUtils.Companion.withContext
 import com.android.systemui.util.time.SystemClock
 import javax.inject.Inject
 import kotlin.math.max
@@ -263,7 +265,7 @@ constructor(
      *   not being throttled.
      */
     private suspend fun refreshThrottling(): Long {
-        return withContext(backgroundDispatcher) {
+        return withContext("$TAG#refreshThrottling", backgroundDispatcher) {
             val failedAttemptCount = async { repository.getFailedAuthenticationAttemptCount() }
             val deadline = async { repository.getThrottlingEndTimestamp() }
             val remainingMs = max(0, deadline.await() - clock.elapsedRealtime())
@@ -311,6 +313,10 @@ constructor(
                 DomainLayerAuthenticationMethodModel.Pattern
         }
     }
+
+    companion object {
+        const val TAG = "AuthenticationInteractor"
+    }
 }
 
 /** Result of a user authentication attempt. */
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
index 21578f491de7e5c2d9223a21f6917b85a58358b0..56dfa5ed337cf103abf4df112e0e4f2fb5fbbad0 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
@@ -415,7 +415,7 @@ constructor(
     /** Whether we want to wait to show the bouncer in case passive auth succeeds. */
     private fun usePrimaryBouncerPassiveAuthDelay(): Boolean {
         val canRunFaceAuth =
-            keyguardStateController.isFaceAuthEnabled &&
+            keyguardStateController.isFaceEnrolled &&
                 keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(BiometricSourceType.FACE) &&
                 keyguardUpdateMonitor.doesCurrentPostureAllowFaceAuth()
         val canRunActiveUnlock =
diff --git a/packages/SystemUI/src/com/android/systemui/complication/ComplicationLayoutEngine.java b/packages/SystemUI/src/com/android/systemui/complication/ComplicationLayoutEngine.java
index 20b2494a6c295fbfee0cafad04519a06663eb9f4..f7b6b0f06a00648ced396a3c9411dca59808597f 100644
--- a/packages/SystemUI/src/com/android/systemui/complication/ComplicationLayoutEngine.java
+++ b/packages/SystemUI/src/com/android/systemui/complication/ComplicationLayoutEngine.java
@@ -652,8 +652,7 @@ public class ComplicationLayoutEngine implements Complication.VisibilityControll
             CrossFadeHelper.fadeOut(
                     mLayout,
                     mFadeOutDuration,
-                    /* delay= */ 0,
-                    /* endRunnable= */ null);
+                    /* delay= */ 0);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/flags/ConditionalRestarter.kt b/packages/SystemUI/src/com/android/systemui/flags/ConditionalRestarter.kt
index 93b00eef08b52a5f5dc523c3bad0abc29cfdf49e..dd5860484a556b95e9a57828589ecab4342ac201 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/ConditionalRestarter.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/ConditionalRestarter.kt
@@ -17,13 +17,13 @@
 package com.android.systemui.flags
 
 import android.util.Log
-import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.flags.ConditionalRestarter.Condition
+import com.android.systemui.util.kotlin.UnflaggedApplication
+import com.android.systemui.util.kotlin.UnflaggedBackground
 import java.util.concurrent.TimeUnit
 import javax.inject.Inject
 import javax.inject.Named
-import kotlinx.coroutines.CoroutineDispatcher
+import kotlin.coroutines.CoroutineContext
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.Flow
@@ -39,8 +39,8 @@ 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,
+    @UnflaggedApplication private val applicationScope: CoroutineScope,
+    @UnflaggedBackground private val backgroundDispatcher: CoroutineContext,
 ) : Restarter {
 
     private var pendingReason = ""
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 10fac4d328e02649cdd20e6fa9110f19f92c691b..8c81fbbaeb9d80162f67ddf3f75ee84504ef5924 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -118,7 +118,7 @@ object Flags {
     // TODO(b/292213543): Tracking Bug
     @JvmField
     val NOTIFICATION_GROUP_EXPANSION_CHANGE =
-            unreleasedFlag("notification_group_expansion_change", teamfood = true)
+            releasedFlag("notification_group_expansion_change")
 
     // TODO(b/301955929)
     @JvmField
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt b/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
index bc0713952ce1653c9fda73b9a39ab236518778bc..6f491d88dab4fdc3e56e2e4ccb320a78a623965e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
@@ -36,9 +36,9 @@ import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor
 import com.android.systemui.keyguard.ui.preview.KeyguardRemotePreviewManager
 import com.android.systemui.shared.customization.data.content.CustomizationProviderContract as Contract
+import com.android.systemui.util.TraceUtils.Companion.runBlocking
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.runBlocking
 
 class CustomizationProvider :
     ContentProvider(), SystemUIAppComponentFactoryBase.ContextInitializer {
@@ -132,7 +132,7 @@ class CustomizationProvider :
             throw UnsupportedOperationException()
         }
 
-        return runBlocking(mainDispatcher) { insertSelection(values) }
+        return runBlocking("$TAG#insert", mainDispatcher) { insertSelection(values) }
     }
 
     override fun query(
@@ -142,7 +142,7 @@ class CustomizationProvider :
         selectionArgs: Array<out String>?,
         sortOrder: String?,
     ): Cursor? {
-        return runBlocking(mainDispatcher) {
+        return runBlocking("$TAG#query", mainDispatcher) {
             when (uriMatcher.match(uri)) {
                 MATCH_CODE_ALL_AFFORDANCES -> queryAffordances()
                 MATCH_CODE_ALL_SLOTS -> querySlots()
@@ -172,7 +172,7 @@ class CustomizationProvider :
             throw UnsupportedOperationException()
         }
 
-        return runBlocking(mainDispatcher) { deleteSelection(uri, selectionArgs) }
+        return runBlocking("$TAG#delete", mainDispatcher) { deleteSelection(uri, selectionArgs) }
     }
 
     override fun call(method: String, arg: String?, extras: Bundle?): Bundle? {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
index 3cdff76881eefa3576e47ffa1b00693fc90c2d46..6a0d5954fc44c65815f4553446bb2ab277846ea2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
@@ -56,6 +56,10 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.user.data.model.SelectionStatus
 import com.android.systemui.user.data.repository.UserRepository
 import com.google.errorprone.annotations.CompileTimeConstant
+import java.io.PrintWriter
+import java.util.Arrays
+import java.util.stream.Collectors
+import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Job
@@ -78,10 +82,6 @@ import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.flow.stateIn
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
-import java.io.PrintWriter
-import java.util.Arrays
-import java.util.stream.Collectors
-import javax.inject.Inject
 
 /**
  * API to run face authentication and detection for device entry / on keyguard (as opposed to the
@@ -368,10 +368,12 @@ constructor(
         return arrayOf(
             Pair(
                 and(
-                    displayStateInteractor.isDefaultDisplayOff,
-                    keyguardTransitionInteractor.isFinishedInStateWhere(
-                            KeyguardState::deviceIsAwakeInState),
-                ).isFalse(),
+                        displayStateInteractor.isDefaultDisplayOff,
+                        keyguardTransitionInteractor.isFinishedInStateWhere(
+                            KeyguardState::deviceIsAwakeInState
+                        ),
+                    )
+                    .isFalse(),
                 // this can happen if an app is requesting for screen off, the display can
                 // turn off without wakefulness.isStartingToSleepOrAsleep calls
                 "displayIsNotOffWhileFullyTransitionedToAwake",
@@ -381,10 +383,7 @@ constructor(
                 "isFaceAuthEnrolledAndEnabled"
             ),
             Pair(keyguardRepository.isKeyguardGoingAway.isFalse(), "keyguardNotGoingAway"),
-            Pair(
-                powerInteractor.isAsleep.isFalse(),
-                "deviceNotAsleep"
-            ),
+            Pair(powerInteractor.isAsleep.isFalse(), "deviceNotAsleep"),
             Pair(
                 keyguardInteractor.isSecureCameraActive
                     .isFalse()
@@ -430,10 +429,15 @@ constructor(
     private val faceAuthCallback =
         object : FaceManager.AuthenticationCallback() {
             override fun onAuthenticationFailed() {
-                _authenticationStatus.value = FailedFaceAuthenticationStatus()
                 _isAuthenticated.value = false
                 faceAuthLogger.authenticationFailed()
-                onFaceAuthRequestCompleted()
+                if (!_isLockedOut.value) {
+                    // onAuthenticationError gets invoked before onAuthenticationFailed when the
+                    // last auth attempt locks out face authentication.
+                    // Skip updating the authentication status in such a scenario.
+                    _authenticationStatus.value = FailedFaceAuthenticationStatus()
+                    onFaceAuthRequestCompleted()
+                }
             }
 
             override fun onAuthenticationAcquired(acquireInfo: Int) {
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 d44a9d86a731762f665b03bc49bdf25a190b6874..95ac0d8a29997e245d279876dc5e3a6c90a251d3 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
@@ -31,6 +31,7 @@ import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled
 import com.android.systemui.keyguard.shared.model.TransitionState
 import com.android.systemui.power.domain.interactor.PowerInteractor
 import com.android.systemui.shade.data.repository.ShadeRepository
+import com.android.systemui.util.TraceUtils.Companion.launch
 import com.android.systemui.util.kotlin.Utils.Companion.toQuad
 import com.android.systemui.util.kotlin.Utils.Companion.toTriple
 import com.android.systemui.util.kotlin.sample
@@ -43,7 +44,6 @@ import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onStart
-import kotlinx.coroutines.launch
 
 @SysUISingleton
 class FromLockscreenTransitionInteractor
@@ -136,7 +136,7 @@ constructor(
 
     private fun listenForLockscreenToDreaming() {
         val invalidFromStates = setOf(KeyguardState.AOD, KeyguardState.DOZING)
-        scope.launch {
+        scope.launch("$TAG#listenForLockscreenToDreaming") {
             keyguardInteractor.isAbleToDream
                 .sample(
                     combine(
@@ -169,7 +169,7 @@ constructor(
     }
 
     private fun listenForLockscreenToPrimaryBouncer() {
-        scope.launch {
+        scope.launch("$TAG#listenForLockscreenToPrimaryBouncer") {
             keyguardInteractor.primaryBouncerShowing
                 .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
                 .collect { pair ->
@@ -184,7 +184,7 @@ constructor(
     }
 
     private fun listenForLockscreenToAlternateBouncer() {
-        scope.launch {
+        scope.launch("$TAG#listenForLockscreenToAlternateBouncer") {
             keyguardInteractor.alternateBouncerShowing
                 .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
                 .collect { pair ->
@@ -202,7 +202,7 @@ constructor(
     /* Starts transitions when manually dragging up the bouncer from the lockscreen. */
     private fun listenForLockscreenToPrimaryBouncerDragging() {
         var transitionId: UUID? = null
-        scope.launch {
+        scope.launch("$TAG#listenForLockscreenToPrimaryBouncerDragging") {
             shadeRepository.shadeModel
                 .sample(
                     combine(
@@ -287,7 +287,7 @@ constructor(
             return
         }
 
-        scope.launch {
+        scope.launch("$TAG#listenForLockscreenToGone") {
             keyguardInteractor.isKeyguardGoingAway
                 .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
                 .collect { pair ->
@@ -304,7 +304,7 @@ constructor(
             return
         }
 
-        scope.launch {
+        scope.launch("$TAG#listenForLockscreenToGoneDragging") {
             keyguardInteractor.isKeyguardGoingAway
                 .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
                 .collect { pair ->
@@ -317,7 +317,7 @@ constructor(
     }
 
     private fun listenForLockscreenToOccluded() {
-        scope.launch {
+        scope.launch("$TAG#listenForLockscreenToOccluded") {
             keyguardInteractor.isKeyguardOccluded
                 .sample(transitionInteractor.startedKeyguardState, ::Pair)
                 .collect { (isOccluded, keyguardState) ->
@@ -329,7 +329,7 @@ constructor(
     }
 
     private fun listenForLockscreenToAodOrDozing() {
-        scope.launch {
+        scope.launch("$TAG#listenForLockscreenToAodOrDozing") {
             powerInteractor.isAsleep
                 .sample(
                     combine(
@@ -375,6 +375,7 @@ constructor(
     }
 
     companion object {
+        const val TAG = "FromLockscreenTransitionInteractor"
         private val DEFAULT_DURATION = 400.milliseconds
         val TO_DREAMING_DURATION = 933.milliseconds
         val TO_OCCLUDED_DURATION = 450.milliseconds
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 de791aa23e226083f815fe443d517f6facda99e3..fe9370fd8ce9f9f828a4427ba6441e00c85f641f 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
@@ -23,7 +23,6 @@ import android.content.Context
 import android.content.Intent
 import android.util.Log
 import com.android.internal.widget.LockPatternUtils
-import com.android.systemui.res.R
 import com.android.systemui.animation.DialogLaunchAnimator
 import com.android.systemui.animation.Expandable
 import com.android.systemui.dagger.SysUISingleton
@@ -44,11 +43,12 @@ import com.android.systemui.keyguard.shared.model.KeyguardSlotPickerRepresentati
 import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition
 import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLogger
 import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.res.R
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.shared.customization.data.content.CustomizationProviderContract as Contract
 import com.android.systemui.statusbar.phone.SystemUIDialog
 import com.android.systemui.statusbar.policy.KeyguardStateController
-import com.android.systemui.util.TraceUtils.Companion.traceAsync
+import com.android.systemui.util.TraceUtils.Companion.withContext
 import dagger.Lazy
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
@@ -59,7 +59,6 @@ import kotlinx.coroutines.flow.flatMapLatest
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onStart
-import kotlinx.coroutines.withContext
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SysUISingleton
@@ -417,10 +416,8 @@ constructor(
     }
 
     private suspend fun isFeatureDisabledByDevicePolicy(): Boolean =
-        traceAsync(TAG, "isFeatureDisabledByDevicePolicy") {
-            withContext(backgroundDispatcher) {
-                devicePolicyManager.areKeyguardShortcutsDisabled(userId = userTracker.userId)
-            }
+        withContext("$TAG#isFeatureDisabledByDevicePolicy", backgroundDispatcher) {
+            devicePolicyManager.areKeyguardShortcutsDisabled(userId = userTracker.userId)
         }
 
     companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/log/table/Diffable.kt b/packages/SystemUI/src/com/android/systemui/log/table/Diffable.kt
index 565bf241a1946ffad95a3f56a19899911964c0be..baa07c14ae0494d888a5d155a5cf321f6c961899 100644
--- a/packages/SystemUI/src/com/android/systemui/log/table/Diffable.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/table/Diffable.kt
@@ -95,7 +95,7 @@ fun Flow<Boolean>.logDiffsForTable(
         tableLogBuffer.logChange(columnPrefix, columnName, initialValue, isInitial = true)
         initialValue
     }
-    return this.pairwiseBy(initialValueFun) { prevVal, newVal: Boolean ->
+    return this.pairwiseBy(initialValueFun) { prevVal: Boolean, newVal: Boolean ->
         if (prevVal != newVal) {
             tableLogBuffer.logChange(columnPrefix, columnName, newVal)
         }
@@ -114,7 +114,7 @@ fun Flow<Int>.logDiffsForTable(
         tableLogBuffer.logChange(columnPrefix, columnName, initialValue, isInitial = true)
         initialValue
     }
-    return this.pairwiseBy(initialValueFun) { prevVal, newVal: Int ->
+    return this.pairwiseBy(initialValueFun) { prevVal: Int, newVal: Int ->
         if (prevVal != newVal) {
             tableLogBuffer.logChange(columnPrefix, columnName, newVal)
         }
@@ -133,7 +133,7 @@ fun Flow<Int?>.logDiffsForTable(
         tableLogBuffer.logChange(columnPrefix, columnName, initialValue, isInitial = true)
         initialValue
     }
-    return this.pairwiseBy(initialValueFun) { prevVal, newVal: Int? ->
+    return this.pairwiseBy(initialValueFun) { prevVal: Int?, newVal: Int? ->
         if (prevVal != newVal) {
             tableLogBuffer.logChange(columnPrefix, columnName, newVal)
         }
@@ -152,7 +152,7 @@ fun Flow<String?>.logDiffsForTable(
         tableLogBuffer.logChange(columnPrefix, columnName, initialValue, isInitial = true)
         initialValue
     }
-    return this.pairwiseBy(initialValueFun) { prevVal, newVal: String? ->
+    return this.pairwiseBy(initialValueFun) { prevVal: String?, newVal: String? ->
         if (prevVal != newVal) {
             tableLogBuffer.logChange(columnPrefix, columnName, newVal)
         }
@@ -176,7 +176,7 @@ fun <T> Flow<List<T>>.logDiffsForTable(
         )
         initialValue
     }
-    return this.pairwiseBy(initialValueFun) { prevVal, newVal: List<T> ->
+    return this.pairwiseBy(initialValueFun) { prevVal: List<T>, newVal: List<T> ->
         if (prevVal != newVal) {
             // TODO(b/267761156): Can we log list changes without using toString?
             tableLogBuffer.logChange(columnPrefix, columnName, newVal.toString())
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 051eeb0cfaf1e229aa4c747c470c453ade111323..bd13d0686462bc256232641c54eaa175c2d2a2a5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -48,6 +48,7 @@ import android.widget.Switch;
 import androidx.annotation.Nullable;
 import androidx.annotation.WorkerThread;
 
+import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.animation.ActivityLaunchAnimator;
@@ -538,12 +539,17 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener,
             Log.i(TAG, "Launching activity before click");
         } else {
             Log.i(TAG, "The activity is starting");
-            ActivityLaunchAnimator.Controller controller = mViewClicked == null
-                    ? null
-                    : ActivityLaunchAnimator.Controller.fromView(mViewClicked, 0);
-            mUiHandler.post(() ->
-                    mActivityStarter.startPendingIntentDismissingKeyguard(
-                            pendingIntent, null, controller)
+
+            ActivityLaunchAnimator.Controller controller =
+                    mViewClicked == null ? null :
+                    ActivityLaunchAnimator.Controller.fromView(
+                            mViewClicked,
+                            InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE
+                    );
+            mActivityStarter.startPendingIntentMaybeDismissingKeyguard(
+                    pendingIntent,
+                    /* intentSentUiThreadCallback= */ null,
+                    controller
             );
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt
index f0650d34fc9db06bd19f49ee6e1b5052700626d4..9ba02b1aa9a86064a46d839ee60dc7d784342781 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt
@@ -17,6 +17,8 @@
 package com.android.systemui.scene.shared.flag
 
 import androidx.annotation.VisibleForTesting
+import com.android.systemui.FeatureFlags
+import com.android.systemui.Flags as AConfigFlags
 import com.android.systemui.compose.ComposeFacade
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.flags.FeatureFlagsClassic
@@ -47,15 +49,15 @@ interface SceneContainerFlags {
 class SceneContainerFlagsImpl
 @AssistedInject
 constructor(
-    private val featureFlags: FeatureFlagsClassic,
+    private val featureFlagsClassic: FeatureFlagsClassic,
+    featureFlags: FeatureFlags,
     @Assisted private val isComposeAvailable: Boolean,
 ) : SceneContainerFlags {
 
     companion object {
         @VisibleForTesting
-        val flags: List<Flag<Boolean>> =
+        val classicFlagTokens: List<Flag<Boolean>> =
             listOf(
-                Flags.SCENE_CONTAINER,
                 Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA,
                 Flags.MIGRATE_LOCK_ICON,
                 Flags.MIGRATE_NSSL,
@@ -67,7 +69,13 @@ constructor(
 
     /** The list of requirements, all must be met for the feature to be enabled. */
     private val requirements =
-        flags.map { FlagMustBeEnabled(it) } +
+        listOf(
+            AconfigFlagMustBeEnabled(
+                flagName = AConfigFlags.FLAG_SCENE_CONTAINER,
+                flagValue = featureFlags.sceneContainer(),
+            ),
+        ) +
+            classicFlagTokens.map { flagToken -> FlagMustBeEnabled(flagToken) } +
             listOf(ComposeMustBeAvailable(), CompileTimeFlagMustBeEnabled())
 
     override fun isEnabled(): Boolean {
@@ -115,14 +123,25 @@ constructor(
 
         override fun isMet(): Boolean {
             return when (flag) {
-                is ResourceBooleanFlag -> featureFlags.isEnabled(flag)
-                is ReleasedFlag -> featureFlags.isEnabled(flag)
-                is UnreleasedFlag -> featureFlags.isEnabled(flag)
+                is ResourceBooleanFlag -> featureFlagsClassic.isEnabled(flag)
+                is ReleasedFlag -> featureFlagsClassic.isEnabled(flag)
+                is UnreleasedFlag -> featureFlagsClassic.isEnabled(flag)
                 else -> error("Unsupported flag type ${flag.javaClass}")
             }
         }
     }
 
+    private inner class AconfigFlagMustBeEnabled(
+        flagName: String,
+        private val flagValue: Boolean,
+    ) : Requirement {
+        override val name: String = "Aconfig flag $flagName must be enabled"
+
+        override fun isMet(): Boolean {
+            return flagValue
+        }
+    }
+
     @AssistedFactory
     interface Factory {
         fun create(isComposeAvailable: Boolean): SceneContainerFlagsImpl
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt
index aa6bfc3473d2d8628652a37ea3ef23d15bd27fe1..10d5f597105a9aee449ee2ddc42b8cb7f8c0e95f 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt
@@ -34,11 +34,11 @@ import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.settings.DisplayTracker
+import com.android.systemui.util.TraceUtils.Companion.launch
 import javax.inject.Inject
 import kotlinx.coroutines.CompletableDeferred
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
 
 @SysUISingleton
@@ -63,7 +63,9 @@ constructor(
         user: UserHandle,
         overrideTransition: Boolean,
     ) {
-        applicationScope.launch { launchIntent(intent, options, user, overrideTransition) }
+        applicationScope.launch("$TAG#launchIntentAsync") {
+            launchIntent(intent, options, user, overrideTransition)
+        }
     }
 
     suspend fun launchIntent(
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt
index c34fd42e2154d1db9f179b69896bbb737934443b..f1c74c1bcff60b0ec5f56e87ac65e9c01cc45e99 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt
@@ -20,10 +20,10 @@ import android.util.Log
 import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.util.TraceUtils.Companion.launch
+import kotlinx.coroutines.CoroutineScope
 import java.util.function.Consumer
 import javax.inject.Inject
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.launch
 
 /** Processes a screenshot request sent from [ScreenshotHelper]. */
 interface ScreenshotRequestProcessor {
@@ -88,7 +88,7 @@ constructor(
      *                 thread
      */
     fun processAsync(screenshot: ScreenshotData, callback: Consumer<ScreenshotData>) {
-        mainScope.launch {
+        mainScope.launch({ "$TAG#processAsync" }) {
             val result = process(screenshot)
             callback.accept(result)
         }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt
index 14e875d28f8f96f6f23030d13478c828ae19c127..d2e47946441b36e30b9e1f250cb1ef57593badcf 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt
@@ -25,7 +25,7 @@ import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.shade.ShadeExpansionStateManager
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.launch
+import com.android.systemui.util.TraceUtils.Companion.launch
 import kotlinx.coroutines.withContext
 
 /** Provides state from the main SystemUI process on behalf of the Screenshot process. */
@@ -47,7 +47,9 @@ constructor(
             }
 
             override fun dismissKeyguard(callback: IOnDoneCallback) {
-                lifecycleScope.launch { executeAfterDismissing(callback) }
+                lifecycleScope.launch("IScreenshotProxy#dismissKeyguard") {
+                    executeAfterDismissing(callback)
+                }
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSoundController.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSoundController.kt
index cd0cab556c4d090083fda3a6c8f90dbba4aae88a..1eae1918c4c7aab945a4c1457f0ff1e34056ebc5 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSoundController.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSoundController.kt
@@ -20,7 +20,7 @@ import android.media.MediaPlayer
 import android.util.Log
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.util.TraceUtils.Companion.tracedAsync
+import com.android.systemui.util.TraceUtils.Companion.async
 import com.google.errorprone.annotations.CanIgnoreReturnValue
 import javax.inject.Inject
 import kotlin.time.Duration.Companion.seconds
@@ -48,7 +48,7 @@ constructor(
 ) : ScreenshotSoundController {
 
     val player: Deferred<MediaPlayer?> =
-        coroutineScope.tracedAsync("loadCameraSound", bgDispatcher) {
+        coroutineScope.async("loadCameraSound", bgDispatcher) {
             try {
                 soundProvider.getScreenshotSound()
             } catch (e: IllegalStateException) {
@@ -58,12 +58,10 @@ constructor(
         }
 
     override fun playCameraSound(): Deferred<Unit> {
-        return coroutineScope.tracedAsync("playCameraSound", bgDispatcher) {
-            player.await()?.start()
-        }
+        return coroutineScope.async("playCameraSound", bgDispatcher) { player.await()?.start() }
     }
     override fun releaseScreenshotSound(): Deferred<Unit> {
-        return coroutineScope.tracedAsync("releaseScreenshotSound", bgDispatcher) {
+        return coroutineScope.async("releaseScreenshotSound", bgDispatcher) {
             try {
                 withTimeout(1.seconds) { player.await()?.release() }
             } catch (e: TimeoutCancellationException) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt
index 25ee8d80d4f55aea62849424fb201c4fd433b01c..5684605601c9d38daa305239a72c40e413f64d2a 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt
@@ -13,11 +13,11 @@ import com.android.systemui.display.data.repository.DisplayRepository
 import com.android.systemui.res.R
 import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_CAPTURE_FAILED
 import com.android.systemui.screenshot.TakeScreenshotService.RequestCallback
+import com.android.systemui.util.TraceUtils.Companion.launch
 import java.util.function.Consumer
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.first
-import kotlinx.coroutines.launch
 
 /**
  * Receives the signal to take a screenshot from [TakeScreenshotService], and calls back with the
@@ -176,7 +176,7 @@ constructor(
         onSaved: Consumer<Uri>,
         requestCallback: RequestCallback
     ) {
-        mainScope.launch {
+        mainScope.launch("TakeScreenshotService#executeScreenshotsAsync") {
             executeScreenshots(screenshotRequest, { uri -> onSaved.accept(uri) }, requestCallback)
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index 3d3447b921fc37a5c2504ad9f368b71336adf9b5..a2627eddf05de1e896df0ed62e0092716f3c1140 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -65,7 +65,7 @@ import com.android.systemui.statusbar.NotificationInsetsController;
 import com.android.systemui.statusbar.NotificationShadeDepthController;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
-import com.android.systemui.statusbar.notification.data.repository.NotificationExpansionRepository;
+import com.android.systemui.statusbar.notification.domain.interactor.NotificationLaunchAnimationInteractor;
 import com.android.systemui.statusbar.notification.stack.AmbientState;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
@@ -182,7 +182,7 @@ public class NotificationShadeWindowViewController implements Dumpable {
             PrimaryBouncerToGoneTransitionViewModel primaryBouncerToGoneTransitionViewModel,
             CommunalViewModel communalViewModel,
             CommunalRepository communalRepository,
-            NotificationExpansionRepository notificationExpansionRepository,
+            NotificationLaunchAnimationInteractor notificationLaunchAnimationInteractor,
             FeatureFlagsClassic featureFlagsClassic,
             SystemClock clock,
             BouncerMessageInteractor bouncerMessageInteractor,
@@ -239,7 +239,7 @@ public class NotificationShadeWindowViewController implements Dumpable {
                 mLockscreenToDreamingTransition);
         collectFlow(
                 mView,
-                notificationExpansionRepository.isExpandAnimationRunning(),
+                notificationLaunchAnimationInteractor.isLaunchAnimationRunning(),
                 this::setExpandAnimationRunning);
 
         mClock = clock;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
index 77b095802b00e8d5becda654dd59e3be43f04376..7d81e55d336a2ff06a21e5bd5be210180e264017 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
@@ -16,7 +16,9 @@
 
 package com.android.systemui.statusbar;
 
+import android.animation.Animator;
 import android.view.View;
+import android.view.ViewPropertyAnimator;
 
 import androidx.annotation.Nullable;
 
@@ -31,32 +33,58 @@ public class CrossFadeHelper {
     public static final long ANIMATION_DURATION_LENGTH = 210;
 
     public static void fadeOut(final View view) {
-        fadeOut(view, null);
+        fadeOut(view, (Runnable) null);
     }
 
     public static void fadeOut(final View view, final Runnable endRunnable) {
         fadeOut(view, ANIMATION_DURATION_LENGTH, 0, endRunnable);
     }
 
+    public static void fadeOut(final View view, final Animator.AnimatorListener listener) {
+        fadeOut(view, ANIMATION_DURATION_LENGTH, 0, listener);
+    }
+
+    public static void fadeOut(final View view, long duration, int delay) {
+        fadeOut(view, duration, delay, (Runnable) null);
+    }
+
     public static void fadeOut(final View view, long duration, int delay,
-            final Runnable endRunnable) {
+            @Nullable final Runnable endRunnable) {
         view.animate().cancel();
         view.animate()
                 .alpha(0f)
                 .setDuration(duration)
                 .setInterpolator(Interpolators.ALPHA_OUT)
                 .setStartDelay(delay)
-                .withEndAction(new Runnable() {
-                    @Override
-                    public void run() {
-                        if (endRunnable != null) {
-                            endRunnable.run();
-                        }
-                        if (view.getVisibility() != View.GONE) {
-                            view.setVisibility(View.INVISIBLE);
-                        }
+                .withEndAction(() -> {
+                    if (endRunnable != null) {
+                        endRunnable.run();
+                    }
+                    if (view.getVisibility() != View.GONE) {
+                        view.setVisibility(View.INVISIBLE);
+                    }
+                });
+        if (view.hasOverlappingRendering()) {
+            view.animate().withLayer();
+        }
+    }
+
+    public static void fadeOut(final View view, long duration, int delay,
+            @Nullable final Animator.AnimatorListener listener) {
+        view.animate().cancel();
+        ViewPropertyAnimator animator = view.animate()
+                .alpha(0f)
+                .setDuration(duration)
+                .setInterpolator(Interpolators.ALPHA_OUT)
+                .setStartDelay(delay)
+                .withEndAction(() -> {
+                    if (view.getVisibility() != View.GONE) {
+                        view.setVisibility(View.INVISIBLE);
                     }
                 });
+        if (listener != null) {
+            animator.setListener(listener);
+        }
         if (view.hasOverlappingRendering()) {
             view.animate().withLayer();
         }
@@ -119,8 +147,12 @@ public class CrossFadeHelper {
         fadeIn(view, ANIMATION_DURATION_LENGTH, /* delay= */ 0, endRunnable);
     }
 
+    public static void fadeIn(final View view, Animator.AnimatorListener listener) {
+        fadeIn(view, ANIMATION_DURATION_LENGTH, /* delay= */ 0, listener);
+    }
+
     public static void fadeIn(final View view, long duration, int delay) {
-        fadeIn(view, duration, delay, /* endRunnable= */ null);
+        fadeIn(view, duration, delay, /* endRunnable= */ (Runnable) null);
     }
 
     public static void fadeIn(final View view, long duration, int delay,
@@ -141,6 +173,26 @@ public class CrossFadeHelper {
         }
     }
 
+    public static void fadeIn(final View view, long duration, int delay,
+            @Nullable Animator.AnimatorListener listener) {
+        view.animate().cancel();
+        if (view.getVisibility() == View.INVISIBLE) {
+            view.setAlpha(0.0f);
+            view.setVisibility(View.VISIBLE);
+        }
+        ViewPropertyAnimator animator = view.animate()
+                .alpha(1f)
+                .setDuration(duration)
+                .setStartDelay(delay)
+                .setInterpolator(Interpolators.ALPHA_IN);
+        if (listener != null) {
+            animator.setListener(listener);
+        }
+        if (view.hasOverlappingRendering() && view.getLayerType() != View.LAYER_TYPE_HARDWARE) {
+            view.animate().withLayer();
+        }
+    }
+
     public static void fadeIn(View view, float fadeInAmount) {
         fadeIn(view, fadeInAmount, false /* remap */);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 2f1b589899a0295a9bb0280d968fc29b6c3325f2..dd24ca78005f41f6a5b501d9819b2548173715d5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -1457,7 +1457,7 @@ public class KeyguardIndicationController {
     }
 
     private boolean canUnlockWithFingerprint() {
-        return mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
+        return mKeyguardUpdateMonitor.isUnlockWithFingerprintPossible(
                 getCurrentUser()) && mKeyguardUpdateMonitor.isUnlockingWithFingerprintAllowed();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
index ff4570ea0fc5ead2b39469ddaf3bb1c2a26c00bb..2e1e395518a00be9b9149b7a9b2b988e4cd50e8b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
@@ -29,8 +29,11 @@ import android.util.Log;
 
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.flags.FeatureFlagsClassic;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.plugins.PluginManager;
 import com.android.systemui.statusbar.dagger.CentralSurfacesModule;
+import com.android.systemui.statusbar.domain.interactor.SilentNotificationStatusIconsVisibilityInteractor;
 import com.android.systemui.statusbar.notification.collection.NotifCollection;
 import com.android.systemui.statusbar.notification.collection.PipelineDumpable;
 import com.android.systemui.statusbar.notification.collection.PipelineDumper;
@@ -59,7 +62,9 @@ public class NotificationListener extends NotificationListenerWithPlugins implem
     private static final long MAX_RANKING_DELAY_MILLIS = 500L;
 
     private final Context mContext;
+    private final FeatureFlagsClassic mFeatureFlags;
     private final NotificationManager mNotificationManager;
+    private final SilentNotificationStatusIconsVisibilityInteractor mStatusIconInteractor;
     private final SystemClock mSystemClock;
     private final Executor mMainExecutor;
     private final List<NotificationHandler> mNotificationHandlers = new ArrayList<>();
@@ -75,13 +80,17 @@ public class NotificationListener extends NotificationListenerWithPlugins implem
     @Inject
     public NotificationListener(
             Context context,
+            FeatureFlagsClassic featureFlags,
             NotificationManager notificationManager,
+            SilentNotificationStatusIconsVisibilityInteractor statusIconInteractor,
             SystemClock systemClock,
             @Main Executor mainExecutor,
             PluginManager pluginManager) {
         super(pluginManager);
         mContext = context;
+        mFeatureFlags = featureFlags;
         mNotificationManager = notificationManager;
+        mStatusIconInteractor = statusIconInteractor;
         mSystemClock = systemClock;
         mMainExecutor = mainExecutor;
     }
@@ -95,6 +104,7 @@ public class NotificationListener extends NotificationListenerWithPlugins implem
     }
 
     /** Registers a listener that's notified when any notification-related settings change. */
+    @Deprecated
     public void addNotificationSettingsListener(NotificationSettingsListener listener) {
         mSettingsListeners.add(listener);
     }
@@ -230,8 +240,12 @@ public class NotificationListener extends NotificationListenerWithPlugins implem
 
     @Override
     public void onSilentStatusBarIconsVisibilityChanged(boolean hideSilentStatusIcons) {
-        for (NotificationSettingsListener listener : mSettingsListeners) {
-            listener.onStatusBarIconsBehaviorChanged(hideSilentStatusIcons);
+        if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_ICON_CONTAINER_REFACTOR)) {
+            mStatusIconInteractor.setHideSilentStatusIcons(hideSilentStatusIcons);
+        } else {
+            for (NotificationSettingsListener listener : mSettingsListeners) {
+                listener.onStatusBarIconsBehaviorChanged(hideSilentStatusIcons);
+            }
         }
     }
 
@@ -294,6 +308,7 @@ public class NotificationListener extends NotificationListenerWithPlugins implem
         return ranking;
     }
 
+    @Deprecated
     public interface NotificationSettingsListener {
 
         default void onStatusBarIconsBehaviorChanged(boolean hideSilentStatusIcons) { }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/NotificationListenerSettingsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/NotificationListenerSettingsRepository.kt
new file mode 100644
index 0000000000000000000000000000000000000000..2c706a5327f28c4420dce2fc721cae3eaa7e3f97
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/NotificationListenerSettingsRepository.kt
@@ -0,0 +1,28 @@
+/*
+ * 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.data.repository
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.NotificationListener
+import javax.inject.Inject
+import kotlinx.coroutines.flow.MutableStateFlow
+
+/** Exposes state pertaining to settings tracked over the [NotificationListener] boundary. */
+@SysUISingleton
+class NotificationListenerSettingsRepository @Inject constructor() {
+    /** Should icons for silent notifications be shown in the status bar? */
+    val showSilentStatusIcons = MutableStateFlow(true)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/domain/interactor/SilentNotificationStatusIconsVisibilityInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/domain/interactor/SilentNotificationStatusIconsVisibilityInteractor.kt
new file mode 100644
index 0000000000000000000000000000000000000000..1248b1c1cbb09073f38014d9e018cd0a8178acce
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/domain/interactor/SilentNotificationStatusIconsVisibilityInteractor.kt
@@ -0,0 +1,28 @@
+/*
+ * 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.domain.interactor
+
+import com.android.systemui.statusbar.data.repository.NotificationListenerSettingsRepository
+import javax.inject.Inject
+
+class SilentNotificationStatusIconsVisibilityInteractor
+@Inject
+constructor(private val repository: NotificationListenerSettingsRepository) {
+    /** Set whether icons for silent notifications be hidden in the status bar. */
+    fun setHideSilentStatusIcons(hideIcons: Boolean) {
+        repository.showSilentStatusIcons.value = !hideIcons
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
index 756151bd57e0c03ce4b834ce2fe8073e92aa82ac..96279e2d2e449dffb227f4d28022afdd517fae5f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
@@ -21,7 +21,7 @@ import android.view.ViewGroup
 import com.android.internal.jank.InteractionJankMonitor
 import com.android.systemui.animation.ActivityLaunchAnimator
 import com.android.systemui.animation.LaunchAnimator
-import com.android.systemui.statusbar.notification.data.repository.NotificationExpansionRepository
+import com.android.systemui.statusbar.notification.domain.interactor.NotificationLaunchAnimationInteractor
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer
 import com.android.systemui.statusbar.policy.HeadsUpManager
@@ -33,7 +33,7 @@ private const val TAG = "NotificationLaunchAnimatorController"
 
 /** A provider of [NotificationLaunchAnimatorController]. */
 class NotificationLaunchAnimatorControllerProvider(
-    private val notificationExpansionRepository: NotificationExpansionRepository,
+    private val notificationLaunchAnimationInteractor: NotificationLaunchAnimationInteractor,
     private val notificationListContainer: NotificationListContainer,
     private val headsUpManager: HeadsUpManager,
     private val jankMonitor: InteractionJankMonitor
@@ -44,7 +44,7 @@ class NotificationLaunchAnimatorControllerProvider(
         onFinishAnimationCallback: Runnable? = null
     ): NotificationLaunchAnimatorController {
         return NotificationLaunchAnimatorController(
-            notificationExpansionRepository,
+            notificationLaunchAnimationInteractor,
             notificationListContainer,
             headsUpManager,
             notification,
@@ -60,7 +60,7 @@ class NotificationLaunchAnimatorControllerProvider(
  * notification expanding into an opening window.
  */
 class NotificationLaunchAnimatorController(
-    private val notificationExpansionRepository: NotificationExpansionRepository,
+    private val notificationLaunchAnimationInteractor: NotificationLaunchAnimationInteractor,
     private val notificationListContainer: NotificationListContainer,
     private val headsUpManager: HeadsUpManager,
     private val notification: ExpandableNotificationRow,
@@ -143,7 +143,7 @@ class NotificationLaunchAnimatorController(
         if (ActivityLaunchAnimator.DEBUG_LAUNCH_ANIMATION) {
             Log.d(TAG, "onIntentStarted(willAnimate=$willAnimate)")
         }
-        notificationExpansionRepository.setIsExpandAnimationRunning(willAnimate)
+        notificationLaunchAnimationInteractor.setIsLaunchAnimationRunning(willAnimate)
         notificationEntry.isExpandAnimationRunning = willAnimate
 
         if (!willAnimate) {
@@ -180,7 +180,7 @@ class NotificationLaunchAnimatorController(
 
         // TODO(b/184121838): Should we call InteractionJankMonitor.cancel if the animation started
         // here?
-        notificationExpansionRepository.setIsExpandAnimationRunning(false)
+        notificationLaunchAnimationInteractor.setIsLaunchAnimationRunning(false)
         notificationEntry.isExpandAnimationRunning = false
         removeHun(animate = true)
         onFinishAnimationCallback?.run()
@@ -200,7 +200,7 @@ class NotificationLaunchAnimatorController(
         jankMonitor.end(InteractionJankMonitor.CUJ_NOTIFICATION_APP_START)
 
         notification.isExpandAnimationRunning = false
-        notificationExpansionRepository.setIsExpandAnimationRunning(false)
+        notificationLaunchAnimationInteractor.setIsLaunchAnimationRunning(false)
         notificationEntry.isExpandAnimationRunning = false
         notificationListContainer.setExpandingNotification(null)
         applyParams(null)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
index e763797d99669ecfe826f20fcd578b742a9a123d..7b3a93a4a094618da86a134a0ba67bc1bd203a26 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
@@ -225,7 +225,7 @@ public class NotifCollection implements Dumpable, PipelineDumpable {
 
     /** @see NotifPipeline#getEntry(String) () */
     @Nullable
-    NotificationEntry getEntry(@NonNull String key) {
+    public NotificationEntry getEntry(@NonNull String key) {
         return mNotificationSet.get(key);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt
index c2a021d0803f10df14cfd39520f60171bbedc723..07e84bb37fa04032be1ba49bbfb244fd6471921d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt
@@ -52,9 +52,10 @@ internal constructor(
     fun onAfterRenderList(entries: List<ListEntry>, controller: NotifStackController) =
         traceSection("StackCoordinator.onAfterRenderList") {
             controller.setNotifStats(calculateNotifStats(entries))
-            notificationIconAreaController.updateNotificationIcons(entries)
             if (featureFlags.isEnabled(Flags.NOTIFICATION_ICON_CONTAINER_REFACTOR)) {
                 renderListInteractor.setRenderedList(entries)
+            } else {
+                notificationIconAreaController.updateNotificationIcons(entries)
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index 8561869af352f29e015b459f159bd4c7126f14c5..fa366c65b4a3b1942aa7458ce2c4ad3ffbe68fec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -54,7 +54,7 @@ import com.android.systemui.statusbar.notification.collection.render.NotifGutsVi
 import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource;
 import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
 import com.android.systemui.statusbar.notification.data.NotificationDataLayerModule;
-import com.android.systemui.statusbar.notification.data.repository.NotificationExpansionRepository;
+import com.android.systemui.statusbar.notification.domain.interactor.NotificationLaunchAnimationInteractor;
 import com.android.systemui.statusbar.notification.icon.ConversationIconManager;
 import com.android.systemui.statusbar.notification.icon.IconManager;
 import com.android.systemui.statusbar.notification.init.NotificationsController;
@@ -204,12 +204,12 @@ public interface NotificationsModule {
     @Provides
     @SysUISingleton
     static NotificationLaunchAnimatorControllerProvider provideNotifLaunchAnimControllerProvider(
-            NotificationExpansionRepository notificationExpansionRepository,
+            NotificationLaunchAnimationInteractor notificationLaunchAnimationInteractor,
             NotificationListContainer notificationListContainer,
             HeadsUpManager headsUpManager,
             InteractionJankMonitor jankMonitor) {
         return new NotificationLaunchAnimatorControllerProvider(
-                notificationExpansionRepository,
+                notificationLaunchAnimationInteractor,
                 notificationListContainer,
                 headsUpManager,
                 jankMonitor);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/HeadsUpNotificationIconViewStateRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/HeadsUpNotificationIconViewStateRepository.kt
new file mode 100644
index 0000000000000000000000000000000000000000..afed6bef58fc8868876bdc0cff0be8afb36eb7c1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/HeadsUpNotificationIconViewStateRepository.kt
@@ -0,0 +1,30 @@
+/*
+ * 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.data.repository
+
+import android.graphics.Rect
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+import kotlinx.coroutines.flow.MutableStateFlow
+
+/** View-states pertaining to heads-up notification icons. */
+@SysUISingleton
+class HeadsUpNotificationIconViewStateRepository @Inject constructor() {
+    /** Notification key for a notification icon to show isolated, or `null` if none. */
+    val isolatedNotification = MutableStateFlow<String?>(null)
+    /** Area to display the isolated notification, or `null` if none. */
+    val isolatedIconLocation = MutableStateFlow<Rect?>(null)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/NotificationLaunchAnimationRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/NotificationLaunchAnimationRepository.kt
new file mode 100644
index 0000000000000000000000000000000000000000..9b562991f9a333268032283b41184bc3b8658dc0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/NotificationLaunchAnimationRepository.kt
@@ -0,0 +1,27 @@
+/*
+ * 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.data.repository
+
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+import kotlinx.coroutines.flow.MutableStateFlow
+
+/** A repository tracking the status of notification launch animations. */
+@SysUISingleton
+class NotificationLaunchAnimationRepository @Inject constructor() {
+    val isLaunchAnimationRunning = MutableStateFlow(false)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationIconInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationIconInteractor.kt
new file mode 100644
index 0000000000000000000000000000000000000000..17b6e9f572c9e0b193eb132bca35894c3f2c439a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationIconInteractor.kt
@@ -0,0 +1,44 @@
+/*
+ * 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.domain.interactor
+
+import android.graphics.Rect
+import com.android.systemui.statusbar.notification.data.repository.HeadsUpNotificationIconViewStateRepository
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+
+/** Domain logic pertaining to heads up notification icons. */
+class HeadsUpNotificationIconInteractor
+@Inject
+constructor(
+    private val repository: HeadsUpNotificationIconViewStateRepository,
+) {
+    /** Notification key for a notification icon to show isolated, or `null` if none. */
+    val isolatedIconLocation: Flow<Rect?> = repository.isolatedIconLocation
+
+    /** Area to display the isolated notification, or `null` if none. */
+    val isolatedNotification: Flow<String?> = repository.isolatedNotification
+
+    /** Updates the location where isolated notification icons are shown. */
+    fun setIsolatedIconLocation(rect: Rect?) {
+        repository.isolatedIconLocation.value = rect
+    }
+
+    /** Updates which notification will have its icon displayed isolated. */
+    fun setIsolatedIconNotificationKey(key: String?) {
+        repository.isolatedNotification.value = key
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/NotificationExpansionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationLaunchAnimationInteractor.kt
similarity index 59%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/NotificationExpansionRepository.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationLaunchAnimationInteractor.kt
index 6f0a97adb3116e40d9b9b9a69065e781a4a2a611..22ce4f11b6615589d9257077fe408a9433f9e733 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/NotificationExpansionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationLaunchAnimationInteractor.kt
@@ -14,22 +14,20 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.notification.data.repository
+package com.android.systemui.statusbar.notification.domain.interactor
 
 import android.util.Log
 import com.android.systemui.animation.ActivityLaunchAnimator
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.notification.data.repository.NotificationLaunchAnimationRepository
 import javax.inject.Inject
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.asStateFlow
-
-private const val TAG = "NotificationExpansionRepository"
+import kotlinx.coroutines.flow.StateFlow
 
 /** A repository tracking the status of notification expansion animations. */
 @SysUISingleton
-class NotificationExpansionRepository @Inject constructor() {
-    private val _isExpandAnimationRunning = MutableStateFlow(false)
+class NotificationLaunchAnimationInteractor
+@Inject
+constructor(private val repository: NotificationLaunchAnimationRepository) {
 
     /**
      * Emits true if an animation that expands a notification object into an opening window is
@@ -37,13 +35,18 @@ class NotificationExpansionRepository @Inject constructor() {
      *
      * See [com.android.systemui.statusbar.notification.NotificationLaunchAnimatorController].
      */
-    val isExpandAnimationRunning: Flow<Boolean> = _isExpandAnimationRunning.asStateFlow()
+    val isLaunchAnimationRunning: StateFlow<Boolean>
+        get() = repository.isLaunchAnimationRunning
 
-    /** Sets whether the notification expansion animation is currently running. */
-    fun setIsExpandAnimationRunning(running: Boolean) {
+    /** Sets whether the notification expansion launch animation is currently running. */
+    fun setIsLaunchAnimationRunning(running: Boolean) {
         if (ActivityLaunchAnimator.DEBUG_LAUNCH_ANIMATION) {
-            Log.d(TAG, "setIsExpandAnimationRunning(running=$running)")
+            Log.d(TAG, "setIsLaunchAnimationRunning(running=$running)")
         }
-        _isExpandAnimationRunning.value = running
+        repository.isLaunchAnimationRunning.value = running
+    }
+
+    companion object {
+        private const val TAG = "NotificationLaunchAnimationInteractor"
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt
index c5396ddbe565a6c7a334aeac628463ff5f87eed7..604ecbc047ff50cb0609739f1c0b13d2d3e864fb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt
@@ -15,12 +15,16 @@
  */
 package com.android.systemui.statusbar.notification.domain.interactor
 
+import android.graphics.drawable.Icon
 import com.android.systemui.statusbar.notification.collection.ListEntry
+import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider
 import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationListRepository
 import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel
 import javax.inject.Inject
 import kotlinx.coroutines.flow.update
 
+private typealias ModelStore = Map<String, ActiveNotificationModel>
+
 /**
  * Logic for passing information from the
  * [com.android.systemui.statusbar.notification.collection.NotifPipeline] to the presentation
@@ -30,6 +34,7 @@ class RenderNotificationListInteractor
 @Inject
 constructor(
     private val repository: ActiveNotificationListRepository,
+    private val sectionStyleProvider: SectionStyleProvider,
 ) {
     /**
      * Sets the current list of rendered notification entries as displayed in the notification
@@ -38,21 +43,100 @@ constructor(
      * @see com.android.systemui.statusbar.notification.data.repository.ActiveNotificationListRepository.activeNotifications
      */
     fun setRenderedList(entries: List<ListEntry>) {
-        repository.activeNotifications.update { modelsByKey ->
+        repository.activeNotifications.update { existingModels ->
             entries.associateBy(
                 keySelector = { it.key },
-                valueTransform = { it.toModel(modelsByKey[it.key]) }
+                valueTransform = { it.toModel(existingModels) },
+            )
+        }
+    }
+
+    private fun ListEntry.toModel(
+        existingModels: ModelStore,
+    ): ActiveNotificationModel =
+        existingModels.createOrReuse(
+            key = key,
+            groupKey = representativeEntry?.sbn?.groupKey,
+            isAmbient = sectionStyleProvider.isMinimized(this),
+            isRowDismissed = representativeEntry?.isRowDismissed == true,
+            isSilent = sectionStyleProvider.isSilent(this),
+            isLastMessageFromReply = representativeEntry?.isLastMessageFromReply == true,
+            isSuppressedFromStatusBar = representativeEntry?.shouldSuppressStatusBar() == true,
+            isPulsing = representativeEntry?.showingPulsing() == true,
+            aodIcon = representativeEntry?.icons?.aodIcon?.sourceIcon,
+            shelfIcon = representativeEntry?.icons?.shelfIcon?.sourceIcon,
+            statusBarIcon = representativeEntry?.icons?.statusBarIcon?.sourceIcon,
+        )
+
+    private fun ModelStore.createOrReuse(
+        key: String,
+        groupKey: String?,
+        isAmbient: Boolean,
+        isRowDismissed: Boolean,
+        isSilent: Boolean,
+        isLastMessageFromReply: Boolean,
+        isSuppressedFromStatusBar: Boolean,
+        isPulsing: Boolean,
+        aodIcon: Icon?,
+        shelfIcon: Icon?,
+        statusBarIcon: Icon?
+    ): ActiveNotificationModel {
+        return this[key]?.takeIf {
+            it.isCurrent(
+                key = key,
+                groupKey = groupKey,
+                isAmbient = isAmbient,
+                isRowDismissed = isRowDismissed,
+                isSilent = isSilent,
+                isLastMessageFromReply = isLastMessageFromReply,
+                isSuppressedFromStatusBar = isSuppressedFromStatusBar,
+                isPulsing = isPulsing,
+                aodIcon = aodIcon,
+                shelfIcon = shelfIcon,
+                statusBarIcon = statusBarIcon
             )
         }
+            ?: ActiveNotificationModel(
+                key = key,
+                groupKey = groupKey,
+                isAmbient = isAmbient,
+                isRowDismissed = isRowDismissed,
+                isSilent = isSilent,
+                isLastMessageFromReply = isLastMessageFromReply,
+                isSuppressedFromStatusBar = isSuppressedFromStatusBar,
+                isPulsing = isPulsing,
+                aodIcon = aodIcon,
+                shelfIcon = shelfIcon,
+                statusBarIcon = statusBarIcon,
+            )
     }
 
-    private fun ListEntry.toModel(existing: ActiveNotificationModel?): ActiveNotificationModel {
-        val isCurrent =
-            when {
-                existing == null -> false
-                key == existing.key -> true
-                else -> false
-            }
-        return if (isCurrent) existing!! else ActiveNotificationModel(key = key)
+    private fun ActiveNotificationModel.isCurrent(
+        key: String,
+        groupKey: String?,
+        isAmbient: Boolean,
+        isRowDismissed: Boolean,
+        isSilent: Boolean,
+        isLastMessageFromReply: Boolean,
+        isSuppressedFromStatusBar: Boolean,
+        isPulsing: Boolean,
+        aodIcon: Icon?,
+        shelfIcon: Icon?,
+        statusBarIcon: Icon?
+    ): Boolean {
+        return when {
+            key != this.key -> false
+            groupKey != this.groupKey -> false
+            isAmbient != this.isAmbient -> false
+            isRowDismissed != this.isRowDismissed -> false
+            isSilent != this.isSilent -> false
+            isLastMessageFromReply != this.isLastMessageFromReply -> false
+            isSuppressedFromStatusBar != this.isSuppressedFromStatusBar -> false
+            isPulsing != this.isPulsing -> false
+            aodIcon != this.aodIcon -> false
+            shelfIcon != this.shelfIcon -> false
+            statusBarIcon != this.statusBarIcon -> false
+            else -> true
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractor.kt
index f3e122ce690b5ccdbcf928d3a02d63976698a192..1f7ab962c3f2d487e30ff362eeccb968ad9a78cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractor.kt
@@ -32,6 +32,7 @@ constructor(
     val hasFilteredOutSeenNotifications: StateFlow<Boolean> =
         notificationListRepository.hasFilteredOutSeenNotifications
 
+    /** Set whether already-seen notifications are currently filtered out of the shade. */
     fun setHasFilteredOutSeenNotifications(value: Boolean) {
         notificationListRepository.hasFilteredOutSeenNotifications.value = value
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
index e74b3fcdf050177e0036ac4da925d7c22634170b..ba916542fa67d58e5350cb03224abcb1b7ceaa0a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
@@ -19,6 +19,9 @@ package com.android.systemui.statusbar.notification.footer.ui.view;
 import static android.graphics.PorterDuff.Mode.SRC_ATOP;
 
 import android.annotation.ColorInt;
+import android.annotation.DrawableRes;
+import android.annotation.StringRes;
+import android.annotation.SuppressLint;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.Configuration;
@@ -35,6 +38,7 @@ import androidx.annotation.NonNull;
 
 import com.android.settingslib.Utils;
 import com.android.systemui.res.R;
+import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor;
 import com.android.systemui.statusbar.notification.row.FooterViewButton;
 import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;
 import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
@@ -44,6 +48,8 @@ import com.android.systemui.util.DumpUtilsKt;
 import java.io.PrintWriter;
 
 public class FooterView extends StackScrollerDecorView {
+    private static final String TAG = "FooterView";
+
     private FooterViewButton mClearAllButton;
     private FooterViewButton mManageButton;
     private boolean mShowHistory;
@@ -57,6 +63,9 @@ public class FooterView extends StackScrollerDecorView {
     private String mSeenNotifsFilteredText;
     private Drawable mSeenNotifsFilteredIcon;
 
+    private @StringRes int mMessageStringId;
+    private @DrawableRes int mMessageIconId;
+
     public FooterView(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
@@ -84,6 +93,50 @@ public class FooterView extends StackScrollerDecorView {
         });
     }
 
+    /** Set the string for a message to be shown instead of the buttons. */
+    public void setMessageString(@StringRes int messageId) {
+        if (FooterViewRefactor.isUnexpectedlyInLegacyMode()) return;
+        if (mMessageStringId == messageId) {
+            return; // nothing changed
+        }
+        mMessageStringId = messageId;
+        updateMessageString();
+    }
+
+    private void updateMessageString() {
+        if (mMessageStringId == 0) {
+            return; // not initialized yet
+        }
+        String messageString = getContext().getString(mMessageStringId);
+        mSeenNotifsFooterTextView.setText(messageString);
+    }
+
+
+    /** Set the icon to be shown before the message (see {@link #setMessageString(int)}). */
+    public void setMessageIcon(@DrawableRes int iconId) {
+        if (FooterViewRefactor.isUnexpectedlyInLegacyMode()) return;
+        if (mMessageIconId == iconId) {
+            return; // nothing changed
+        }
+        mMessageIconId = iconId;
+        updateMessageIcon();
+    }
+
+    private void updateMessageIcon() {
+        if (mMessageIconId == 0) {
+            return; // not initialized yet
+        }
+        int unlockIconSize = getResources()
+                .getDimensionPixelSize(R.dimen.notifications_unseen_footer_icon_size);
+        @SuppressLint("UseCompatLoadingForDrawables")
+        Drawable messageIcon = getContext().getDrawable(mMessageIconId);
+        if (messageIcon != null) {
+            messageIcon.setBounds(0, 0, unlockIconSize, unlockIconSize);
+            mSeenNotifsFooterTextView
+                    .setCompoundDrawablesRelative(messageIcon, null, null, null);
+        }
+    }
+
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
@@ -148,9 +201,11 @@ public class FooterView extends StackScrollerDecorView {
             mManageButton.setText(mManageNotificationText);
             mManageButton.setContentDescription(mManageNotificationText);
         }
-        mSeenNotifsFooterTextView.setText(mSeenNotifsFilteredText);
-        mSeenNotifsFooterTextView
-                .setCompoundDrawablesRelative(mSeenNotifsFilteredIcon, null, null, null);
+        if (!FooterViewRefactor.isEnabled()) {
+            mSeenNotifsFooterTextView.setText(mSeenNotifsFilteredText);
+            mSeenNotifsFooterTextView
+                    .setCompoundDrawablesRelative(mSeenNotifsFilteredIcon, null, null, null);
+        }
     }
 
     /** Whether the start button shows "History" (true) or "Manage" (false). */
@@ -167,6 +222,11 @@ public class FooterView extends StackScrollerDecorView {
                 mContext.getString(R.string.accessibility_clear_all));
         updateResources();
         updateContent();
+
+        if (FooterViewRefactor.isEnabled()) {
+            updateMessageString();
+            updateMessageIcon();
+        }
     }
 
     /**
@@ -200,11 +260,13 @@ public class FooterView extends StackScrollerDecorView {
         mManageNotificationText = getContext().getString(R.string.manage_notifications_text);
         mManageNotificationHistoryText = getContext()
                 .getString(R.string.manage_notifications_history_text);
-        int unlockIconSize = getResources()
-                .getDimensionPixelSize(R.dimen.notifications_unseen_footer_icon_size);
-        mSeenNotifsFilteredText = getContext().getString(R.string.unlock_to_see_notif_text);
-        mSeenNotifsFilteredIcon = getContext().getDrawable(R.drawable.ic_friction_lock_closed);
-        mSeenNotifsFilteredIcon.setBounds(0, 0, unlockIconSize, unlockIconSize);
+        if (!FooterViewRefactor.isEnabled()) {
+            int unlockIconSize = getResources()
+                    .getDimensionPixelSize(R.dimen.notifications_unseen_footer_icon_size);
+            mSeenNotifsFilteredText = getContext().getString(R.string.unlock_to_see_notif_text);
+            mSeenNotifsFilteredIcon = getContext().getDrawable(R.drawable.ic_friction_lock_closed);
+            mSeenNotifsFilteredIcon.setBounds(0, 0, unlockIconSize, unlockIconSize);
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewbinder/FooterViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewbinder/FooterViewBinder.kt
new file mode 100644
index 0000000000000000000000000000000000000000..6d8234371b65867c0f4588e7e33ab3b72dbaa468
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewbinder/FooterViewBinder.kt
@@ -0,0 +1,43 @@
+/*
+ * 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.footer.ui.viewbinder
+
+import androidx.lifecycle.lifecycleScope
+import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.statusbar.notification.footer.ui.view.FooterView
+import com.android.systemui.statusbar.notification.footer.ui.viewmodel.FooterViewModel
+import kotlinx.coroutines.DisposableHandle
+import kotlinx.coroutines.launch
+
+/** Binds a [FooterView] to its [view model][FooterViewModel]. */
+object FooterViewBinder {
+    fun bind(
+        footer: FooterView,
+        viewModel: FooterViewModel,
+    ): DisposableHandle {
+        return footer.repeatWhenAttached {
+            // Listen for changes when the view is attached.
+            lifecycleScope.launch {
+                viewModel.message.collect { message ->
+                    footer.setFooterLabelVisible(message.visible)
+                    footer.setMessageString(message.messageId)
+                    footer.setMessageIcon(message.iconId)
+                }
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterMessageViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterMessageViewModel.kt
new file mode 100644
index 0000000000000000000000000000000000000000..bc912fb106f0e4b7cbd06d8b362d818eb61da651
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterMessageViewModel.kt
@@ -0,0 +1,27 @@
+/*
+ * 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.footer.ui.viewmodel
+
+import android.annotation.DrawableRes
+import android.annotation.StringRes
+
+/** A ViewModel for the string message that can be shown in the footer. */
+data class FooterMessageViewModel(
+    @StringRes val messageId: Int,
+    @DrawableRes val iconId: Int,
+    val visible: Boolean,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModel.kt
new file mode 100644
index 0000000000000000000000000000000000000000..ffa5ff052454fc7d8a6bc002cbdf119215fbc1ca
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModel.kt
@@ -0,0 +1,45 @@
+/*
+ * 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.footer.ui.viewmodel
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor
+import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor
+import com.android.systemui.statusbar.notification.footer.ui.view.FooterView
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+
+/** ViewModel for [FooterView]. */
+@SysUISingleton
+class FooterViewModel
+@Inject
+constructor(seenNotificationsInteractor: SeenNotificationsInteractor) {
+    init {
+        /* Check if */ FooterViewRefactor.isUnexpectedlyInLegacyMode()
+    }
+
+    val message: Flow<FooterMessageViewModel> =
+        seenNotificationsInteractor.hasFilteredOutSeenNotifications.map { hasFilteredOutNotifs ->
+            FooterMessageViewModel(
+                messageId = R.string.unlock_to_see_notif_text,
+                iconId = R.drawable.ic_friction_lock_closed,
+                visible = hasFilteredOutNotifs,
+            )
+        }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractor.kt
new file mode 100644
index 0000000000000000000000000000000000000000..00d873e074b8d2e84ead2952a307cc14cab56b9a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractor.kt
@@ -0,0 +1,127 @@
+/*
+ * 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.
+ *
+ */
+
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.statusbar.notification.icon.domain.interactor
+
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
+import com.android.systemui.statusbar.data.repository.NotificationListenerSettingsRepository
+import com.android.systemui.statusbar.notification.data.repository.NotificationsKeyguardViewStateRepository
+import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
+import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel
+import com.android.wm.shell.bubbles.Bubbles
+import java.util.Optional
+import javax.inject.Inject
+import kotlin.jvm.optionals.getOrNull
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.flatMapLatest
+
+/** Domain logic related to notification icons. */
+class NotificationIconsInteractor
+@Inject
+constructor(
+    private val activeNotificationsInteractor: ActiveNotificationsInteractor,
+    private val bubbles: Optional<Bubbles>,
+    private val keyguardViewStateRepository: NotificationsKeyguardViewStateRepository,
+) {
+    /** Returns a subset of all active notifications based on the supplied filtration parameters. */
+    fun filteredNotifSet(
+        showAmbient: Boolean = true,
+        showLowPriority: Boolean = true,
+        showDismissed: Boolean = true,
+        showRepliedMessages: Boolean = true,
+        showPulsing: Boolean = true,
+    ): Flow<Set<ActiveNotificationModel>> {
+        return combine(
+            activeNotificationsInteractor.notifications,
+            keyguardViewStateRepository.areNotificationsFullyHidden,
+        ) { notifications, notifsFullyHidden ->
+            notifications
+                .asSequence()
+                .filter { model: ActiveNotificationModel ->
+                    shouldShowNotificationIcon(
+                        model = model,
+                        showAmbient = showAmbient,
+                        showLowPriority = showLowPriority,
+                        showDismissed = showDismissed,
+                        showRepliedMessages = showRepliedMessages,
+                        showPulsing = showPulsing,
+                        notifsFullyHidden = notifsFullyHidden,
+                    )
+                }
+                .toSet()
+        }
+    }
+
+    private fun shouldShowNotificationIcon(
+        model: ActiveNotificationModel,
+        showAmbient: Boolean,
+        showLowPriority: Boolean,
+        showDismissed: Boolean,
+        showRepliedMessages: Boolean,
+        showPulsing: Boolean,
+        notifsFullyHidden: Boolean,
+    ): Boolean {
+        return when {
+            !showAmbient && model.isAmbient -> false
+            !showLowPriority && model.isSilent -> false
+            !showDismissed && model.isRowDismissed -> false
+            !showRepliedMessages && model.isLastMessageFromReply -> false
+            !showAmbient && model.isSuppressedFromStatusBar -> false
+            !showPulsing && model.isPulsing && !notifsFullyHidden -> false
+            bubbles.getOrNull()?.isBubbleExpanded(model.key) == true -> false
+            else -> true
+        }
+    }
+}
+
+/** Domain logic related to notification icons shown on the always-on display. */
+class AlwaysOnDisplayNotificationIconsInteractor
+@Inject
+constructor(
+    deviceEntryInteractor: DeviceEntryInteractor,
+    iconsInteractor: NotificationIconsInteractor,
+) {
+    val aodNotifs: Flow<Set<ActiveNotificationModel>> =
+        deviceEntryInteractor.isBypassEnabled.flatMapLatest { isBypassEnabled ->
+            iconsInteractor.filteredNotifSet(
+                showAmbient = false,
+                showDismissed = false,
+                showRepliedMessages = false,
+                showPulsing = !isBypassEnabled,
+            )
+        }
+}
+
+/** Domain logic related to notification icons shown in the status bar. */
+class StatusBarNotificationIconsInteractor
+@Inject
+constructor(
+    iconsInteractor: NotificationIconsInteractor,
+    settingsRepository: NotificationListenerSettingsRepository,
+) {
+    val statusBarNotifs: Flow<Set<ActiveNotificationModel>> =
+        settingsRepository.showSilentStatusIcons.flatMapLatest { showSilentIcons ->
+            iconsInteractor.filteredNotifSet(
+                showAmbient = false,
+                showLowPriority = showSilentIcons,
+                showDismissed = false,
+                showRepliedMessages = false,
+            )
+        }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImpl.kt
index de011dbd1ab5f2985f7d4b14545ffb52342f3642..246933ad69e334f373c56091c4f5b642bcd68476 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImpl.kt
@@ -17,43 +17,23 @@ package com.android.systemui.statusbar.notification.icon.ui.viewbinder
 
 import android.content.Context
 import android.graphics.Rect
-import android.os.Bundle
-import android.os.Trace
-import android.view.LayoutInflater
 import android.view.View
-import android.widget.FrameLayout
-import androidx.annotation.VisibleForTesting
-import androidx.collection.ArrayMap
-import com.android.internal.statusbar.StatusBarIcon
 import com.android.systemui.common.ui.ConfigurationState
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.demomode.DemoMode
-import com.android.systemui.demomode.DemoModeController
 import com.android.systemui.flags.FeatureFlagsClassic
 import com.android.systemui.flags.Flags
 import com.android.systemui.flags.RefactorFlag
-import com.android.systemui.res.R
-import com.android.systemui.statusbar.NotificationListener
-import com.android.systemui.statusbar.NotificationMediaManager
 import com.android.systemui.statusbar.NotificationShelfController
 import com.android.systemui.statusbar.StatusBarIconView
-import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
 import com.android.systemui.statusbar.notification.collection.ListEntry
-import com.android.systemui.statusbar.notification.collection.NotificationEntry
-import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider
 import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerAlwaysOnDisplayViewModel
 import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerShelfViewModel
-import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerStatusBarViewModel
 import com.android.systemui.statusbar.notification.shelf.ui.viewbinder.NotificationShelfViewBinderWrapperControllerImpl
 import com.android.systemui.statusbar.phone.DozeParameters
-import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.statusbar.phone.NotificationIconAreaController
 import com.android.systemui.statusbar.phone.NotificationIconContainer
 import com.android.systemui.statusbar.phone.ScreenOffAnimationController
-import com.android.systemui.statusbar.window.StatusBarWindowController
-import com.android.wm.shell.bubbles.Bubbles
-import java.util.Optional
-import java.util.function.Function
+import com.android.systemui.statusbar.policy.ConfigurationController
 import javax.inject.Inject
 import kotlinx.coroutines.DisposableHandle
 
@@ -68,57 +48,22 @@ import kotlinx.coroutines.DisposableHandle
 class NotificationIconAreaControllerViewBinderWrapperImpl
 @Inject
 constructor(
-    private val context: Context,
     private val configuration: ConfigurationState,
-    private val wakeUpCoordinator: NotificationWakeUpCoordinator,
-    private val bypassController: KeyguardBypassController,
-    private val mediaManager: NotificationMediaManager,
-    notificationListener: NotificationListener,
+    private val configurationController: ConfigurationController,
     private val dozeParameters: DozeParameters,
-    private val sectionStyleProvider: SectionStyleProvider,
-    private val bubblesOptional: Optional<Bubbles>,
-    demoModeController: DemoModeController,
     private val featureFlags: FeatureFlagsClassic,
-    private val statusBarWindowController: StatusBarWindowController,
     private val screenOffAnimationController: ScreenOffAnimationController,
+    private val shelfIconViewStore: ShelfNotificationIconViewStore,
     private val shelfIconsViewModel: NotificationIconContainerShelfViewModel,
-    private val statusBarIconsViewModel: NotificationIconContainerStatusBarViewModel,
+    private val aodIconViewStore: AlwaysOnDisplayNotificationIconViewStore,
     private val aodIconsViewModel: NotificationIconContainerAlwaysOnDisplayViewModel,
-) : NotificationIconAreaController, NotificationWakeUpCoordinator.WakeUpListener, DemoMode {
+) : NotificationIconAreaController {
 
-    private val updateStatusBarIcons = Runnable { updateStatusBarIcons() }
     private val shelfRefactor = RefactorFlag(featureFlags, Flags.NOTIFICATION_SHELF_REFACTOR)
 
-    private var iconSize = 0
-    private var iconHPadding = 0
-    private var notificationEntries = listOf<ListEntry>()
-    private var notificationIconArea: View? = null
-    private var notificationIcons: NotificationIconContainer? = null
     private var shelfIcons: NotificationIconContainer? = null
     private var aodIcons: NotificationIconContainer? = null
     private var aodBindJob: DisposableHandle? = null
-    private var showLowPriority = true
-
-    @VisibleForTesting
-    val settingsListener: NotificationListener.NotificationSettingsListener =
-        object : NotificationListener.NotificationSettingsListener {
-            override fun onStatusBarIconsBehaviorChanged(hideSilentStatusIcons: Boolean) {
-                showLowPriority = !hideSilentStatusIcons
-                updateStatusBarIcons()
-            }
-        }
-
-    init {
-        wakeUpCoordinator.addListener(this)
-        demoModeController.addCallback(this)
-        notificationListener.addNotificationSettingsListener(settingsListener)
-        initializeNotificationAreaViews(context)
-    }
-
-    @VisibleForTesting
-    fun shouldShowLowPriorityIcons(): Boolean {
-        return showLowPriority
-    }
 
     /** Called by the Keyguard*ViewController whose view contains the aod icons. */
     override fun setupAodIcons(aodIcons: NotificationIconContainer) {
@@ -135,14 +80,12 @@ constructor(
                 aodIcons,
                 aodIconsViewModel,
                 configuration,
+                configurationController,
                 dozeParameters,
                 featureFlags,
                 screenOffAnimationController,
+                aodIconViewStore,
             )
-        if (changed) {
-            updateAodNotificationIcons()
-        }
-        updateIconLayoutParams(context)
     }
 
     override fun setupShelf(notificationShelfController: NotificationShelfController) =
@@ -154,65 +97,30 @@ constructor(
                 icons,
                 shelfIconsViewModel,
                 configuration,
+                configurationController,
                 dozeParameters,
                 featureFlags,
                 screenOffAnimationController,
+                shelfIconViewStore,
             )
             shelfIcons = icons
         }
     }
 
-    override fun onDensityOrFontScaleChanged(context: Context) {
-        updateIconLayoutParams(context)
-    }
+    override fun onDensityOrFontScaleChanged(context: Context) = unsupported
 
     /** Returns the view that represents the notification area. */
-    override fun getNotificationInnerAreaView(): View? {
-        return notificationIconArea
-    }
+    override fun getNotificationInnerAreaView(): View? = unsupported
 
     /** Updates the notifications with the given list of notifications to display. */
-    override fun updateNotificationIcons(entries: List<ListEntry>) {
-        notificationEntries = entries
-        updateNotificationIcons()
-    }
-
-    private fun updateStatusBarIcons() {
-        updateIconsForLayout(
-            { entry: NotificationEntry -> entry.icons.statusBarIcon },
-            notificationIcons,
-            showAmbient = false /* showAmbient */,
-            showLowPriority = showLowPriority,
-            hideDismissed = true /* hideDismissed */,
-            hideRepliedMessages = true /* hideRepliedMessages */,
-            hideCurrentMedia = false /* hideCurrentMedia */,
-            hidePulsing = false /* hidePulsing */
-        )
-    }
+    override fun updateNotificationIcons(entries: List<ListEntry>) = unsupported
 
-    override fun updateAodNotificationIcons() {
-        if (aodIcons == null) {
-            return
-        }
-        updateIconsForLayout(
-            { entry: NotificationEntry -> entry.icons.aodIcon },
-            aodIcons,
-            showAmbient = false /* showAmbient */,
-            showLowPriority = true /* showLowPriority */,
-            hideDismissed = true /* hideDismissed */,
-            hideRepliedMessages = true /* hideRepliedMessages */,
-            hideCurrentMedia = true /* hideCurrentMedia */,
-            hidePulsing = bypassController.bypassEnabled /* hidePulsing */
-        )
-    }
+    override fun updateAodNotificationIcons() = unsupported
 
-    override fun showIconIsolated(icon: StatusBarIconView?, animated: Boolean) {
-        notificationIcons!!.showIconIsolated(icon, animated)
-    }
+    override fun showIconIsolated(icon: StatusBarIconView?, animated: Boolean) = unsupported
 
-    override fun setIsolatedIconLocation(iconDrawingRect: Rect, requireStateUpdate: Boolean) {
-        notificationIcons!!.setIsolatedIconLocation(iconDrawingRect, requireStateUpdate)
-    }
+    override fun setIsolatedIconLocation(iconDrawingRect: Rect, requireStateUpdate: Boolean) =
+        unsupported
 
     override fun setAnimationsEnabled(enabled: Boolean) = unsupported
 
@@ -222,271 +130,6 @@ constructor(
         return if (aodIcons == null) 0 else aodIcons!!.height
     }
 
-    override fun onFullyHiddenChanged(isFullyHidden: Boolean) {
-        updateAodNotificationIcons()
-    }
-
-    override fun demoCommands(): List<String> {
-        val commands = ArrayList<String>()
-        commands.add(DemoMode.COMMAND_NOTIFICATIONS)
-        return commands
-    }
-
-    override fun dispatchDemoCommand(command: String, args: Bundle) {
-        if (notificationIconArea != null) {
-            val visible = args.getString("visible")
-            val vis = if ("false" == visible) View.INVISIBLE else View.VISIBLE
-            notificationIconArea?.visibility = vis
-        }
-    }
-
-    override fun onDemoModeFinished() {
-        if (notificationIconArea != null) {
-            notificationIconArea?.visibility = View.VISIBLE
-        }
-    }
-
-    private fun inflateIconArea(inflater: LayoutInflater): View {
-        return inflater.inflate(R.layout.notification_icon_area, null)
-    }
-
-    /** Initializes the views that will represent the notification area. */
-    private fun initializeNotificationAreaViews(context: Context) {
-        reloadDimens(context)
-        val layoutInflater = LayoutInflater.from(context)
-        notificationIconArea = inflateIconArea(layoutInflater)
-        notificationIcons = notificationIconArea?.findViewById(R.id.notificationIcons)
-        NotificationIconContainerViewBinder.bind(
-            notificationIcons!!,
-            statusBarIconsViewModel,
-            configuration,
-            dozeParameters,
-            featureFlags,
-            screenOffAnimationController,
-        )
-    }
-
-    private fun updateIconLayoutParams(context: Context) {
-        reloadDimens(context)
-        val params = generateIconLayoutParams()
-        for (i in 0 until notificationIcons!!.childCount) {
-            val child = notificationIcons!!.getChildAt(i)
-            child.layoutParams = params
-        }
-        if (shelfIcons != null) {
-            for (i in 0 until shelfIcons!!.childCount) {
-                val child = shelfIcons!!.getChildAt(i)
-                child.layoutParams = params
-            }
-        }
-        if (aodIcons != null) {
-            for (i in 0 until aodIcons!!.childCount) {
-                val child = aodIcons!!.getChildAt(i)
-                child.layoutParams = params
-            }
-        }
-    }
-
-    private fun generateIconLayoutParams(): FrameLayout.LayoutParams {
-        return FrameLayout.LayoutParams(
-            iconSize + 2 * iconHPadding,
-            statusBarWindowController.statusBarHeight
-        )
-    }
-
-    private fun reloadDimens(context: Context) {
-        val res = context.resources
-        iconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size_sp)
-        iconHPadding = res.getDimensionPixelSize(R.dimen.status_bar_icon_horizontal_margin)
-    }
-
-    private fun shouldShowNotificationIcon(
-        entry: NotificationEntry,
-        showAmbient: Boolean,
-        showLowPriority: Boolean,
-        hideDismissed: Boolean,
-        hideRepliedMessages: Boolean,
-        hideCurrentMedia: Boolean,
-        hidePulsing: Boolean
-    ): Boolean {
-        if (!showAmbient && sectionStyleProvider.isMinimized(entry)) {
-            return false
-        }
-        if (hideCurrentMedia && entry.key == mediaManager.mediaNotificationKey) {
-            return false
-        }
-        if (!showLowPriority && sectionStyleProvider.isSilent(entry)) {
-            return false
-        }
-        if (entry.isRowDismissed && hideDismissed) {
-            return false
-        }
-        if (hideRepliedMessages && entry.isLastMessageFromReply) {
-            return false
-        }
-        // showAmbient == show in shade but not shelf
-        if (!showAmbient && entry.shouldSuppressStatusBar()) {
-            return false
-        }
-        if (
-            hidePulsing &&
-                entry.showingPulsing() &&
-                (!wakeUpCoordinator.notificationsFullyHidden || !entry.isPulseSuppressed)
-        ) {
-            return false
-        }
-        return if (bubblesOptional.isPresent && bubblesOptional.get().isBubbleExpanded(entry.key)) {
-            false
-        } else true
-    }
-
-    private fun updateNotificationIcons() {
-        Trace.beginSection("NotificationIconAreaController.updateNotificationIcons")
-        updateStatusBarIcons()
-        updateShelfIcons()
-        updateAodNotificationIcons()
-        Trace.endSection()
-    }
-
-    private fun updateShelfIcons() {
-        if (shelfIcons == null) {
-            return
-        }
-        updateIconsForLayout(
-            { entry: NotificationEntry -> entry.icons.shelfIcon },
-            shelfIcons,
-            showAmbient = true,
-            showLowPriority = true,
-            hideDismissed = false,
-            hideRepliedMessages = false,
-            hideCurrentMedia = false,
-            hidePulsing = false
-        )
-    }
-
-    /**
-     * Updates the notification icons for a host layout. This will ensure that the notification host
-     * layout will have the same icons like the ones in here.
-     *
-     * @param function A function to look up an icon view based on an entry
-     * @param hostLayout which layout should be updated
-     * @param showAmbient should ambient notification icons be shown
-     * @param showLowPriority should icons from silent notifications be shown
-     * @param hideDismissed should dismissed icons be hidden
-     * @param hideRepliedMessages should messages that have been replied to be hidden
-     * @param hidePulsing should pulsing notifications be hidden
-     */
-    private fun updateIconsForLayout(
-        function: Function<NotificationEntry, StatusBarIconView?>,
-        hostLayout: NotificationIconContainer?,
-        showAmbient: Boolean,
-        showLowPriority: Boolean,
-        hideDismissed: Boolean,
-        hideRepliedMessages: Boolean,
-        hideCurrentMedia: Boolean,
-        hidePulsing: Boolean,
-    ) {
-        val toShow = ArrayList<StatusBarIconView>(notificationEntries.size)
-        // Filter out ambient notifications and notification children.
-        for (i in notificationEntries.indices) {
-            val entry = notificationEntries[i].representativeEntry
-            if (entry != null && entry.row != null) {
-                if (
-                    shouldShowNotificationIcon(
-                        entry,
-                        showAmbient,
-                        showLowPriority,
-                        hideDismissed,
-                        hideRepliedMessages,
-                        hideCurrentMedia,
-                        hidePulsing
-                    )
-                ) {
-                    val iconView = function.apply(entry)
-                    if (iconView != null) {
-                        toShow.add(iconView)
-                    }
-                }
-            }
-        }
-
-        // In case we are changing the suppression of a group, the replacement shouldn't flicker
-        // and it should just be replaced instead. We therefore look for notifications that were
-        // just replaced by the child or vice-versa to suppress this.
-        val replacingIcons = ArrayMap<String, ArrayList<StatusBarIcon>>()
-        val toRemove = ArrayList<View>()
-        for (i in 0 until hostLayout!!.childCount) {
-            val child = hostLayout.getChildAt(i) as? StatusBarIconView ?: continue
-            if (!toShow.contains(child)) {
-                var iconWasReplaced = false
-                val removedGroupKey = child.notification.groupKey
-                for (j in toShow.indices) {
-                    val candidate = toShow[j]
-                    if (
-                        candidate.sourceIcon.sameAs(child.sourceIcon) &&
-                            candidate.notification.groupKey == removedGroupKey
-                    ) {
-                        if (!iconWasReplaced) {
-                            iconWasReplaced = true
-                        } else {
-                            iconWasReplaced = false
-                            break
-                        }
-                    }
-                }
-                if (iconWasReplaced) {
-                    var statusBarIcons = replacingIcons[removedGroupKey]
-                    if (statusBarIcons == null) {
-                        statusBarIcons = ArrayList()
-                        replacingIcons[removedGroupKey] = statusBarIcons
-                    }
-                    statusBarIcons.add(child.statusBarIcon)
-                }
-                toRemove.add(child)
-            }
-        }
-        // removing all duplicates
-        val duplicates = ArrayList<String?>()
-        for (key in replacingIcons.keys) {
-            val statusBarIcons = replacingIcons[key]!!
-            if (statusBarIcons.size != 1) {
-                duplicates.add(key)
-            }
-        }
-        replacingIcons.removeAll(duplicates)
-        hostLayout.setReplacingIcons(replacingIcons)
-        val toRemoveCount = toRemove.size
-        for (i in 0 until toRemoveCount) {
-            hostLayout.removeView(toRemove[i])
-        }
-        val params = generateIconLayoutParams()
-        for (i in toShow.indices) {
-            val v = toShow[i]
-            // The view might still be transiently added if it was just removed and added again
-            hostLayout.removeTransientView(v)
-            if (v.parent == null) {
-                if (hideDismissed) {
-                    v.setOnDismissListener(updateStatusBarIcons)
-                }
-                hostLayout.addView(v, i, params)
-            }
-        }
-        hostLayout.setChangingViewPositions(true)
-        // Re-sort notification icons
-        val childCount = hostLayout.childCount
-        for (i in 0 until childCount) {
-            val actual = hostLayout.getChildAt(i)
-            val expected = toShow[i]
-            if (actual === expected) {
-                continue
-            }
-            hostLayout.removeView(expected)
-            hostLayout.addView(expected, i)
-        }
-        hostLayout.setChangingViewPositions(false)
-        hostLayout.setReplacingIcons(null)
-    }
-
     companion object {
         val unsupported: Nothing
             get() =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt
index 079004c2a60a3f95234064e45c667fc06d8a2a82..75926194af581c9be86d831535d233e7dca10380 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt
@@ -15,11 +15,17 @@
  */
 package com.android.systemui.statusbar.notification.icon.ui.viewbinder
 
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
 import android.graphics.Rect
 import android.view.View
+import android.view.ViewPropertyAnimator
+import android.widget.FrameLayout
+import androidx.collection.ArrayMap
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
 import com.android.app.animation.Interpolators
+import com.android.internal.policy.SystemBarUtils
 import com.android.internal.util.ContrastColorUtil
 import com.android.systemui.common.ui.ConfigurationState
 import com.android.systemui.flags.FeatureFlagsClassic
@@ -29,78 +35,235 @@ import com.android.systemui.res.R
 import com.android.systemui.statusbar.CrossFadeHelper
 import com.android.systemui.statusbar.StatusBarIconView
 import com.android.systemui.statusbar.notification.NotificationUtils
+import com.android.systemui.statusbar.notification.collection.NotifCollection
+import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerViewBinder.IconViewStore
 import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerViewModel
 import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerViewModel.IconColors
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerViewModel.IconsViewData
 import com.android.systemui.statusbar.phone.DozeParameters
 import com.android.systemui.statusbar.phone.NotificationIconContainer
 import com.android.systemui.statusbar.phone.ScreenOffAnimationController
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.onConfigChanged
 import com.android.systemui.util.children
+import com.android.systemui.util.kotlin.mapValuesNotNullTo
+import com.android.systemui.util.kotlin.sample
+import com.android.systemui.util.kotlin.stateFlow
+import com.android.systemui.util.ui.isAnimating
+import com.android.systemui.util.ui.stopAnimating
+import com.android.systemui.util.ui.value
+import javax.inject.Inject
 import kotlinx.coroutines.DisposableHandle
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.mapNotNull
 import kotlinx.coroutines.flow.stateIn
 import kotlinx.coroutines.launch
 
 /** Binds a [NotificationIconContainer] to its [view model][NotificationIconContainerViewModel]. */
 object NotificationIconContainerViewBinder {
+    @JvmStatic
     fun bind(
         view: NotificationIconContainer,
         viewModel: NotificationIconContainerViewModel,
         configuration: ConfigurationState,
+        configurationController: ConfigurationController,
         dozeParameters: DozeParameters,
         featureFlags: FeatureFlagsClassic,
         screenOffAnimationController: ScreenOffAnimationController,
+        viewStore: IconViewStore,
     ): DisposableHandle {
         val contrastColorUtil = ContrastColorUtil.getInstance(view.context)
         return view.repeatWhenAttached {
             repeatOnLifecycle(Lifecycle.State.CREATED) {
-                launch { viewModel.animationsEnabled.collect(view::setAnimationsEnabled) }
-                launch {
-                    viewModel.isDozing.collect { (isDozing, animate) ->
-                        val animateIfNotBlanking = animate && !dozeParameters.displayNeedsBlanking
-                        view.setDozing(isDozing, animateIfNotBlanking, /* delay= */ 0) {
-                            viewModel.completeDozeAnimation()
-                        }
-                    }
-                }
+                launch { bindAnimationsEnabled(viewModel, view) }
+                launch { bindIsDozing(viewModel, view, dozeParameters) }
                 // TODO(b/278765923): this should live where AOD is bound, not inside of the NIC
                 //  view-binder
                 launch {
-                    val iconAppearTranslation =
-                        configuration
-                            .getDimensionPixelSize(R.dimen.shelf_appear_translation)
-                            .stateIn(this)
                     bindVisibility(
                         viewModel,
                         view,
+                        configuration,
                         featureFlags,
                         screenOffAnimationController,
-                        iconAppearTranslation,
-                    ) {
-                        viewModel.completeVisibilityAnimation()
-                    }
+                    )
                 }
+                launch { bindIconColors(viewModel, view, contrastColorUtil) }
                 launch {
-                    viewModel.iconColors
-                        .mapNotNull { lookup -> lookup.iconColors(view.viewBounds) }
-                        .collect { iconLookup -> applyTint(view, iconLookup, contrastColorUtil) }
+                    bindIconViewData(
+                        viewModel,
+                        view,
+                        configuration,
+                        configurationController,
+                        viewStore,
+                    )
                 }
+                launch { bindIsolatedIcon(viewModel, view, viewStore) }
             }
         }
     }
 
-    // TODO(b/305739416): Once SBIV has its own Recommended Architecture stack, this can be moved
-    //  there and cleaned up.
-    private fun applyTint(
+    private suspend fun bindAnimationsEnabled(
+        viewModel: NotificationIconContainerViewModel,
+        view: NotificationIconContainer
+    ) {
+        viewModel.animationsEnabled.collect(view::setAnimationsEnabled)
+    }
+
+    private suspend fun bindIconColors(
+        viewModel: NotificationIconContainerViewModel,
         view: NotificationIconContainer,
-        iconColors: IconColors,
         contrastColorUtil: ContrastColorUtil,
     ) {
-        view.children.filterIsInstance<StatusBarIconView>().forEach { iv ->
-            if (iv.width != 0) {
-                updateTintForIcon(iv, iconColors, contrastColorUtil)
+        viewModel.iconColors
+            .mapNotNull { lookup -> lookup.iconColors(view.viewBounds) }
+            .collect { iconLookup -> applyTint(view, iconLookup, contrastColorUtil) }
+    }
+
+    private suspend fun bindIsDozing(
+        viewModel: NotificationIconContainerViewModel,
+        view: NotificationIconContainer,
+        dozeParameters: DozeParameters,
+    ) {
+        viewModel.isDozing.collect { isDozing ->
+            if (isDozing.isAnimating) {
+                val animate = !dozeParameters.displayNeedsBlanking
+                view.setDozing(
+                    /* dozing = */ isDozing.value,
+                    /* fade = */ animate,
+                    /* delay = */ 0,
+                    /* endRunnable = */ isDozing::stopAnimating,
+                )
+            } else {
+                view.setDozing(
+                    /* dozing = */ isDozing.value,
+                    /* fade= */ false,
+                    /* delay= */ 0,
+                )
+            }
+        }
+    }
+
+    private suspend fun bindIsolatedIcon(
+        viewModel: NotificationIconContainerViewModel,
+        view: NotificationIconContainer,
+        viewStore: IconViewStore,
+    ) {
+        coroutineScope {
+            launch {
+                viewModel.isolatedIconLocation.collect { location ->
+                    view.setIsolatedIconLocation(location, true)
+                }
+            }
+            launch {
+                viewModel.isolatedIcon.collect { iconInfo ->
+                    val iconView = iconInfo.value?.let { viewStore.iconView(it.notifKey) }
+                    if (iconInfo.isAnimating) {
+                        view.showIconIsolatedAnimated(iconView, iconInfo::stopAnimating)
+                    } else {
+                        view.showIconIsolated(iconView)
+                    }
+                }
+            }
+        }
+    }
+
+    private suspend fun bindIconViewData(
+        viewModel: NotificationIconContainerViewModel,
+        view: NotificationIconContainer,
+        configuration: ConfigurationState,
+        configurationController: ConfigurationController,
+        viewStore: IconViewStore,
+    ): Unit = coroutineScope {
+        val iconSizeFlow: Flow<Int> =
+            configuration.getDimensionPixelSize(
+                com.android.internal.R.dimen.status_bar_icon_size_sp,
+            )
+        val iconHorizontalPaddingFlow: Flow<Int> =
+            configuration.getDimensionPixelSize(R.dimen.status_bar_icon_horizontal_margin)
+        val statusBarHeightFlow: StateFlow<Int> =
+            stateFlow(changedSignals = configurationController.onConfigChanged) {
+                SystemBarUtils.getStatusBarHeight(view.context)
+            }
+        val layoutParams: Flow<FrameLayout.LayoutParams> =
+            combine(iconSizeFlow, iconHorizontalPaddingFlow, statusBarHeightFlow) {
+                iconSize,
+                iconHPadding,
+                statusBarHeight,
+                ->
+                FrameLayout.LayoutParams(iconSize + 2 * iconHPadding, statusBarHeight)
+            }
+
+        launch {
+            layoutParams.collect { params: FrameLayout.LayoutParams ->
+                for (child in view.children) {
+                    child.layoutParams = params
+                }
             }
         }
+
+        var prevIcons = IconsViewData()
+        viewModel.iconsViewData.sample(layoutParams, ::Pair).collect {
+            (iconsData: IconsViewData, layoutParams: FrameLayout.LayoutParams),
+            ->
+            val iconsDiff = IconsViewData.computeDifference(iconsData, prevIcons)
+            prevIcons = iconsData
+
+            val replacingIcons =
+                iconsDiff.groupReplacements.mapValuesNotNullTo(ArrayMap()) { (_, v) ->
+                    viewStore.iconView(v.notifKey)?.statusBarIcon
+                }
+            view.setReplacingIcons(replacingIcons)
+
+            val childrenByNotifKey: Map<String, StatusBarIconView> =
+                view.children.filterIsInstance<StatusBarIconView>().associateByTo(ArrayMap()) {
+                    it.notification.key
+                }
+
+            iconsDiff.removed
+                .mapNotNull { key -> childrenByNotifKey[key] }
+                .forEach { child -> view.removeView(child) }
+
+            val toAdd = iconsDiff.added.mapNotNull { viewStore.iconView(it.notifKey) }
+            for ((i, sbiv) in toAdd.withIndex()) {
+                // The view might still be transiently added if it was just removed
+                // and added again
+                view.removeTransientView(sbiv)
+                view.addView(sbiv, i, layoutParams)
+            }
+
+            view.setChangingViewPositions(true)
+            // Re-sort notification icons
+            val childCount = view.childCount
+            for (i in 0 until childCount) {
+                val actual = view.getChildAt(i)
+                val expected = viewStore.iconView(iconsData.visibleKeys[i].notifKey)!!
+                if (actual === expected) {
+                    continue
+                }
+                view.removeView(expected)
+                view.addView(expected, i)
+            }
+            view.setChangingViewPositions(false)
+
+            view.setReplacingIcons(null)
+        }
+    }
+
+    // TODO(b/305739416): Once StatusBarIconView has its own Recommended Architecture stack, this
+    //  can be moved there and cleaned up.
+    private fun applyTint(
+        view: NotificationIconContainer,
+        iconColors: IconColors,
+        contrastColorUtil: ContrastColorUtil,
+    ) {
+        view.children
+            .filterIsInstance<StatusBarIconView>()
+            .filter { it.width != 0 }
+            .forEach { iv -> updateTintForIcon(iv, iconColors, contrastColorUtil) }
     }
 
     private fun updateTintForIcon(
@@ -117,34 +280,41 @@ object NotificationIconContainerViewBinder {
     private suspend fun bindVisibility(
         viewModel: NotificationIconContainerViewModel,
         view: NotificationIconContainer,
+        configuration: ConfigurationState,
         featureFlags: FeatureFlagsClassic,
         screenOffAnimationController: ScreenOffAnimationController,
-        iconAppearTranslation: StateFlow<Int>,
-        onAnimationEnd: () -> Unit,
-    ) {
+    ): Unit = coroutineScope {
+        val iconAppearTranslation =
+            configuration.getDimensionPixelSize(R.dimen.shelf_appear_translation).stateIn(this)
         val statusViewMigrated = featureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)
-        viewModel.isVisible.collect { (isVisible, animate) ->
+        viewModel.isVisible.collect { isVisible ->
             view.animate().cancel()
+            val animatorListener =
+                object : AnimatorListenerAdapter() {
+                    override fun onAnimationEnd(animation: Animator) {
+                        isVisible.stopAnimating()
+                    }
+                }
             when {
-                !animate -> {
+                !isVisible.isAnimating -> {
                     view.alpha = 1f
                     if (!statusViewMigrated) {
                         view.translationY = 0f
                     }
-                    view.visibility = if (isVisible) View.VISIBLE else View.INVISIBLE
+                    view.visibility = if (isVisible.value) View.VISIBLE else View.INVISIBLE
                 }
                 featureFlags.isEnabled(Flags.NEW_AOD_TRANSITION) -> {
                     animateInIconTranslation(view, statusViewMigrated)
-                    if (isVisible) {
-                        CrossFadeHelper.fadeIn(view, onAnimationEnd)
+                    if (isVisible.value) {
+                        CrossFadeHelper.fadeIn(view, animatorListener)
                     } else {
-                        CrossFadeHelper.fadeOut(view, onAnimationEnd)
+                        CrossFadeHelper.fadeOut(view, animatorListener)
                     }
                 }
-                !isVisible -> {
+                !isVisible.value -> {
                     // Let's make sure the icon are translated to 0, since we cancelled it above
                     animateInIconTranslation(view, statusViewMigrated)
-                    CrossFadeHelper.fadeOut(view, onAnimationEnd)
+                    CrossFadeHelper.fadeOut(view, animatorListener)
                 }
                 view.visibility != View.VISIBLE -> {
                     // No fading here, let's just appear the icons instead!
@@ -155,14 +325,14 @@ object NotificationIconContainerViewBinder {
                         animate = screenOffAnimationController.shouldAnimateAodIcons(),
                         iconAppearTranslation.value,
                         statusViewMigrated,
+                        animatorListener,
                     )
-                    onAnimationEnd()
                 }
                 else -> {
                     // Let's make sure the icons are translated to 0, since we cancelled it above
                     animateInIconTranslation(view, statusViewMigrated)
                     // We were fading out, let's fade in instead
-                    CrossFadeHelper.fadeIn(view, onAnimationEnd)
+                    CrossFadeHelper.fadeIn(view, animatorListener)
                 }
             }
         }
@@ -173,18 +343,20 @@ object NotificationIconContainerViewBinder {
         animate: Boolean,
         iconAppearTranslation: Int,
         statusViewMigrated: Boolean,
+        animatorListener: Animator.AnimatorListener,
     ) {
         if (animate) {
             if (!statusViewMigrated) {
                 view.translationY = -iconAppearTranslation.toFloat()
             }
             view.alpha = 0f
-            animateInIconTranslation(view, statusViewMigrated)
             view
                 .animate()
                 .alpha(1f)
                 .setInterpolator(Interpolators.LINEAR)
                 .setDuration(AOD_ICONS_APPEAR_DURATION)
+                .apply { if (statusViewMigrated) animateInIconTranslation() }
+                .setListener(animatorListener)
                 .start()
         } else {
             view.alpha = 1.0f
@@ -196,15 +368,13 @@ object NotificationIconContainerViewBinder {
 
     private fun animateInIconTranslation(view: View, statusViewMigrated: Boolean) {
         if (!statusViewMigrated) {
-            view
-                .animate()
-                .setInterpolator(Interpolators.DECELERATE_QUINT)
-                .translationY(0f)
-                .setDuration(AOD_ICONS_APPEAR_DURATION)
-                .start()
+            view.animate().animateInIconTranslation().setDuration(AOD_ICONS_APPEAR_DURATION).start()
         }
     }
 
+    private fun ViewPropertyAnimator.animateInIconTranslation(): ViewPropertyAnimator =
+        setInterpolator(Interpolators.DECELERATE_QUINT).translationY(0f)
+
     private const val AOD_ICONS_APPEAR_DURATION: Long = 200
 
     private val View.viewBounds: Rect
@@ -218,4 +388,39 @@ object NotificationIconContainerViewBinder {
                 /* bottom = */ top + height,
             )
         }
+
+    /** External storage for [StatusBarIconView] instances. */
+    fun interface IconViewStore {
+        fun iconView(key: String): StatusBarIconView?
+    }
+}
+
+/** [IconViewStore] for the [com.android.systemui.statusbar.NotificationShelf] */
+class ShelfNotificationIconViewStore
+@Inject
+constructor(
+    private val notifCollection: NotifCollection,
+) : IconViewStore {
+    override fun iconView(key: String): StatusBarIconView? =
+        notifCollection.getEntry(key)?.icons?.shelfIcon
+}
+
+/** [IconViewStore] for the always-on display. */
+class AlwaysOnDisplayNotificationIconViewStore
+@Inject
+constructor(
+    private val notifCollection: NotifCollection,
+) : IconViewStore {
+    override fun iconView(key: String): StatusBarIconView? =
+        notifCollection.getEntry(key)?.icons?.aodIcon
+}
+
+/** [IconViewStore] for the status bar. */
+class StatusBarNotificationIconViewStore
+@Inject
+constructor(
+    private val notifCollection: NotifCollection,
+) : IconViewStore {
+    override fun iconView(key: String): StatusBarIconView? =
+        notifCollection.getEntry(key)?.icons?.statusBarIcon
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt
index e9de4bd654d3fb8c2449dcfbadb51f9bec95aa60..120d342b18d842d682aedf9cac7a7fb80a334394 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt
@@ -30,8 +30,11 @@ import com.android.systemui.keyguard.shared.model.TransitionStep
 import com.android.systemui.res.R
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.statusbar.notification.domain.interactor.NotificationsKeyguardInteractor
+import com.android.systemui.statusbar.notification.icon.domain.interactor.AlwaysOnDisplayNotificationIconsInteractor
 import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerViewModel.ColorLookup
 import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerViewModel.IconColors
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerViewModel.IconInfo
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerViewModel.IconsViewData
 import com.android.systemui.statusbar.phone.DozeParameters
 import com.android.systemui.statusbar.phone.ScreenOffAnimationController
 import com.android.systemui.util.kotlin.pairwise
@@ -39,11 +42,13 @@ import com.android.systemui.util.kotlin.sample
 import com.android.systemui.util.ui.AnimatableEvent
 import com.android.systemui.util.ui.AnimatedValue
 import com.android.systemui.util.ui.toAnimatedValueFlow
+import com.android.systemui.util.ui.zip
 import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableSharedFlow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.map
 
 /** View-model for the row of notification icons displayed on the always-on display. */
@@ -55,6 +60,7 @@ constructor(
     private val deviceEntryInteractor: DeviceEntryInteractor,
     private val dozeParameters: DozeParameters,
     private val featureFlags: FeatureFlagsClassic,
+    iconsInteractor: AlwaysOnDisplayNotificationIconsInteractor,
     keyguardInteractor: KeyguardInteractor,
     keyguardTransitionInteractor: KeyguardTransitionInteractor,
     private val notificationsKeyguardInteractor: NotificationsKeyguardInteractor,
@@ -62,9 +68,6 @@ constructor(
     shadeInteractor: ShadeInteractor,
 ) : NotificationIconContainerViewModel {
 
-    private val onDozeAnimationComplete = MutableSharedFlow<Unit>(extraBufferCapacity = 1)
-    private val onVisAnimationComplete = MutableSharedFlow<Unit>(extraBufferCapacity = 1)
-
     override val iconColors: Flow<ColorLookup> =
         configuration.getColorAttr(R.attr.wallpaperTextColor, DEFAULT_AOD_ICON_COLOR).map { tint ->
             ColorLookup { IconColorsImpl(tint) }
@@ -93,7 +96,7 @@ constructor(
                 AnimatableEvent(isDozing, animate)
             }
             .distinctUntilChanged()
-            .toAnimatedValueFlow(completionEvents = onDozeAnimationComplete)
+            .toAnimatedValueFlow()
 
     override val isVisible: Flow<AnimatedValue<Boolean>> =
         combine(
@@ -103,46 +106,54 @@ constructor(
                 isPulseExpandingAnimated(),
             ) {
                 onKeyguard: Boolean,
-                bypassEnabled: Boolean,
-                (notifsFullyHidden: Boolean, isAnimatingHide: Boolean),
-                (pulseExpanding: Boolean, isAnimatingPulse: Boolean),
+                isBypassEnabled: Boolean,
+                notifsFullyHidden: AnimatedValue<Boolean>,
+                pulseExpanding: AnimatedValue<Boolean>,
                 ->
-                val isAnimating = isAnimatingHide || isAnimatingPulse
                 when {
                     // Hide the AOD icons if we're not in the KEYGUARD state unless the screen off
                     // animation is playing, in which case we want them to be visible if we're
                     // animating in the AOD UI and will be switching to KEYGUARD shortly.
                     !onKeyguard && !screenOffAnimationController.shouldShowAodIconsWhenShade() ->
-                        AnimatedValue(false, isAnimating = false)
-                    // If we're bypassing, then we're visible
-                    bypassEnabled -> AnimatedValue(true, isAnimating)
-                    // If we are pulsing (and not bypassing), then we are hidden
-                    pulseExpanding -> AnimatedValue(false, isAnimating)
-                    // If notifs are fully gone, then we're visible
-                    notifsFullyHidden -> AnimatedValue(true, isAnimating)
-                    // Otherwise, we're hidden
-                    else -> AnimatedValue(false, isAnimating)
+                        AnimatedValue.NotAnimating(false)
+                    else ->
+                        zip(notifsFullyHidden, pulseExpanding) {
+                            areNotifsFullyHidden,
+                            isPulseExpanding,
+                            ->
+                            when {
+                                // If we're bypassing, then we're visible
+                                isBypassEnabled -> true
+                                // If we are pulsing (and not bypassing), then we are hidden
+                                isPulseExpanding -> false
+                                // If notifs are fully gone, then we're visible
+                                areNotifsFullyHidden -> true
+                                // Otherwise, we're hidden
+                                else -> false
+                            }
+                        }
                 }
             }
             .distinctUntilChanged()
 
-    override fun completeDozeAnimation() {
-        onDozeAnimationComplete.tryEmit(Unit)
-    }
+    override val iconsViewData: Flow<IconsViewData> =
+        iconsInteractor.aodNotifs.map { entries ->
+            IconsViewData(
+                visibleKeys = entries.mapNotNull { it.toIconInfo(it.aodIcon) },
+            )
+        }
 
-    override fun completeVisibilityAnimation() {
-        onVisAnimationComplete.tryEmit(Unit)
-    }
+    override val isolatedIcon: Flow<AnimatedValue<IconInfo?>> =
+        flowOf(AnimatedValue.NotAnimating(null))
+    override val isolatedIconLocation: Flow<Rect> = emptyFlow()
 
     /** Is there an expanded pulse, are we animating in response? */
     private fun isPulseExpandingAnimated(): Flow<AnimatedValue<Boolean>> {
         return notificationsKeyguardInteractor.isPulseExpanding
             .pairwise(initialValue = null)
             // If pulsing changes, start animating, unless it's the first emission
-            .map { (prev, expanding) ->
-                AnimatableEvent(expanding!!, startAnimating = prev != null)
-            }
-            .toAnimatedValueFlow(completionEvents = onVisAnimationComplete)
+            .map { (prev, expanding) -> AnimatableEvent(expanding, startAnimating = prev != null) }
+            .toAnimatedValueFlow()
     }
 
     /** Are notifications completely hidden from view, are we animating in response? */
@@ -164,11 +175,11 @@ constructor(
                         // We only want the appear animations to happen when the notifications
                         // get fully hidden, since otherwise the un-hide animation overlaps.
                         featureFlags.isEnabled(Flags.NEW_AOD_TRANSITION) -> true
-                        else -> fullyHidden!!
+                        else -> fullyHidden
                     }
-                AnimatableEvent(fullyHidden!!, animate)
+                AnimatableEvent(fullyHidden, animate)
             }
-            .toAnimatedValueFlow(completionEvents = onVisAnimationComplete)
+            .toAnimatedValueFlow()
     }
 
     private class IconColorsImpl(override val tint: Int) : IconColors {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModel.kt
index f305155e9b3d823c8755b48d68f24d56154a31c6..c6aabb7527da99dfd5bfd27fe8f4e2d8aff20191 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModel.kt
@@ -15,20 +15,37 @@
  */
 package com.android.systemui.statusbar.notification.icon.ui.viewmodel
 
+import android.graphics.Rect
+import com.android.systemui.statusbar.notification.icon.domain.interactor.NotificationIconsInteractor
 import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerViewModel.ColorLookup
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerViewModel.IconInfo
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerViewModel.IconsViewData
 import com.android.systemui.util.ui.AnimatedValue
 import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.emptyFlow
 import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
 
 /** View-model for the overflow row of notification icons displayed in the notification shade. */
-class NotificationIconContainerShelfViewModel @Inject constructor() :
-    NotificationIconContainerViewModel {
+class NotificationIconContainerShelfViewModel
+@Inject
+constructor(
+    interactor: NotificationIconsInteractor,
+) : NotificationIconContainerViewModel {
+
     override val animationsEnabled: Flow<Boolean> = flowOf(true)
     override val isDozing: Flow<AnimatedValue<Boolean>> = emptyFlow()
     override val isVisible: Flow<AnimatedValue<Boolean>> = emptyFlow()
-    override fun completeDozeAnimation() {}
-    override fun completeVisibilityAnimation() {}
     override val iconColors: Flow<ColorLookup> = emptyFlow()
+    override val isolatedIcon: Flow<AnimatedValue<IconInfo?>> =
+        flowOf(AnimatedValue.NotAnimating(null))
+    override val isolatedIconLocation: Flow<Rect> = emptyFlow()
+
+    override val iconsViewData: Flow<IconsViewData> =
+        interactor.filteredNotifSet().map { entries ->
+            IconsViewData(
+                visibleKeys = entries.mapNotNull { it.toIconInfo(it.shelfIcon) },
+            )
+        }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt
index ee01fcca82d47400cd305673ba8b668e6fa530ac..4d14024fcd99fb11fb767cd9fd53d994c5fb1dad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt
@@ -20,20 +20,32 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
 import com.android.systemui.plugins.DarkIconDispatcher
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
+import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationIconInteractor
+import com.android.systemui.statusbar.notification.icon.domain.interactor.StatusBarNotificationIconsInteractor
 import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerViewModel.ColorLookup
 import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerViewModel.IconColors
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerViewModel.IconInfo
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerViewModel.IconsViewData
 import com.android.systemui.statusbar.phone.domain.interactor.DarkIconInteractor
+import com.android.systemui.util.kotlin.pairwise
+import com.android.systemui.util.kotlin.sample
+import com.android.systemui.util.ui.AnimatableEvent
 import com.android.systemui.util.ui.AnimatedValue
+import com.android.systemui.util.ui.toAnimatedValueFlow
 import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.map
 
 /** View-model for the row of notification icons displayed in the status bar, */
 class NotificationIconContainerStatusBarViewModel
 @Inject
 constructor(
     darkIconInteractor: DarkIconInteractor,
+    iconsInteractor: StatusBarNotificationIconsInteractor,
+    headsUpIconInteractor: HeadsUpNotificationIconInteractor,
     keyguardInteractor: KeyguardInteractor,
     notificationsInteractor: ActiveNotificationsInteractor,
     shadeInteractor: ShadeInteractor,
@@ -45,6 +57,7 @@ constructor(
         ) { panelTouchesEnabled, isKeyguardShowing ->
             panelTouchesEnabled && !isKeyguardShowing
         }
+
     override val iconColors: Flow<ColorLookup> =
         combine(
             darkIconInteractor.tintAreas,
@@ -60,10 +73,40 @@ constructor(
                 }
             }
         }
+
     override val isDozing: Flow<AnimatedValue<Boolean>> = emptyFlow()
     override val isVisible: Flow<AnimatedValue<Boolean>> = emptyFlow()
-    override fun completeDozeAnimation() {}
-    override fun completeVisibilityAnimation() {}
+
+    override val iconsViewData: Flow<IconsViewData> =
+        iconsInteractor.statusBarNotifs.map { entries ->
+            IconsViewData(
+                visibleKeys = entries.mapNotNull { it.toIconInfo(it.statusBarIcon) },
+            )
+        }
+
+    override val isolatedIcon: Flow<AnimatedValue<IconInfo?>> =
+        headsUpIconInteractor.isolatedNotification
+            .pairwise(initialValue = null)
+            .sample(combine(iconsViewData, shadeInteractor.shadeExpansion, ::Pair)) {
+                (prev, isolatedNotif),
+                (iconsViewData, shadeExpansion),
+                ->
+                val iconInfo =
+                    isolatedNotif?.let {
+                        iconsViewData.visibleKeys.firstOrNull { it.notifKey == isolatedNotif }
+                    }
+                val animate =
+                    when {
+                        isolatedNotif == prev -> false
+                        isolatedNotif == null || prev == null -> shadeExpansion == 0f
+                        else -> false
+                    }
+                AnimatableEvent(iconInfo, animate)
+            }
+            .toAnimatedValueFlow()
+
+    override val isolatedIconLocation: Flow<Rect> =
+        headsUpIconInteractor.isolatedIconLocation.filterNotNull()
 
     private class IconColorsImpl(
         override val tint: Int,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerViewModel.kt
index c98811b0e28552fdb2ee37e71319824893514578..a611323201e32afd463339ddbc338427e7cba640 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerViewModel.kt
@@ -16,6 +16,11 @@
 package com.android.systemui.statusbar.notification.icon.ui.viewmodel
 
 import android.graphics.Rect
+import android.graphics.drawable.Icon
+import androidx.collection.ArrayMap
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerViewModel.IconInfo
+import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel
+import com.android.systemui.util.kotlin.mapValuesNotNullTo
 import com.android.systemui.util.ui.AnimatedValue
 import kotlinx.coroutines.flow.Flow
 
@@ -37,17 +42,14 @@ interface NotificationIconContainerViewModel {
     /** The colors with which to display the notification icons. */
     val iconColors: Flow<ColorLookup>
 
-    /**
-     * Signal completion of the [isDozing] animation; if [isDozing]'s [AnimatedValue.isAnimating]
-     * property was `true`, calling this method will update it to `false`.
-     */
-    fun completeDozeAnimation()
+    /** [IconsViewData] indicating which icons to display in the view. */
+    val iconsViewData: Flow<IconsViewData>
 
-    /**
-     * Signal completion of the [isVisible] animation; if [isVisible]'s [AnimatedValue.isAnimating]
-     * property was `true`, calling this method will update it to `false`.
-     */
-    fun completeVisibilityAnimation()
+    /** An Icon to show "isolated" in the IconContainer. */
+    val isolatedIcon: Flow<AnimatedValue<IconInfo?>>
+
+    /** Location to show an isolated icon, if there is one. */
+    val isolatedIconLocation: Flow<Rect>
 
     /**
      * Lookup the colors to use for the notification icons based on the bounds of the icon
@@ -69,4 +71,126 @@ interface NotificationIconContainerViewModel {
          */
         fun staticDrawableColor(viewBounds: Rect, isColorized: Boolean): Int
     }
+
+    /** Encapsulates the collection of notification icons present on the device. */
+    data class IconsViewData(
+        /** Icons that are visible in the container. */
+        val visibleKeys: List<IconInfo> = emptyList(),
+        /** Keys of icons that are "behind" the overflow dot. */
+        val collapsedKeys: Set<String> = emptySet(),
+        /** Whether the overflow dot should be shown regardless if [collapsedKeys] is empty. */
+        val forceShowDot: Boolean = false,
+    ) {
+        /** The difference between two [IconsViewData]s. */
+        data class Diff(
+            /** Icons added in the newer dataset. */
+            val added: List<IconInfo> = emptyList(),
+            /** Icons removed from the older dataset. */
+            val removed: List<String> = emptyList(),
+            /**
+             * Groups whose icon was replaced with a single new notification icon. The key of the
+             * [Map] is the notification group key, and the value is the new icon.
+             *
+             * Specifically, this models a difference where the older dataset had notification
+             * groups with a single icon in the set, and the newer dataset has a single, different
+             * icon for the same group. A view binder can use this information for special
+             * animations for this specific change.
+             */
+            val groupReplacements: Map<String, IconInfo> = emptyMap(),
+        )
+
+        companion object {
+            /**
+             * Returns an [IconsViewData.Diff] calculated from a [new] and [previous][prev]
+             * [IconsViewData] state.
+             */
+            fun computeDifference(new: IconsViewData, prev: IconsViewData): Diff {
+                val added: List<IconInfo> =
+                    new.visibleKeys.filter {
+                        it.notifKey !in prev.visibleKeys.asSequence().map { it.notifKey }
+                    }
+                val removed: List<IconInfo> =
+                    prev.visibleKeys.filter {
+                        it.notifKey !in new.visibleKeys.asSequence().map { it.notifKey }
+                    }
+                val groupsToShow: Set<IconGroupInfo> =
+                    new.visibleKeys.asSequence().map { it.groupInfo }.toSet()
+                val replacements: ArrayMap<String, IconInfo> =
+                    removed
+                        .asSequence()
+                        .filter { keyToRemove -> keyToRemove.groupInfo in groupsToShow }
+                        .groupBy { it.groupInfo.groupKey }
+                        .mapValuesNotNullTo(ArrayMap()) { (_, vs) ->
+                            vs.takeIf { it.size == 1 }?.get(0)
+                        }
+                return Diff(added, removed.map { it.notifKey }, replacements)
+            }
+        }
+    }
+
+    /** An Icon, and keys for unique identification. */
+    data class IconInfo(
+        val sourceIcon: Icon,
+        val notifKey: String,
+        val groupKey: String,
+    )
+}
+
+/**
+ * Construct an [IconInfo] out of an [ActiveNotificationModel], or return `null` if one cannot be
+ * created due to missing information.
+ */
+fun ActiveNotificationModel.toIconInfo(sourceIcon: Icon?): IconInfo? {
+    return sourceIcon?.let {
+        groupKey?.let { groupKey ->
+            IconInfo(
+                sourceIcon = sourceIcon,
+                notifKey = key,
+                groupKey = groupKey,
+            )
+        }
+    }
+}
+
+private val IconInfo.groupInfo: IconGroupInfo
+    get() = IconGroupInfo(sourceIcon, groupKey)
+
+private data class IconGroupInfo(
+    val sourceIcon: Icon,
+    val groupKey: String,
+) {
+
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (javaClass != other?.javaClass) return false
+
+        other as IconGroupInfo
+
+        if (groupKey != other.groupKey) return false
+        return sourceIcon.sameAs(other.sourceIcon)
+    }
+
+    override fun hashCode(): Int {
+        var result = groupKey.hashCode()
+        result = 31 * result + sourceIcon.type.hashCode()
+        when (sourceIcon.type) {
+            Icon.TYPE_BITMAP,
+            Icon.TYPE_ADAPTIVE_BITMAP -> {
+                result = 31 * result + sourceIcon.bitmap.hashCode()
+            }
+            Icon.TYPE_DATA -> {
+                result = 31 * result + sourceIcon.dataLength.hashCode()
+                result = 31 * result + sourceIcon.dataOffset.hashCode()
+            }
+            Icon.TYPE_RESOURCE -> {
+                result = 31 * result + sourceIcon.resId.hashCode()
+                result = 31 * result + sourceIcon.resPackage.hashCode()
+            }
+            Icon.TYPE_URI,
+            Icon.TYPE_URI_ADAPTIVE_BITMAP -> {
+                result = 31 * result + sourceIcon.uriString.hashCode()
+            }
+        }
+        return result
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/ActiveNotificationModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/ActiveNotificationModel.kt
index ea29cab3b7dcfc62b913c77c11564f306d8d1534..78370baa43116aa991c2def48c61d9981e8ffa15 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/ActiveNotificationModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/ActiveNotificationModel.kt
@@ -15,8 +15,36 @@
 
 package com.android.systemui.statusbar.notification.shared
 
+import android.graphics.drawable.Icon
+
 /** Model for entries in the notification stack. */
 data class ActiveNotificationModel(
     /** Notification key associated with this entry. */
     val key: String,
+    /** Notification group key associated with this entry. */
+    val groupKey: String?,
+    /** Is this entry in the ambient / minimized section (lowest priority)? */
+    val isAmbient: Boolean,
+    /**
+     * Is this entry dismissed? This is `true` when the user has dismissed the notification in the
+     * UI, but `NotificationManager` has not yet signalled to us that it has received the dismissal.
+     */
+    val isRowDismissed: Boolean,
+    /** Is this entry in the silent section? */
+    val isSilent: Boolean,
+    /**
+     * Does this entry represent a conversation, the last message of which was from a remote input
+     * reply?
+     */
+    val isLastMessageFromReply: Boolean,
+    /** Is this entry suppressed from appearing in the status bar as an icon? */
+    val isSuppressedFromStatusBar: Boolean,
+    /** Is this entry actively pulsing on AOD or bypassed-keyguard? */
+    val isPulsing: Boolean,
+    /** Icon to display on AOD. */
+    val aodIcon: Icon?,
+    /** Icon to display in the notification shelf. */
+    val shelfIcon: Icon?,
+    /** Icon to display in the status bar. */
+    val statusBarIcon: Icon?,
 )
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 77d5a2d70d4399ccc10341dace416c14e0d3146b..1e9cfa8d1d3a78bc15c038b79d9a8249ab1dc307 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
@@ -107,6 +107,7 @@ import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
+import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor;
 import com.android.systemui.statusbar.notification.footer.ui.view.FooterView;
 import com.android.systemui.statusbar.notification.init.NotificationsController;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
@@ -694,7 +695,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
         super.onFinishInflate();
 
         inflateEmptyShadeView();
-        inflateFooterView();
+        if (!FooterViewRefactor.isEnabled()) {
+            inflateFooterView();
+        }
     }
 
     /**
@@ -729,9 +732,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
     }
 
     void reinflateViews() {
-        inflateFooterView();
+        if (!FooterViewRefactor.isEnabled()) {
+            inflateFooterView();
+            updateFooter();
+        }
         inflateEmptyShadeView();
-        updateFooter();
         mSectionsManager.reinflateViews();
     }
 
@@ -746,7 +751,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
 
     @VisibleForTesting
     public void updateFooter() {
-        if (mFooterView == null) {
+        if (mFooterView == null || mController == null) {
             return;
         }
         // TODO: move this logic to controller, which will invoke updateFooterView directly
@@ -4546,7 +4551,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
         return mFooterView != null && mFooterView.isHistoryShown();
     }
 
-    void setFooterView(@NonNull FooterView footerView) {
+    /** Bind the {@link FooterView} to the NSSL. */
+    public void setFooterView(@NonNull FooterView footerView) {
         int index = -1;
         if (mFooterView != null) {
             index = indexOfChild(mFooterView);
@@ -4557,6 +4563,16 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
         if (mManageButtonClickListener != null) {
             mFooterView.setManageButtonClickListener(mManageButtonClickListener);
         }
+        mFooterView.setClearAllButtonClickListener(v -> {
+            if (mFooterClearAllListener != null) {
+                mFooterClearAllListener.onClearAll();
+            }
+            clearNotifications(ROWS_ALL, true /* closeShade */);
+            footerView.setSecondaryVisible(false /* visible */, true /* animate */);
+        });
+        if (FooterViewRefactor.isEnabled()) {
+            updateFooter();
+        }
     }
 
     public void setEmptyShadeView(EmptyShadeView emptyShadeView) {
@@ -4619,7 +4635,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
         mFooterView.setVisible(visible, animate);
         mFooterView.setSecondaryVisible(showDismissView, animate);
         mFooterView.showHistory(showHistory);
-        mFooterView.setFooterLabelVisible(mHasFilteredOutSeenNotifications);
+        if (!FooterViewRefactor.isEnabled()) {
+            mFooterView.setFooterLabelVisible(mHasFilteredOutSeenNotifications);
+        }
     }
 
     @VisibleForTesting
@@ -5370,15 +5388,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
 
     @VisibleForTesting
     protected void inflateFooterView() {
+        FooterViewRefactor.assertInLegacyMode();
         FooterView footerView = (FooterView) LayoutInflater.from(mContext).inflate(
                 R.layout.status_bar_notification_footer, this, false);
-        footerView.setClearAllButtonClickListener(v -> {
-            if (mFooterClearAllListener != null) {
-                mFooterClearAllListener.onClearAll();
-            }
-            clearNotifications(ROWS_ALL, true /* closeShade */);
-            footerView.setSecondaryVisible(false /* visible */, true /* animate */);
-        });
         setFooterView(footerView);
     }
 
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 8e88a91b5cd97ba7cded084aaa813d52a3d87256..79448b46fa06eba76413ae70f6aaada8c567b1d0 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
@@ -62,7 +62,7 @@ import com.android.systemui.classifier.FalsingCollector;
 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.FeatureFlagsClassic;
 import com.android.systemui.flags.Flags;
 import com.android.systemui.flags.RefactorFlag;
 import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository;
@@ -206,7 +206,7 @@ public class NotificationStackScrollLayoutController {
     private HeadsUpAppearanceController mHeadsUpAppearanceController;
     private boolean mIsInTransitionToAod = false;
 
-    private final FeatureFlags mFeatureFlags;
+    private final FeatureFlagsClassic mFeatureFlags;
     private final RefactorFlag mShelfRefactor;
     private final NotificationTargetsHelper mNotificationTargetsHelper;
     private final SecureSettings mSecureSettings;
@@ -669,7 +669,7 @@ public class NotificationStackScrollLayoutController {
             NotificationStackScrollLogger logger,
             NotificationStackSizeCalculator notificationStackSizeCalculator,
             NotificationIconAreaController notifIconAreaController,
-            FeatureFlags featureFlags,
+            FeatureFlagsClassic featureFlags,
             NotificationTargetsHelper notificationTargetsHelper,
             SecureSettings secureSettings,
             NotificationDismissibilityProvider dismissibilityProvider,
@@ -832,7 +832,8 @@ public class NotificationStackScrollLayoutController {
 
         mViewModel.ifPresent(
                 vm -> NotificationListViewBinder
-                        .bind(mView, vm, mFalsingManager, mFeatureFlags, mNotifIconAreaController));
+                        .bind(mView, vm, mFalsingManager, mFeatureFlags, mNotifIconAreaController,
+                                mConfigurationController));
 
         collectFlow(mView, mKeyguardTransitionRepo.getTransitions(),
                 this::onKeyguardTransitionChanged);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
index dee3973edb55169daff368612a6e3828b69403d2..a3792cf6a0f07cc8e4bc548998212a5605f6e18e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
@@ -17,14 +17,23 @@
 package com.android.systemui.statusbar.notification.stack.ui.viewbinder
 
 import android.view.LayoutInflater
-import com.android.systemui.res.R
-import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.FeatureFlagsClassic
+import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.res.R
 import com.android.systemui.statusbar.NotificationShelf
+import com.android.systemui.statusbar.notification.footer.ui.view.FooterView
+import com.android.systemui.statusbar.notification.footer.ui.viewbinder.FooterViewBinder
 import com.android.systemui.statusbar.notification.shelf.ui.viewbinder.NotificationShelfViewBinder
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
 import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationListViewModel
 import com.android.systemui.statusbar.phone.NotificationIconAreaController
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.onDensityOrFontScaleChanged
+import com.android.systemui.statusbar.policy.onThemeChanged
+import com.android.systemui.util.traceSection
+import com.android.systemui.util.view.reinflateAndBindLatest
+import kotlinx.coroutines.flow.merge
 
 /** Binds a [NotificationStackScrollLayout] to its [view model][NotificationListViewModel]. */
 object NotificationListViewBinder {
@@ -33,8 +42,9 @@ object NotificationListViewBinder {
         view: NotificationStackScrollLayout,
         viewModel: NotificationListViewModel,
         falsingManager: FalsingManager,
-        featureFlags: FeatureFlags,
+        featureFlags: FeatureFlagsClassic,
         iconAreaController: NotificationIconAreaController,
+        configurationController: ConfigurationController,
     ) {
         val shelf =
             LayoutInflater.from(view.context)
@@ -47,5 +57,26 @@ object NotificationListViewBinder {
             iconAreaController
         )
         view.setShelf(shelf)
+
+        viewModel.footer.ifPresent { footerViewModel ->
+            // The footer needs to be re-inflated every time the theme or the font size changes.
+            view.repeatWhenAttached {
+                LayoutInflater.from(view.context).reinflateAndBindLatest(
+                    R.layout.status_bar_notification_footer,
+                    view,
+                    attachToRoot = false,
+                    // TODO(b/305930747): This may lead to duplicate invocations if both flows emit,
+                    // find a solution to only emit one event.
+                    merge(
+                        configurationController.onThemeChanged,
+                        configurationController.onDensityOrFontScaleChanged,
+                    ),
+                ) { view ->
+                    traceSection("bind FooterView") {
+                        FooterViewBinder.bind(view as FooterView, footerViewModel)
+                    }
+                }
+            }
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt
index 11f68e0f663b6970b06f56ee84927f95b8a0a6bf..261371d59a3d983dcf0749352e863f2e6a88a54b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt
@@ -17,8 +17,9 @@
 package com.android.systemui.statusbar.notification.stack.ui.viewmodel
 
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.FeatureFlagsClassic
 import com.android.systemui.flags.Flags
+import com.android.systemui.statusbar.notification.footer.ui.viewmodel.FooterViewModel
 import com.android.systemui.statusbar.notification.shelf.ui.viewmodel.NotificationShelfViewModel
 import dagger.Module
 import dagger.Provides
@@ -28,6 +29,7 @@ import javax.inject.Provider
 /** ViewModel for the list of notifications. */
 class NotificationListViewModel(
     val shelf: NotificationShelfViewModel,
+    val footer: Optional<FooterViewModel>,
 )
 
 @Module
@@ -36,12 +38,33 @@ object NotificationListViewModelModule {
     @Provides
     @SysUISingleton
     fun maybeProvideViewModel(
-        featureFlags: FeatureFlags,
+        featureFlags: FeatureFlagsClassic,
         shelfViewModel: Provider<NotificationShelfViewModel>,
-    ): Optional<NotificationListViewModel> =
-        if (featureFlags.isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR)) {
-            Optional.of(NotificationListViewModel(shelfViewModel.get()))
+        footerViewModel: Provider<FooterViewModel>,
+    ): Optional<NotificationListViewModel> {
+        return if (featureFlags.isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR)) {
+            if (com.android.systemui.Flags.notificationsFooterViewRefactor()) {
+                Optional.of(
+                    NotificationListViewModel(
+                        shelfViewModel.get(),
+                        Optional.of(footerViewModel.get())
+                    )
+                )
+            } else {
+                Optional.of(NotificationListViewModel(shelfViewModel.get(), Optional.empty()))
+            }
         } else {
+            if (com.android.systemui.Flags.notificationsFooterViewRefactor()) {
+                throw IllegalStateException(
+                    "The com.android.systemui.notifications_footer_view_refactor flag requires " +
+                        "the notification_shelf_refactor flag to be enabled. First disable the " +
+                        "footer flag using `adb shell device_config put systemui " +
+                        "com.android.systemui.notifications_footer_view_refactor false`, then " +
+                        "enable the notification_shelf_refactor flag in Flag Flipper. " +
+                        "Afterwards, you can try re-enabling the footer refactor flag via adb."
+                )
+            }
             Optional.empty()
         }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
index 07d3a1cf24c06e9a51810b255eafc1ef4a0fd0b5..2d125462b16ef3c7fff0a16a5d70d8974a9eb0e1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
@@ -30,7 +30,6 @@ import android.view.View
 import android.view.WindowManager
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.systemui.ActivityIntentHelper
-import com.android.systemui.res.R
 import com.android.systemui.animation.ActivityLaunchAnimator
 import com.android.systemui.animation.ActivityLaunchAnimator.PendingIntentStarter
 import com.android.systemui.animation.DelegateLaunchAnimatorController
@@ -43,6 +42,7 @@ import com.android.systemui.keyguard.KeyguardViewMediator
 import com.android.systemui.keyguard.WakefulnessLifecycle
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.plugins.ActivityStarter.OnDismissAction
+import com.android.systemui.res.R
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.shade.ShadeController
 import com.android.systemui.shade.ShadeViewController
@@ -134,6 +134,19 @@ constructor(
         )
     }
 
+    override fun startPendingIntentMaybeDismissingKeyguard(
+        intent: PendingIntent,
+        intentSentUiThreadCallback: Runnable?,
+        animationController: ActivityLaunchAnimator.Controller?
+    ) {
+        activityStarterInternal.startPendingIntentDismissingKeyguard(
+            intent = intent,
+            intentSentUiThreadCallback = intentSentUiThreadCallback,
+            animationController = animationController,
+            showOverLockscreen = true,
+        )
+    }
+
     /**
      * TODO(b/279084380): Change callers to just call startActivityDismissingKeyguard and deprecate
      *   this.
@@ -454,7 +467,7 @@ constructor(
                     !willLaunchResolverActivity &&
                     shouldAnimateLaunch(isActivityIntent = true)
             val animController =
-                wrapAnimationController(
+                wrapAnimationControllerForShadeOrStatusBar(
                     animationController = animationController,
                     dismissShade = dismissShade,
                     isLaunchForActivity = true,
@@ -547,12 +560,18 @@ constructor(
             )
         }
 
-        /** Starts a pending intent after dismissing keyguard. */
+        /**
+         * Starts a pending intent after dismissing keyguard.
+         *
+         * This can be called in a background thread (to prevent calls in [ActivityIntentHelper] in
+         * the main thread).
+         */
         fun startPendingIntentDismissingKeyguard(
             intent: PendingIntent,
             intentSentUiThreadCallback: Runnable? = null,
             associatedView: View? = null,
             animationController: ActivityLaunchAnimator.Controller? = null,
+            showOverLockscreen: Boolean = false,
         ) {
             val animationController =
                 if (associatedView is ExpandableNotificationRow) {
@@ -566,79 +585,103 @@ constructor(
                         lockScreenUserManager.currentUserId,
                     ))
 
+            val actuallyShowOverLockscreen =
+                showOverLockscreen &&
+                    intent.isActivity &&
+                    activityIntentHelper.wouldPendingShowOverLockscreen(
+                        intent,
+                        lockScreenUserManager.currentUserId
+                    )
+
             val animate =
                 !willLaunchResolverActivity &&
                     animationController != null &&
-                    shouldAnimateLaunch(intent.isActivity)
+                    shouldAnimateLaunch(intent.isActivity, actuallyShowOverLockscreen)
+
+            // We wrap animationCallback with a StatusBarLaunchAnimatorController so
+            // that the shade is collapsed after the animation (or when it is cancelled,
+            // aborted, etc).
+            val statusBarController =
+                wrapAnimationControllerForShadeOrStatusBar(
+                    animationController = animationController,
+                    dismissShade = true,
+                    isLaunchForActivity = intent.isActivity,
+                )
+            val controller =
+                if (actuallyShowOverLockscreen) {
+                    wrapAnimationControllerForLockscreen(statusBarController)
+                } else {
+                    statusBarController
+                }
 
             // If we animate, don't collapse the shade and defer the keyguard dismiss (in case we
             // run the animation on the keyguard). The animation will take care of (instantly)
             // collapsing the shade and hiding the keyguard once it is done.
             val collapse = !animate
-            executeRunnableDismissingKeyguard(
-                runnable = {
-                    try {
-                        // We wrap animationCallback with a StatusBarLaunchAnimatorController so
-                        // that the shade is collapsed after the animation (or when it is cancelled,
-                        // aborted, etc).
-                        val controller: ActivityLaunchAnimator.Controller? =
-                            wrapAnimationController(
-                                animationController = animationController,
-                                dismissShade = true,
-                                isLaunchForActivity = intent.isActivity,
-                            )
-                        activityLaunchAnimator.startPendingIntentWithAnimation(
-                            controller,
-                            animate,
-                            intent.creatorPackage,
-                            object : PendingIntentStarter {
-                                override fun startPendingIntent(
-                                    animationAdapter: RemoteAnimationAdapter?
-                                ): Int {
-                                    val options =
-                                        ActivityOptions(
-                                            CentralSurfaces.getActivityOptions(
-                                                displayId,
-                                                animationAdapter
-                                            )
+            val runnable = Runnable {
+                try {
+                    activityLaunchAnimator.startPendingIntentWithAnimation(
+                        controller,
+                        animate,
+                        intent.creatorPackage,
+                        actuallyShowOverLockscreen,
+                        object : PendingIntentStarter {
+                            override fun startPendingIntent(
+                                animationAdapter: RemoteAnimationAdapter?
+                            ): Int {
+                                val options =
+                                    ActivityOptions(
+                                        CentralSurfaces.getActivityOptions(
+                                            displayId,
+                                            animationAdapter
                                         )
-                                    // TODO b/221255671: restrict this to only be set for
-                                    // notifications
-                                    options.isEligibleForLegacyPermissionPrompt = true
-                                    options.setPendingIntentBackgroundActivityStartMode(
-                                        ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
                                     )
-                                    return intent.sendAndReturnResult(
-                                        null,
-                                        0,
-                                        null,
-                                        null,
-                                        null,
-                                        null,
-                                        options.toBundle()
-                                    )
-                                }
-                            },
-                        )
-                    } catch (e: PendingIntent.CanceledException) {
-                        // the stack trace isn't very helpful here.
-                        // Just log the exception message.
-                        Log.w(TAG, "Sending intent failed: $e")
-                        if (!collapse) {
-                            // executeRunnableDismissingKeyguard did not collapse for us already.
-                            shadeControllerLazy.get().collapseOnMainThread()
-                        }
-                        // TODO: Dismiss Keyguard.
-                    }
-                    if (intent.isActivity) {
-                        assistManagerLazy.get().hideAssist()
+                                // TODO b/221255671: restrict this to only be set for
+                                // notifications
+                                options.isEligibleForLegacyPermissionPrompt = true
+                                options.setPendingIntentBackgroundActivityStartMode(
+                                    ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
+                                )
+                                return intent.sendAndReturnResult(
+                                    null,
+                                    0,
+                                    null,
+                                    null,
+                                    null,
+                                    null,
+                                    options.toBundle()
+                                )
+                            }
+                        },
+                    )
+                } catch (e: PendingIntent.CanceledException) {
+                    // the stack trace isn't very helpful here.
+                    // Just log the exception message.
+                    Log.w(TAG, "Sending intent failed: $e")
+                    if (!collapse) {
+                        // executeRunnableDismissingKeyguard did not collapse for us already.
+                        shadeControllerLazy.get().collapseOnMainThread()
                     }
-                    intentSentUiThreadCallback?.let { postOnUiThread(runnable = it) }
-                },
-                afterKeyguardGone = willLaunchResolverActivity,
-                dismissShade = collapse,
-                willAnimateOnKeyguard = animate,
-            )
+                    // TODO: Dismiss Keyguard.
+                }
+                if (intent.isActivity) {
+                    assistManagerLazy.get().hideAssist()
+                }
+                intentSentUiThreadCallback?.let { postOnUiThread(runnable = it) }
+            }
+
+            if (!actuallyShowOverLockscreen) {
+                postOnUiThread(delay = 0) {
+                    executeRunnableDismissingKeyguard(
+                        runnable = runnable,
+                        afterKeyguardGone = willLaunchResolverActivity,
+                        dismissShade = collapse,
+                        willAnimateOnKeyguard = animate,
+                    )
+                }
+            } else {
+                postOnUiThread(delay = 0, runnable)
+            }
         }
 
         /** Starts an Activity. */
@@ -678,71 +721,12 @@ constructor(
                 // Wrap the animation controller to dismiss the shade and set
                 // mIsLaunchingActivityOverLockscreen during the animation.
                 val delegate =
-                    wrapAnimationController(
+                    wrapAnimationControllerForShadeOrStatusBar(
                         animationController = animationController,
                         dismissShade = dismissShade,
                         isLaunchForActivity = true,
                     )
-                delegate?.let {
-                    controller =
-                        object : DelegateLaunchAnimatorController(delegate) {
-                            override fun onIntentStarted(willAnimate: Boolean) {
-                                delegate?.onIntentStarted(willAnimate)
-                                if (willAnimate) {
-                                    centralSurfaces?.setIsLaunchingActivityOverLockscreen(true)
-                                }
-                            }
-
-                            override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {
-                                super.onLaunchAnimationStart(isExpandingFullyAbove)
-
-                                // Double check that the keyguard is still showing and not going
-                                // away, but if so set the keyguard occluded. Typically, WM will let
-                                // KeyguardViewMediator know directly, but we're overriding that to
-                                // play the custom launch animation, so we need to take care of that
-                                // here. The unocclude animation is not overridden, so WM will call
-                                // KeyguardViewMediator's unocclude animation runner when the
-                                // activity is exited.
-                                if (
-                                    keyguardStateController.isShowing &&
-                                        !keyguardStateController.isKeyguardGoingAway
-                                ) {
-                                    Log.d(TAG, "Setting occluded = true in #startActivity.")
-                                    keyguardViewMediatorLazy
-                                        .get()
-                                        .setOccluded(true /* isOccluded */, true /* animate */)
-                                }
-                            }
-
-                            override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) {
-                                // Set mIsLaunchingActivityOverLockscreen to false before actually
-                                // finishing the animation so that we can assume that
-                                // mIsLaunchingActivityOverLockscreen being true means that we will
-                                // collapse the shade (or at least run the post collapse runnables)
-                                // later on.
-                                centralSurfaces?.setIsLaunchingActivityOverLockscreen(false)
-                                delegate?.onLaunchAnimationEnd(isExpandingFullyAbove)
-                            }
-
-                            override fun onLaunchAnimationCancelled(
-                                newKeyguardOccludedState: Boolean?
-                            ) {
-                                if (newKeyguardOccludedState != null) {
-                                    keyguardViewMediatorLazy
-                                        .get()
-                                        .setOccluded(newKeyguardOccludedState, false /* animate */)
-                                }
-
-                                // Set mIsLaunchingActivityOverLockscreen to false before actually
-                                // finishing the animation so that we can assume that
-                                // mIsLaunchingActivityOverLockscreen being true means that we will
-                                // collapse the shade (or at least run the // post collapse
-                                // runnables) later on.
-                                centralSurfaces?.setIsLaunchingActivityOverLockscreen(false)
-                                delegate.onLaunchAnimationCancelled(newKeyguardOccludedState)
-                            }
-                        }
-                }
+                controller = wrapAnimationControllerForLockscreen(delegate)
             } else if (dismissShade) {
                 // The animation will take care of dismissing the shade at the end of the animation.
                 // If we don't animate, collapse it directly.
@@ -874,7 +858,7 @@ constructor(
          *   window.
          * @param isLaunchForActivity whether the launch is for an activity.
          */
-        private fun wrapAnimationController(
+        private fun wrapAnimationControllerForShadeOrStatusBar(
             animationController: ActivityLaunchAnimator.Controller?,
             dismissShade: Boolean,
             isLaunchForActivity: Boolean,
@@ -909,6 +893,72 @@ constructor(
             return animationController
         }
 
+        /**
+         * Wraps an animation controller so that if an activity would be launched on top of the
+         * lockscreen, the correct flags are set for it to be occluded.
+         */
+        private fun wrapAnimationControllerForLockscreen(
+            animationController: ActivityLaunchAnimator.Controller?
+        ): ActivityLaunchAnimator.Controller? {
+            return animationController?.let {
+                object : DelegateLaunchAnimatorController(it) {
+                    override fun onIntentStarted(willAnimate: Boolean) {
+                        delegate.onIntentStarted(willAnimate)
+                        if (willAnimate) {
+                            centralSurfaces?.setIsLaunchingActivityOverLockscreen(true)
+                        }
+                    }
+
+                    override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {
+                        super.onLaunchAnimationStart(isExpandingFullyAbove)
+
+                        // Double check that the keyguard is still showing and not going
+                        // away, but if so set the keyguard occluded. Typically, WM will let
+                        // KeyguardViewMediator know directly, but we're overriding that to
+                        // play the custom launch animation, so we need to take care of that
+                        // here. The unocclude animation is not overridden, so WM will call
+                        // KeyguardViewMediator's unocclude animation runner when the
+                        // activity is exited.
+                        if (
+                            keyguardStateController.isShowing &&
+                                !keyguardStateController.isKeyguardGoingAway
+                        ) {
+                            Log.d(TAG, "Setting occluded = true in #startActivity.")
+                            keyguardViewMediatorLazy
+                                .get()
+                                .setOccluded(true /* isOccluded */, true /* animate */)
+                        }
+                    }
+
+                    override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) {
+                        // Set mIsLaunchingActivityOverLockscreen to false before actually
+                        // finishing the animation so that we can assume that
+                        // mIsLaunchingActivityOverLockscreen being true means that we will
+                        // collapse the shade (or at least run the post collapse runnables)
+                        // later on.
+                        centralSurfaces?.setIsLaunchingActivityOverLockscreen(false)
+                        delegate.onLaunchAnimationEnd(isExpandingFullyAbove)
+                    }
+
+                    override fun onLaunchAnimationCancelled(newKeyguardOccludedState: Boolean?) {
+                        if (newKeyguardOccludedState != null) {
+                            keyguardViewMediatorLazy
+                                .get()
+                                .setOccluded(newKeyguardOccludedState, false /* animate */)
+                        }
+
+                        // Set mIsLaunchingActivityOverLockscreen to false before actually
+                        // finishing the animation so that we can assume that
+                        // mIsLaunchingActivityOverLockscreen being true means that we will
+                        // collapse the shade (or at least run the // post collapse
+                        // runnables) later on.
+                        centralSurfaces?.setIsLaunchingActivityOverLockscreen(false)
+                        delegate.onLaunchAnimationCancelled(newKeyguardOccludedState)
+                    }
+                }
+            }
+        }
+
         /** Retrieves the current user handle to start the Activity. */
         private fun getActivityUserHandle(intent: Intent): UserHandle {
             val packages: Array<String> =
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 daa4f1807625572a1079ff1aebd034a2bdfacbc5..cbe9d4b93ead10a01c72d351972c67cffdb79666 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -733,8 +733,8 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
 
         // Suppress all face auth errors if fingerprint can be used to authenticate
         if ((biometricSourceType == BiometricSourceType.FACE
-                && !mUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
-                mSelectedUserInteractor.get().getSelectedUserId()))
+                && !mUpdateMonitor.isUnlockWithFingerprintPossible(
+                    mSelectedUserInteractor.get().getSelectedUserId()))
                 || (biometricSourceType == BiometricSourceType.FINGERPRINT)) {
             mHapticsInteractor.vibrateError();
         }
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 cb85966ca581d789db5e75b47f632a1093ccebb3..8295f65f2eced92dfabf0edde45ffee690d50b96 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -202,7 +202,6 @@ import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
 import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
-import com.android.systemui.statusbar.notification.data.repository.NotificationExpansionRepository;
 import com.android.systemui.statusbar.notification.init.NotificationsController;
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -296,7 +295,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
     private CentralSurfacesCommandQueueCallbacks mCommandQueueCallbacks;
     private float mTransitionToFullShadeProgress = 0f;
     private final NotificationListContainer mNotifListContainer;
-    private final NotificationExpansionRepository mNotificationExpansionRepository;
     private boolean mIsShortcutListSearchEnabled;
 
     private final KeyguardStateController.Callback mKeyguardStateControllerCallback =
@@ -650,7 +648,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
             Lazy<NotificationPresenter> notificationPresenterLazy,
             Lazy<NotificationActivityStarter> notificationActivityStarterLazy,
             NotificationLaunchAnimatorControllerProvider notifLaunchAnimatorControllerProvider,
-            NotificationExpansionRepository notificationExpansionRepository,
             DozeParameters dozeParameters,
             ScrimController scrimController,
             Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
@@ -759,7 +756,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
         mPresenterLazy = notificationPresenterLazy;
         mNotificationActivityStarterLazy = notificationActivityStarterLazy;
         mNotificationAnimationProvider = notifLaunchAnimatorControllerProvider;
-        mNotificationExpansionRepository = notificationExpansionRepository;
         mDozeServiceHost = dozeServiceHost;
         mPowerManager = powerManager;
         mDozeParameters = dozeParameters;
@@ -2530,7 +2526,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
                                     && mFingerprintManager.get() != null
                                     && mFingerprintManager.get().isPowerbuttonFps()
                                     && mKeyguardUpdateMonitor
-                                    .getCachedIsUnlockWithFingerprintPossible(
+                                    .isUnlockWithFingerprintPossible(
                                             mUserTracker.getUserId())
                                     && !touchToUnlockAnytime;
                     if (DEBUG_WAKEUP_DELAY) {
@@ -3106,7 +3102,9 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
             }
             // TODO: Bring these out of CentralSurfaces.
             mUserInfoControllerImpl.onDensityOrFontScaleChanged();
-            mNotificationIconAreaController.onDensityOrFontScaleChanged(mContext);
+            if (!mFeatureFlags.isEnabled(Flags.NOTIFICATION_ICON_CONTAINER_REFACTOR)) {
+                mNotificationIconAreaController.onDensityOrFontScaleChanged(mContext);
+            }
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
index d3d11ea4a9f38513f45456f5e6e6eaaafdcd6ca8..66341ba42a6449027c1f770574fadd7173cbc1e1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
@@ -37,6 +37,8 @@ import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.doze.DozeHost;
 import com.android.systemui.doze.DozeLog;
 import com.android.systemui.doze.DozeReceiver;
+import com.android.systemui.flags.FeatureFlagsClassic;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.keyguard.domain.interactor.DozeInteractor;
 import com.android.systemui.shade.NotificationShadeWindowViewController;
@@ -82,6 +84,7 @@ public final class DozeServiceHost implements DozeHost {
     private final SysuiStatusBarStateController mStatusBarStateController;
     private final DeviceProvisionedController mDeviceProvisionedController;
     private final HeadsUpManager mHeadsUpManager;
+    private final FeatureFlagsClassic mFeatureFlags;
     private final BatteryController mBatteryController;
     private final ScrimController mScrimController;
     private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
@@ -107,6 +110,7 @@ public final class DozeServiceHost implements DozeHost {
             WakefulnessLifecycle wakefulnessLifecycle,
             SysuiStatusBarStateController statusBarStateController,
             DeviceProvisionedController deviceProvisionedController,
+            FeatureFlagsClassic featureFlags,
             HeadsUpManager headsUpManager, BatteryController batteryController,
             ScrimController scrimController,
             Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
@@ -130,6 +134,7 @@ public final class DozeServiceHost implements DozeHost {
         mBiometricUnlockControllerLazy = biometricUnlockControllerLazy;
         mAssistManagerLazy = assistManagerLazy;
         mDozeScrimController = dozeScrimController;
+        mFeatureFlags = featureFlags;
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mPulseExpansionHandler = pulseExpansionHandler;
         mNotificationShadeWindowController = notificationShadeWindowController;
@@ -173,8 +178,13 @@ public final class DozeServiceHost implements DozeHost {
 
     void fireNotificationPulse(NotificationEntry entry) {
         Runnable pulseSuppressedListener = () -> {
-            entry.setPulseSuppressed(true);
-            mNotificationIconAreaController.updateAodNotificationIcons();
+            if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_ICON_CONTAINER_REFACTOR)) {
+                mHeadsUpManager.removeNotification(
+                        entry.getKey(), /* releaseImmediately= */ true, /* animate= */ false);
+            } else {
+                entry.setPulseSuppressed(true);
+                mNotificationIconAreaController.updateAodNotificationIcons();
+            }
         };
         Assert.isMainThread();
         for (Callback callback : mCallbacks) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index c493eeda707733945b1968a1a46e816eeb7f1b92..8fee5c0487f33a3c4df730d361e98ca29adf4f8d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -26,6 +26,8 @@ import androidx.annotation.NonNull;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.widget.ViewClippingUtil;
+import com.android.systemui.flags.FeatureFlagsClassic;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.res.R;
@@ -38,6 +40,7 @@ import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.SourceType;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationIconInteractor;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
@@ -104,6 +107,8 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
             };
     private boolean mAnimationsEnabled = true;
     private final KeyguardStateController mKeyguardStateController;
+    private final FeatureFlagsClassic mFeatureFlags;
+    private final HeadsUpNotificationIconInteractor mHeadsUpNotificationIconInteractor;
 
     @VisibleForTesting
     @Inject
@@ -122,6 +127,8 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
             NotificationRoundnessManager notificationRoundnessManager,
             HeadsUpStatusBarView headsUpStatusBarView,
             Clock clockView,
+            FeatureFlagsClassic featureFlags,
+            HeadsUpNotificationIconInteractor headsUpNotificationIconInteractor,
             @Named(OPERATOR_NAME_FRAME_VIEW) Optional<View> operatorNameViewOptional) {
         super(headsUpStatusBarView);
         mNotificationIconAreaController = notificationIconAreaController;
@@ -139,6 +146,8 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
 
         mStackScrollerController = stackScrollerController;
         mShadeViewController = shadeViewController;
+        mFeatureFlags = featureFlags;
+        mHeadsUpNotificationIconInteractor = headsUpNotificationIconInteractor;
         mStackScrollerController.setHeadsUpAppearanceController(this);
         mClockView = clockView;
         mOperatorNameViewOptional = operatorNameViewOptional;
@@ -170,6 +179,9 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
         mHeadsUpManager.addListener(this);
         mView.setOnDrawingRectChangedListener(
                 () -> updateIsolatedIconLocation(true /* requireUpdate */));
+        if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_ICON_CONTAINER_REFACTOR)) {
+            updateIsolatedIconLocation(true);
+        }
         mWakeUpCoordinator.addListener(this);
         getShadeHeadsUpTracker().addTrackingHeadsUpListener(mSetTrackingHeadsUp);
         getShadeHeadsUpTracker().setHeadsUpAppearanceController(this);
@@ -185,6 +197,9 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
     protected void onViewDetached() {
         mHeadsUpManager.removeListener(this);
         mView.setOnDrawingRectChangedListener(null);
+        if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_ICON_CONTAINER_REFACTOR)) {
+            mHeadsUpNotificationIconInteractor.setIsolatedIconLocation(null);
+        }
         mWakeUpCoordinator.removeListener(this);
         getShadeHeadsUpTracker().removeTrackingHeadsUpListener(mSetTrackingHeadsUp);
         getShadeHeadsUpTracker().setHeadsUpAppearanceController(null);
@@ -193,8 +208,13 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
     }
 
     private void updateIsolatedIconLocation(boolean requireStateUpdate) {
-        mNotificationIconAreaController.setIsolatedIconLocation(
-                mView.getIconDrawingRect(), requireStateUpdate);
+        if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_ICON_CONTAINER_REFACTOR)) {
+            mHeadsUpNotificationIconInteractor
+                    .setIsolatedIconLocation(mView.getIconDrawingRect());
+        } else {
+            mNotificationIconAreaController.setIsolatedIconLocation(
+                    mView.getIconDrawingRect(), requireStateUpdate);
+        }
     }
 
     @Override
@@ -230,9 +250,14 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
                 setShown(true);
                 animateIsolation = !isExpanded();
             }
-            updateIsolatedIconLocation(false /* requireUpdate */);
-            mNotificationIconAreaController.showIconIsolated(newEntry == null ? null
-                    : newEntry.getIcons().getStatusBarIcon(), animateIsolation);
+            if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_ICON_CONTAINER_REFACTOR)) {
+                mHeadsUpNotificationIconInteractor.setIsolatedIconNotificationKey(
+                        newEntry == null ? null : newEntry.getKey());
+            } else {
+                updateIsolatedIconLocation(false /* requireUpdate */);
+                mNotificationIconAreaController.showIconIsolated(newEntry == null ? null
+                        : newEntry.getIcons().getStatusBarIcon(), animateIsolation);
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
index 63591d7d6f51461bfdf90aeda89295ce20554ffe..b0183d3fbd407945582fbcda115f350d3fbf4ad2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
@@ -58,7 +58,7 @@ open class KeyguardBypassController : Dumpable, StackScrollAlgorithm.BypassContr
     private var pendingUnlock: PendingUnlock? = null
     private val listeners = mutableListOf<OnBypassStateChangedListener>()
     private val faceAuthEnabledChangedCallback = object : KeyguardStateController.Callback {
-        override fun onFaceAuthEnabledChanged() = notifyListeners()
+        override fun onFaceEnrolledChanged() = notifyListeners()
     }
 
     @IntDef(
@@ -98,7 +98,7 @@ open class KeyguardBypassController : Dumpable, StackScrollAlgorithm.BypassContr
                 FACE_UNLOCK_BYPASS_NEVER -> false
                 else -> field
             }
-            return enabled && mKeyguardStateController.isFaceAuthEnabled &&
+            return enabled && mKeyguardStateController.isFaceEnrolled &&
                     isPostureAllowedForFaceAuth()
         }
         private set(value) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
index 109e77e92b7becc34aa8e8ba5131627149239f69..332984413dde263c6f60abe0fef2e05f37b9883a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
@@ -117,9 +117,7 @@ class KeyguardLiftController @Inject constructor(
         val onKeyguard = keyguardUpdateMonitor.isKeyguardVisible &&
                 !statusBarStateController.isDozing
 
-        val userId = selectedUserInteractor.getSelectedUserId()
-        val isFaceEnabled = keyguardUpdateMonitor.isFaceAuthEnabledForUser(userId)
-        val shouldListen = (onKeyguard || bouncerVisible) && isFaceEnabled
+        val shouldListen = (onKeyguard || bouncerVisible) && keyguardUpdateMonitor.isFaceEnrolled
         if (shouldListen != isListening) {
             isListening = shouldListen
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImpl.java
index f9856b0415e850e24687f9fc88f39f060820001a..4284c96c9966b2264a4c9938e9e5a2ba732c5b99 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImpl.java
@@ -448,7 +448,7 @@ public class LegacyNotificationIconAreaControllerImpl implements
             }
         }
         replacingIcons.removeAll(duplicates);
-        hostLayout.setReplacingIcons(replacingIcons);
+        hostLayout.setReplacingIconsLegacy(replacingIcons);
 
         final int toRemoveCount = toRemove.size();
         for (int i = 0; i < toRemoveCount; i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index b15c0fdd5a4c5eddc46a73305ae73af01ed6cdd2..535f6acab5be48469009a565bdc66310caf58e91 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -40,6 +40,8 @@ import androidx.collection.ArrayMap;
 import com.android.app.animation.Interpolators;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.settingslib.Utils;
+import com.android.systemui.flags.Flags;
+import com.android.systemui.flags.RefactorFlag;
 import com.android.systemui.res.R;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.notification.stack.AnimationFilter;
@@ -131,6 +133,9 @@ public class NotificationIconContainer extends ViewGroup {
         }
     }.setDuration(CONTENT_FADE_DURATION);
 
+    private final RefactorFlag mIconContainerRefactorFlag =
+            RefactorFlag.forView(Flags.NOTIFICATION_ICON_CONTAINER_REFACTOR);
+
     /* Maximum number of icons on AOD when also showing overflow dot. */
     private int mMaxIconsOnAod;
 
@@ -156,7 +161,8 @@ public class NotificationIconContainer extends ViewGroup {
     private int mIconSize;
     private boolean mDisallowNextAnimation;
     private boolean mAnimationsEnabled = true;
-    private ArrayMap<String, ArrayList<StatusBarIcon>> mReplacingIcons;
+    private ArrayMap<String, StatusBarIcon> mReplacingIcons;
+    private ArrayMap<String, ArrayList<StatusBarIcon>> mReplacingIconsLegacy;
     // Keep track of the last visible icon so collapsed container can report on its location
     private IconState mLastVisibleIconState;
     private IconState mFirstVisibleIconState;
@@ -167,6 +173,7 @@ public class NotificationIconContainer extends ViewGroup {
     private final int[] mAbsolutePosition = new int[2];
     private View mIsolatedIconForAnimation;
     private int mThemedTextColorPrimary;
+    private Runnable mIsolatedIconAnimationEndRunnable;
 
     public NotificationIconContainer(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -339,23 +346,29 @@ public class NotificationIconContainer extends ViewGroup {
     }
 
     private boolean isReplacingIcon(View child) {
-        if (mReplacingIcons == null) {
-            return false;
-        }
         if (!(child instanceof StatusBarIconView)) {
             return false;
         }
         StatusBarIconView iconView = (StatusBarIconView) child;
         Icon sourceIcon = iconView.getSourceIcon();
         String groupKey = iconView.getNotification().getGroupKey();
-        ArrayList<StatusBarIcon> statusBarIcons = mReplacingIcons.get(groupKey);
-        if (statusBarIcons != null) {
-            StatusBarIcon replacedIcon = statusBarIcons.get(0);
-            if (sourceIcon.sameAs(replacedIcon.icon)) {
-                return true;
+        if (mIconContainerRefactorFlag.isEnabled()) {
+            if (mReplacingIcons == null) {
+                return false;
+            }
+            StatusBarIcon replacedIcon = mReplacingIcons.get(groupKey);
+            return replacedIcon != null && sourceIcon.sameAs(replacedIcon.icon);
+        } else {
+            if (mReplacingIconsLegacy == null) {
+                return false;
             }
+            ArrayList<StatusBarIcon> statusBarIcons = mReplacingIconsLegacy.get(groupKey);
+            if (statusBarIcons != null) {
+                StatusBarIcon replacedIcon = statusBarIcons.get(0);
+                return sourceIcon.sameAs(replacedIcon.icon);
+            }
+            return false;
         }
-        return false;
     }
 
     @Override
@@ -681,14 +694,36 @@ public class NotificationIconContainer extends ViewGroup {
         mAnimationsEnabled = enabled;
     }
 
-    public void setReplacingIcons(ArrayMap<String, ArrayList<StatusBarIcon>> replacingIcons) {
+    public void setReplacingIconsLegacy(ArrayMap<String, ArrayList<StatusBarIcon>> replacingIcons) {
+        mIconContainerRefactorFlag.assertInLegacyMode();
+        mReplacingIconsLegacy = replacingIcons;
+    }
+
+    public void setReplacingIcons(ArrayMap<String, StatusBarIcon> replacingIcons) {
+        if (mIconContainerRefactorFlag.isUnexpectedlyInLegacyMode()) return;
         mReplacingIcons = replacingIcons;
     }
 
+    @Deprecated
     public void showIconIsolated(StatusBarIconView icon, boolean animated) {
+        mIconContainerRefactorFlag.assertInLegacyMode();
         if (animated) {
-            mIsolatedIconForAnimation = icon != null ? icon : mIsolatedIcon;
+            showIconIsolatedAnimated(icon, null);
+        } else {
+            showIconIsolated(icon);
         }
+    }
+
+    public void showIconIsolatedAnimated(StatusBarIconView icon,
+            @Nullable Runnable onAnimationEnd) {
+        if (mIconContainerRefactorFlag.isUnexpectedlyInLegacyMode()) return;
+        mIsolatedIconForAnimation = icon != null ? icon : mIsolatedIcon;
+        mIsolatedIconAnimationEndRunnable = onAnimationEnd;
+        showIconIsolated(icon);
+    }
+
+    public void showIconIsolated(StatusBarIconView icon) {
+        if (mIconContainerRefactorFlag.isUnexpectedlyInLegacyMode()) return;
         mIsolatedIcon = icon;
         updateState();
     }
@@ -813,6 +848,11 @@ public class NotificationIconContainer extends ViewGroup {
                             animationProperties = UNISOLATION_PROPERTY;
                             animationProperties.setDelay(
                                     mIsolatedIcon != null ? CONTENT_FADE_DELAY : 0);
+                            Consumer<Property> endAction = getEndAction();
+                            if (endAction != null) {
+                                animationProperties.setAnimationEndAction(endAction);
+                                animationProperties.setAnimationCancelAction(endAction);
+                            }
                         } else {
                             animationProperties = UNISOLATION_PROPERTY_OTHERS;
                             animationProperties.setDelay(
@@ -836,6 +876,18 @@ public class NotificationIconContainer extends ViewGroup {
             needsCannedAnimation = false;
         }
 
+        @Nullable
+        private Consumer<Property> getEndAction() {
+            if (mIsolatedIconAnimationEndRunnable == null) return null;
+            final Runnable endRunnable = mIsolatedIconAnimationEndRunnable;
+            return prop -> {
+                endRunnable.run();
+                if (mIsolatedIconAnimationEndRunnable == endRunnable) {
+                    mIsolatedIconAnimationEndRunnable = null;
+                }
+            };
+        }
+
         @Override
         public void initFrom(View view) {
             super.initFrom(view);
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 63c022c5bb6b145114cfe69395220a6857e0f6aa..e2a4714e611684f019eda9edf310b1c4b9fd9ca8 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
@@ -38,9 +38,13 @@ import com.android.app.animation.Interpolators;
 import com.android.app.animation.InterpolatorsAndroidX;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.Dumpable;
+import com.android.systemui.common.ui.ConfigurationState;
 import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.demomode.DemoMode;
+import com.android.systemui.demomode.DemoModeController;
 import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.FeatureFlagsClassic;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.res.R;
 import com.android.systemui.shade.ShadeExpansionStateManager;
@@ -52,8 +56,15 @@ import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.disableflags.DisableFlagsLogger.DisableState;
 import com.android.systemui.statusbar.events.SystemStatusAnimationCallback;
 import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
+import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerViewBinder;
+import com.android.systemui.statusbar.notification.icon.ui.viewbinder.StatusBarNotificationIconViewStore;
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerStatusBarViewModel;
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerViewModel;
+import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.NotificationIconAreaController;
+import com.android.systemui.statusbar.phone.NotificationIconContainer;
 import com.android.systemui.statusbar.phone.PhoneStatusBarView;
+import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
 import com.android.systemui.statusbar.phone.StatusBarHideIconsForBouncerManager;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.phone.StatusBarIconController.DarkIconManager;
@@ -66,6 +77,7 @@ import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallListener;
 import com.android.systemui.statusbar.pipeline.shared.ui.binder.CollapsedStatusBarViewBinder;
 import com.android.systemui.statusbar.pipeline.shared.ui.binder.StatusBarVisibilityChangeListener;
 import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.CollapsedStatusBarViewModel;
+import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.window.StatusBarWindowStateController;
 import com.android.systemui.statusbar.window.StatusBarWindowStateListener;
@@ -83,6 +95,7 @@ import java.util.Set;
 import java.util.concurrent.Executor;
 
 import javax.inject.Inject;
+
 import kotlin.Unit;
 
 /**
@@ -128,7 +141,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
     private final OngoingCallController mOngoingCallController;
     private final SystemStatusAnimationScheduler mAnimationScheduler;
     private final StatusBarLocationPublisher mLocationPublisher;
-    private final FeatureFlags mFeatureFlags;
+    private final FeatureFlagsClassic mFeatureFlags;
     private final NotificationIconAreaController mNotificationIconAreaController;
     private final ShadeExpansionStateManager mShadeExpansionStateManager;
     private final StatusBarIconController mStatusBarIconController;
@@ -142,6 +155,13 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
     private final DumpManager mDumpManager;
     private final StatusBarWindowStateController mStatusBarWindowStateController;
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    private final NotificationIconContainerViewModel mStatusBarIconsViewModel;
+    private final ConfigurationState mConfigurationState;
+    private final ConfigurationController mConfigurationController;
+    private final DozeParameters mDozeParameters;
+    private final ScreenOffAnimationController mScreenOffAnimationController;
+    private final NotificationIconContainerViewBinder.IconViewStore mStatusBarIconViewStore;
+    private final DemoModeController mDemoModeController;
 
     private List<String> mBlockedIcons = new ArrayList<>();
     private Map<Startable, Startable.State> mStartableStates = new ArrayMap<>();
@@ -211,9 +231,9 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
             StatusBarLocationPublisher locationPublisher,
             NotificationIconAreaController notificationIconAreaController,
             ShadeExpansionStateManager shadeExpansionStateManager,
-            FeatureFlags featureFlags,
+            FeatureFlagsClassic featureFlags,
             StatusBarIconController statusBarIconController,
-            StatusBarIconController.DarkIconManager.Factory darkIconManagerFactory,
+            DarkIconManager.Factory darkIconManagerFactory,
             CollapsedStatusBarViewModel collapsedStatusBarViewModel,
             CollapsedStatusBarViewBinder collapsedStatusBarViewBinder,
             StatusBarHideIconsForBouncerManager statusBarHideIconsForBouncerManager,
@@ -228,8 +248,14 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
             @Main Executor mainExecutor,
             DumpManager dumpManager,
             StatusBarWindowStateController statusBarWindowStateController,
-            KeyguardUpdateMonitor keyguardUpdateMonitor
-    ) {
+            KeyguardUpdateMonitor keyguardUpdateMonitor,
+            NotificationIconContainerStatusBarViewModel statusBarIconsViewModel,
+            ConfigurationState configurationState,
+            ConfigurationController configurationController,
+            DozeParameters dozeParameters,
+            ScreenOffAnimationController screenOffAnimationController,
+            StatusBarNotificationIconViewStore statusBarIconViewStore,
+            DemoModeController demoModeController) {
         mStatusBarFragmentComponentFactory = statusBarFragmentComponentFactory;
         mOngoingCallController = ongoingCallController;
         mAnimationScheduler = animationScheduler;
@@ -254,18 +280,55 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
         mDumpManager = dumpManager;
         mStatusBarWindowStateController = statusBarWindowStateController;
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+        mStatusBarIconsViewModel = statusBarIconsViewModel;
+        mConfigurationState = configurationState;
+        mConfigurationController = configurationController;
+        mDozeParameters = dozeParameters;
+        mScreenOffAnimationController = screenOffAnimationController;
+        mStatusBarIconViewStore = statusBarIconViewStore;
+        mDemoModeController = demoModeController;
     }
 
+    private final DemoMode mDemoModeCallback = new DemoMode() {
+        @Override
+        public List<String> demoCommands() {
+            return List.of(DemoMode.COMMAND_NOTIFICATIONS);
+        }
+
+        @Override
+        public void dispatchDemoCommand(String command, Bundle args) {
+            if (mNotificationIconAreaInner == null) return;
+            String visible = args.getString("visible");
+            if ("false".equals(visible)) {
+                mNotificationIconAreaInner.setVisibility(View.INVISIBLE);
+            } else {
+                mNotificationIconAreaInner.setVisibility(View.VISIBLE);
+            }
+        }
+
+        @Override
+        public void onDemoModeFinished() {
+            if (mNotificationIconAreaInner == null) return;
+            mNotificationIconAreaInner.setVisibility(View.VISIBLE);
+        }
+    };
+
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         mStatusBarWindowStateController.addListener(mStatusBarWindowStateListener);
+        if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_ICON_CONTAINER_REFACTOR)) {
+            mDemoModeController.addCallback(mDemoModeCallback);
+        }
     }
 
     @Override
     public void onDestroy() {
         super.onDestroy();
         mStatusBarWindowStateController.removeListener(mStatusBarWindowStateListener);
+        if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_ICON_CONTAINER_REFACTOR)) {
+            mDemoModeController.removeCallback(mDemoModeCallback);
+        }
     }
 
     @Override
@@ -405,14 +468,31 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
 
     /** Initializes views related to the notification icon area. */
     public void initNotificationIconArea() {
-        ViewGroup notificationIconArea = mStatusBar.findViewById(R.id.notification_icon_area);
-        mNotificationIconAreaInner =
-                mNotificationIconAreaController.getNotificationInnerAreaView();
-        if (mNotificationIconAreaInner.getParent() != null) {
-            ((ViewGroup) mNotificationIconAreaInner.getParent())
-                    .removeView(mNotificationIconAreaInner);
-        }
-        notificationIconArea.addView(mNotificationIconAreaInner);
+        ViewGroup notificationIconArea = mStatusBar.requireViewById(R.id.notification_icon_area);
+        if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_ICON_CONTAINER_REFACTOR)) {
+            mNotificationIconAreaInner =
+                LayoutInflater.from(getContext())
+                        .inflate(R.layout.notification_icon_area, notificationIconArea, true);
+            NotificationIconContainer notificationIcons =
+                    notificationIconArea.requireViewById(R.id.notificationIcons);
+            NotificationIconContainerViewBinder.bind(
+                    notificationIcons,
+                    mStatusBarIconsViewModel,
+                    mConfigurationState,
+                    mConfigurationController,
+                    mDozeParameters,
+                    mFeatureFlags,
+                    mScreenOffAnimationController,
+                    mStatusBarIconViewStore);
+        } else {
+            mNotificationIconAreaInner =
+                    mNotificationIconAreaController.getNotificationInnerAreaView();
+            if (mNotificationIconAreaInner.getParent() != null) {
+                ((ViewGroup) mNotificationIconAreaInner.getParent())
+                        .removeView(mNotificationIconAreaInner);
+            }
+            notificationIconArea.addView(mNotificationIconAreaInner);
+        }
 
         updateNotificationIconAreaAndCallChip(/* animate= */ false);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationControllerExt.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationControllerExt.kt
index 25d67aff50a9cb5c5d4b0d8dbc2c132bd1a2c2d5..0a2bbe580b99d2365f73c756963b05e47d91024b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationControllerExt.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationControllerExt.kt
@@ -13,6 +13,7 @@
  */
 package com.android.systemui.statusbar.policy
 
+import android.content.res.Configuration
 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.Flow
@@ -50,3 +51,20 @@ val ConfigurationController.onThemeChanged: Flow<Unit>
         addCallback(listener)
         awaitClose { removeCallback(listener) }
     }
+
+/**
+ * A [Flow] that emits whenever the configuration has changed.
+ *
+ * @see ConfigurationController.ConfigurationListener.onConfigChanged
+ */
+val ConfigurationController.onConfigChanged: Flow<Configuration>
+    get() = conflatedCallbackFlow {
+        val listener =
+            object : ConfigurationController.ConfigurationListener {
+                override fun onConfigChanged(newConfig: Configuration) {
+                    trySend(newConfig)
+                }
+            }
+        addCallback(listener)
+        awaitClose { removeCallback(listener) }
+    }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
index 8929e024c00d18243f57c2e208cec3699bc9ae58..52133ee5b7cd41ac5893e48686d9d4045d079424 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
@@ -130,7 +130,7 @@ public interface KeyguardStateController extends CallbackController<Callback> {
     /**
      * If there are faces enrolled and user enabled face auth on keyguard.
      */
-    default boolean isFaceAuthEnabled() {
+    default boolean isFaceEnrolled() {
         return false;
     }
 
@@ -265,9 +265,9 @@ public interface KeyguardStateController extends CallbackController<Callback> {
 
         /**
          * Triggered when face auth becomes available or unavailable. Value should be queried with
-         * {@link KeyguardStateController#isFaceAuthEnabled()}.
+         * {@link KeyguardStateController#isFaceEnrolled()}.
          */
-        default void onFaceAuthEnabledChanged() {}
+        default void onFaceEnrolledChanged() {}
 
         /**
          * Triggered when the notification panel is starting or has finished
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 c62451813699f553dd901d226c8a79abd775b5c7..8cc7e7d21fc2392d5f17b26a5709f250a0ccf0dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -85,7 +85,7 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum
     private boolean mTrustManaged;
     private boolean mTrusted;
     private boolean mDebugUnlocked = false;
-    private boolean mFaceAuthEnabled;
+    private boolean mFaceEnrolled;
 
     private float mDismissAmount = 0f;
     private boolean mDismissingFromTouch = false;
@@ -216,7 +216,7 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum
 
     private void notifyKeyguardFaceAuthEnabledChanged() {
         // Copy the list to allow removal during callback.
-        new ArrayList<>(mCallbacks).forEach(Callback::onFaceAuthEnabledChanged);
+        new ArrayList<>(mCallbacks).forEach(Callback::onFaceEnrolledChanged);
     }
 
     private void notifyUnlockedChanged() {
@@ -260,16 +260,16 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum
                 || (Build.IS_DEBUGGABLE && DEBUG_AUTH_WITH_ADB && mDebugUnlocked);
         boolean trustManaged = mKeyguardUpdateMonitor.getUserTrustIsManaged(user);
         boolean trusted = mKeyguardUpdateMonitor.getUserHasTrust(user);
-        boolean faceAuthEnabled = mKeyguardUpdateMonitor.isFaceAuthEnabledForUser(user);
+        boolean faceEnrolled = mKeyguardUpdateMonitor.isFaceEnrolled(user);
         boolean changed = secure != mSecure || canDismissLockScreen != mCanDismissLockScreen
                 || trustManaged != mTrustManaged || mTrusted != trusted
-                || mFaceAuthEnabled != faceAuthEnabled;
+                || mFaceEnrolled != faceEnrolled;
         if (changed || updateAlways) {
             mSecure = secure;
             mCanDismissLockScreen = canDismissLockScreen;
             mTrusted = trusted;
             mTrustManaged = trustManaged;
-            mFaceAuthEnabled = faceAuthEnabled;
+            mFaceEnrolled = faceEnrolled;
             mLogger.logKeyguardStateUpdate(
                     mSecure, mCanDismissLockScreen, mTrusted, mTrustManaged);
             notifyUnlockedChanged();
@@ -290,8 +290,8 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum
     }
 
     @Override
-    public boolean isFaceAuthEnabled() {
-        return mFaceAuthEnabled;
+    public boolean isFaceEnrolled() {
+        return mFaceEnrolled;
     }
 
     @Override
@@ -416,7 +416,7 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum
         pw.println("  mTrustManaged: " + mTrustManaged);
         pw.println("  mTrusted: " + mTrusted);
         pw.println("  mDebugUnlocked: " + mDebugUnlocked);
-        pw.println("  mFaceAuthEnabled: " + mFaceAuthEnabled);
+        pw.println("  mFaceEnrolled: " + mFaceEnrolled);
         pw.println("  isKeyguardFadingAway: " + isKeyguardFadingAway());
         pw.println("  isKeyguardGoingAway: " + isKeyguardGoingAway());
         pw.println("  isLaunchTransitionFadingAway: " + isLaunchTransitionFadingAway());
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/CoroutinesModule.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/CoroutinesModule.kt
index 0a44bda702388a548f38cb2a70a3d554eda38b2a..f0c7be63b64cc7cbabf313d3d3cbc02b23f19282 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/CoroutinesModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/CoroutinesModule.kt
@@ -4,27 +4,74 @@ 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.dagger.qualifiers.Tracing
+import com.android.systemui.flags.FeatureFlagsClassic
+import com.android.systemui.flags.Flags
+import com.android.systemui.util.TraceUtils.Companion.coroutineTracingIsEnabled
+import com.android.systemui.util.tracing.TraceContextElement
 import dagger.Module
 import dagger.Provides
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import javax.inject.Qualifier
+import kotlin.coroutines.CoroutineContext
+import kotlin.coroutines.EmptyCoroutineContext
+
+/** Key associated with a [Boolean] flag that enables or disables the coroutine tracing feature. */
+@Qualifier
+annotation class CoroutineTracingEnabledKey
+
+/**
+ * Same as [@Application], but does not make use of flags. This should only be used when early usage
+ * of [@Application] would introduce a circular dependency on [FeatureFlagsClassic].
+ */
+@Qualifier
+@MustBeDocumented
+@Retention(AnnotationRetention.RUNTIME)
+annotation class UnflaggedApplication
+
+/**
+ * Same as [@Background], but does not make use of flags. This should only be used when early usage
+ * of [@Application] would introduce a circular dependency on [FeatureFlagsClassic].
+ */
+@Qualifier
+@MustBeDocumented
+@Retention(AnnotationRetention.RUNTIME)
+annotation class UnflaggedBackground
 
 /** Providers for various coroutines-related constructs. */
 @Module
-object CoroutinesModule {
+class CoroutinesModule {
     @Provides
     @SysUISingleton
     @Application
     fun applicationScope(
-        @Main dispatcher: CoroutineDispatcher,
-    ): CoroutineScope = CoroutineScope(dispatcher)
+            @Main dispatcherContext: CoroutineContext,
+    ): CoroutineScope = CoroutineScope(dispatcherContext)
+
+    @Provides
+    @SysUISingleton
+    @UnflaggedApplication
+    fun unflaggedApplicationScope(): CoroutineScope = CoroutineScope(Dispatchers.Main.immediate)
 
     @Provides
     @SysUISingleton
     @Main
+    @Deprecated(
+        "Use @Main CoroutineContext instead",
+        ReplaceWith("mainCoroutineContext()", "kotlin.coroutines.CoroutineContext")
+    )
     fun mainDispatcher(): CoroutineDispatcher = Dispatchers.Main.immediate
 
+    @Provides
+    @SysUISingleton
+    @Main
+    fun mainCoroutineContext(@Tracing tracingCoroutineContext: CoroutineContext): CoroutineContext {
+        return Dispatchers.Main.immediate + tracingCoroutineContext
+    }
+
     /**
      * Provide a [CoroutineDispatcher] backed by a thread pool containing at most X threads, where
      * X is the number of CPU cores available.
@@ -37,5 +84,42 @@ object CoroutinesModule {
     @Provides
     @SysUISingleton
     @Background
+    @Deprecated(
+        "Use @Background CoroutineContext instead",
+        ReplaceWith("bgCoroutineContext()", "kotlin.coroutines.CoroutineContext")
+    )
     fun bgDispatcher(): CoroutineDispatcher = Dispatchers.IO
+
+
+    @Provides
+    @Background
+    @SysUISingleton
+    fun bgCoroutineContext(@Tracing tracingCoroutineContext: CoroutineContext): CoroutineContext {
+        return Dispatchers.IO + tracingCoroutineContext
+    }
+
+    @Provides
+    @UnflaggedBackground
+    @SysUISingleton
+    fun unflaggedBackgroundCoroutineContext(): CoroutineContext {
+        return Dispatchers.IO
+    }
+
+    @OptIn(ExperimentalCoroutinesApi::class)
+    @Provides
+    @Tracing
+    @SysUISingleton
+    fun tracingCoroutineContext(
+        @CoroutineTracingEnabledKey enableTracing: Boolean
+    ): CoroutineContext = if (enableTracing) TraceContextElement() else EmptyCoroutineContext
+
+    companion object {
+        @[Provides CoroutineTracingEnabledKey]
+        fun provideIsCoroutineTracingEnabledKey(featureFlags: FeatureFlagsClassic): Boolean {
+            return if (featureFlags.isEnabled(Flags.COROUTINE_TRACING)) {
+                coroutineTracingIsEnabled = true
+                true
+            } else false
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt
index 31b90bae27eb116b563acb8d4c407038f2973f95..8fe57e116405a4adf4464179420f8c77c878ed08 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt
@@ -61,10 +61,10 @@ fun <T, R> Flow<T>.pairwiseBy(transform: suspend (old: T, new: T) -> R): Flow<R>
  *
  * Useful for code that needs to compare the current value to the previous value.
  */
-fun <T, R> Flow<T>.pairwiseBy(
-    initialValue: T,
-    transform: suspend (previousValue: T, newValue: T) -> R,
-): Flow<R> = onStart { emit(initialValue) }.pairwiseBy(transform)
+fun <S, T : S, R> Flow<T>.pairwiseBy(
+    initialValue: S,
+    transform: suspend (previousValue: S, newValue: T) -> R,
+): Flow<R> = pairwiseBy(getInitialValue = { initialValue }, transform)
 
 /**
  * Returns a new [Flow] that combines the two most recent emissions from [this] using [transform].
@@ -75,10 +75,16 @@ fun <T, R> Flow<T>.pairwiseBy(
  *
  * Useful for code that needs to compare the current value to the previous value.
  */
-fun <T, R> Flow<T>.pairwiseBy(
-    getInitialValue: suspend () -> T,
-    transform: suspend (previousValue: T, newValue: T) -> R,
-): Flow<R> = onStart { emit(getInitialValue()) }.pairwiseBy(transform)
+fun <S, T : S, R> Flow<T>.pairwiseBy(
+    getInitialValue: suspend () -> S,
+    transform: suspend (previousValue: S, newValue: T) -> R,
+): Flow<R> = flow {
+    var previousValue: S = getInitialValue()
+    collect { newVal ->
+        emit(transform(previousValue, newVal))
+        previousValue = newVal
+    }
+}
 
 /**
  * Returns a new [Flow] that produces the two most recent emissions from [this]. Note that the new
@@ -86,7 +92,7 @@ fun <T, R> Flow<T>.pairwiseBy(
  *
  * Useful for code that needs to compare the current value to the previous value.
  */
-fun <T> Flow<T>.pairwise(): Flow<WithPrev<T>> = pairwiseBy(::WithPrev)
+fun <T> Flow<T>.pairwise(): Flow<WithPrev<T, T>> = pairwiseBy(::WithPrev)
 
 /**
  * Returns a new [Flow] that produces the two most recent emissions from [this]. [initialValue] will
@@ -94,10 +100,11 @@ fun <T> Flow<T>.pairwise(): Flow<WithPrev<T>> = pairwiseBy(::WithPrev)
  *
  * Useful for code that needs to compare the current value to the previous value.
  */
-fun <T> Flow<T>.pairwise(initialValue: T): Flow<WithPrev<T>> = pairwiseBy(initialValue, ::WithPrev)
+fun <S, T : S> Flow<T>.pairwise(initialValue: S): Flow<WithPrev<S, T>> =
+    pairwiseBy(initialValue, ::WithPrev)
 
 /** Holds a [newValue] emitted from a [Flow], along with the [previousValue] emitted value. */
-data class WithPrev<T>(val previousValue: T, val newValue: T)
+data class WithPrev<out S, out T : S>(val previousValue: S, val newValue: T)
 
 /**
  * Returns a new [Flow] that combines the [Set] changes between each emission from [this] using
@@ -265,112 +272,120 @@ fun <T> Flow<T>.throttle(periodMs: Long, clock: SystemClock): Flow<T> = channelF
  * immediately invoke [getValue] to establish its initial value.
  */
 inline fun <T> CoroutineScope.stateFlow(
-    changedSignals: Flow<Unit>,
+    changedSignals: Flow<*>,
     crossinline getValue: () -> T,
 ): StateFlow<T> =
     changedSignals.map { getValue() }.stateIn(this, SharingStarted.Eagerly, getValue())
 
 inline fun <T1, T2, T3, T4, T5, T6, R> combine(
-        flow: Flow<T1>,
-        flow2: Flow<T2>,
-        flow3: Flow<T3>,
-        flow4: Flow<T4>,
-        flow5: Flow<T5>,
-        flow6: Flow<T6>,
-        crossinline transform: suspend (T1, T2, T3, T4, T5, T6) -> R
+    flow: Flow<T1>,
+    flow2: Flow<T2>,
+    flow3: Flow<T3>,
+    flow4: Flow<T4>,
+    flow5: Flow<T5>,
+    flow6: Flow<T6>,
+    crossinline transform: suspend (T1, T2, T3, T4, T5, T6) -> R
 ): Flow<R> {
-    return kotlinx.coroutines.flow.combine(flow, flow2, flow3, flow4, flow5, flow6) {
-        args: Array<*> ->
+    return kotlinx.coroutines.flow.combine(flow, flow2, flow3, flow4, flow5, flow6) { args: Array<*>
+        ->
         @Suppress("UNCHECKED_CAST")
         transform(
-                args[0] as T1,
-                args[1] as T2,
-                args[2] as T3,
-                args[3] as T4,
-                args[4] as T5,
-                args[5] as T6
+            args[0] as T1,
+            args[1] as T2,
+            args[2] as T3,
+            args[3] as T4,
+            args[4] as T5,
+            args[5] as T6
         )
     }
 }
 
 inline fun <T1, T2, T3, T4, T5, T6, T7, R> combine(
-        flow: Flow<T1>,
-        flow2: Flow<T2>,
-        flow3: Flow<T3>,
-        flow4: Flow<T4>,
-        flow5: Flow<T5>,
-        flow6: Flow<T6>,
-        flow7: Flow<T7>,
-        crossinline transform: suspend (T1, T2, T3, T4, T5, T6, T7) -> R
+    flow: Flow<T1>,
+    flow2: Flow<T2>,
+    flow3: Flow<T3>,
+    flow4: Flow<T4>,
+    flow5: Flow<T5>,
+    flow6: Flow<T6>,
+    flow7: Flow<T7>,
+    crossinline transform: suspend (T1, T2, T3, T4, T5, T6, T7) -> R
 ): Flow<R> {
     return kotlinx.coroutines.flow.combine(flow, flow2, flow3, flow4, flow5, flow6, flow7) {
         args: Array<*> ->
         @Suppress("UNCHECKED_CAST")
         transform(
-                args[0] as T1,
-                args[1] as T2,
-                args[2] as T3,
-                args[3] as T4,
-                args[4] as T5,
-                args[5] as T6,
-                args[6] as T7
+            args[0] as T1,
+            args[1] as T2,
+            args[2] as T3,
+            args[3] as T4,
+            args[4] as T5,
+            args[5] as T6,
+            args[6] as T7
         )
     }
 }
 
 inline fun <T1, T2, T3, T4, T5, T6, T7, T8, R> combine(
-        flow: Flow<T1>,
-        flow2: Flow<T2>,
-        flow3: Flow<T3>,
-        flow4: Flow<T4>,
-        flow5: Flow<T5>,
-        flow6: Flow<T6>,
-        flow7: Flow<T7>,
-        flow8: Flow<T8>,
-        crossinline transform: suspend (T1, T2, T3, T4, T5, T6, T7, T8) -> R
+    flow: Flow<T1>,
+    flow2: Flow<T2>,
+    flow3: Flow<T3>,
+    flow4: Flow<T4>,
+    flow5: Flow<T5>,
+    flow6: Flow<T6>,
+    flow7: Flow<T7>,
+    flow8: Flow<T8>,
+    crossinline transform: suspend (T1, T2, T3, T4, T5, T6, T7, T8) -> R
 ): Flow<R> {
     return kotlinx.coroutines.flow.combine(flow, flow2, flow3, flow4, flow5, flow6, flow7, flow8) {
         args: Array<*> ->
         @Suppress("UNCHECKED_CAST")
         transform(
-                args[0] as T1,
-                args[1] as T2,
-                args[2] as T3,
-                args[3] as T4,
-                args[4] as T5,
-                args[5] as T6,
-                args[6] as T7,
-                args[7] as T8
+            args[0] as T1,
+            args[1] as T2,
+            args[2] as T3,
+            args[3] as T4,
+            args[4] as T5,
+            args[5] as T6,
+            args[6] as T7,
+            args[7] as T8
         )
     }
 }
 
 inline fun <T1, T2, T3, T4, T5, T6, T7, T8, T9, R> combine(
-        flow: Flow<T1>,
-        flow2: Flow<T2>,
-        flow3: Flow<T3>,
-        flow4: Flow<T4>,
-        flow5: Flow<T5>,
-        flow6: Flow<T6>,
-        flow7: Flow<T7>,
-        flow8: Flow<T8>,
-        flow9: Flow<T9>,
-        crossinline transform: suspend (T1, T2, T3, T4, T5, T6, T7, T8, T9) -> R
+    flow: Flow<T1>,
+    flow2: Flow<T2>,
+    flow3: Flow<T3>,
+    flow4: Flow<T4>,
+    flow5: Flow<T5>,
+    flow6: Flow<T6>,
+    flow7: Flow<T7>,
+    flow8: Flow<T8>,
+    flow9: Flow<T9>,
+    crossinline transform: suspend (T1, T2, T3, T4, T5, T6, T7, T8, T9) -> R
 ): Flow<R> {
     return kotlinx.coroutines.flow.combine(
-        flow, flow2, flow3, flow4, flow5, flow6, flow7, flow8, flow9
+        flow,
+        flow2,
+        flow3,
+        flow4,
+        flow5,
+        flow6,
+        flow7,
+        flow8,
+        flow9
     ) { args: Array<*> ->
         @Suppress("UNCHECKED_CAST")
         transform(
-                args[0] as T1,
-                args[1] as T2,
-                args[2] as T3,
-                args[3] as T4,
-                args[4] as T5,
-                args[5] as T6,
-                args[6] as T7,
-                args[6] as T8,
-                args[6] as T9,
+            args[0] as T1,
+            args[1] as T2,
+            args[2] as T3,
+            args[3] as T4,
+            args[4] as T5,
+            args[5] as T6,
+            args[6] as T7,
+            args[6] as T8,
+            args[6] as T9,
         )
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/MapUtils.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/MapUtils.kt
new file mode 100644
index 0000000000000000000000000000000000000000..41cd95b780c9ed575df6602ca75413bd457bb59a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/MapUtils.kt
@@ -0,0 +1,32 @@
+/*
+ * 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.util.kotlin
+
+/** Like [mapValues], but discards `null` values returned from [block]. */
+fun <K, V, R> Map<K, V>.mapValuesNotNull(block: (Map.Entry<K, V>) -> R?): Map<K, R> = buildMap {
+    this@mapValuesNotNull.mapValuesNotNullTo(this, block)
+}
+
+/** Like [mapValuesTo], but discards `null` values returned from [block]. */
+fun <K, V, R, M : MutableMap<in K, in R>> Map<out K, V>.mapValuesNotNullTo(
+    destination: M,
+    block: (Map.Entry<K, V>) -> R?,
+): M {
+    for (entry in this) {
+        block(entry)?.also { destination.put(entry.key, it) }
+    }
+    return destination
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/ui/AnimatedValue.kt b/packages/SystemUI/src/com/android/systemui/util/ui/AnimatedValue.kt
index 51d2afabd7f9758c078cfc8c85a83aed4147f47a..1112d6f4f25c4df20ee135e116c38c8c0db311d4 100644
--- a/packages/SystemUI/src/com/android/systemui/util/ui/AnimatedValue.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/ui/AnimatedValue.kt
@@ -17,26 +17,58 @@
 
 package com.android.systemui.util.ui
 
+import com.android.systemui.util.ui.AnimatedValue.Animating
+import com.android.systemui.util.ui.AnimatedValue.NotAnimating
+import kotlinx.coroutines.CompletableDeferred
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.firstOrNull
-import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.transformLatest
 
 /**
  * A state comprised of a [value] of type [T] paired with a boolean indicating whether or not the
  * [value] [isAnimating] in the UI.
  */
-data class AnimatedValue<T>(
-    val value: T,
-    val isAnimating: Boolean,
-)
+sealed interface AnimatedValue<out T> {
+
+    /** A [state][value] that is not actively animating in the UI. */
+    data class NotAnimating<out T>(val value: T) : AnimatedValue<T>
+
+    /**
+     * A [state][value] that is actively animating in the UI. Invoking [onStopAnimating] will signal
+     * the source of the state to stop animating.
+     */
+    data class Animating<out T>(
+        val value: T,
+        val onStopAnimating: () -> Unit,
+    ) : AnimatedValue<T>
+}
+
+/** The state held in this [AnimatedValue]. */
+inline val <T> AnimatedValue<T>.value: T
+    get() =
+        when (this) {
+            is Animating -> value
+            is NotAnimating -> value
+        }
+
+/** Returns whether or not this [AnimatedValue] is animating or not. */
+inline val <T> AnimatedValue<T>.isAnimating: Boolean
+    get() = this is Animating<T>
+
+/**
+ * If this [AnimatedValue] [isAnimating], then signal that the animation should be stopped.
+ * Otherwise, do nothing.
+ */
+@Suppress("NOTHING_TO_INLINE")
+inline fun AnimatedValue<*>.stopAnimating() {
+    if (this is Animating) onStopAnimating()
+}
 
 /**
  * An event comprised of a [value] of type [T] paired with a [boolean][startAnimating] indicating
  * whether or not this event should start an animation.
  */
-data class AnimatableEvent<T>(
+data class AnimatableEvent<out T>(
     val value: T,
     val startAnimating: Boolean,
 )
@@ -47,16 +79,87 @@ data class AnimatableEvent<T>(
  * [AnimatableEvent.startAnimating] value is `true`. When [completionEvents] emits a value, the
  * [AnimatedValue.isAnimating] will flip to `false`.
  */
-fun <T> Flow<AnimatableEvent<T>>.toAnimatedValueFlow(
-    completionEvents: Flow<Any?>,
-): Flow<AnimatedValue<T>> = transformLatest { (value, startAnimating) ->
-    emit(AnimatedValue(value, isAnimating = startAnimating))
-    if (startAnimating) {
-        // Wait for a completion now that we've started animating
-        completionEvents
-            .map { Unit } // replace the event so that it's never `null`
-            .firstOrNull() // `null` indicates an empty flow
-            // emit the new state if the flow was not empty.
-            ?.run { emit(AnimatedValue(value, isAnimating = false)) }
+fun <T> Flow<AnimatableEvent<T>>.toAnimatedValueFlow(): Flow<AnimatedValue<T>> =
+    transformLatest { (value, startAnimating) ->
+        if (startAnimating) {
+            val onCompleted = CompletableDeferred<Unit>()
+            emit(Animating(value) { onCompleted.complete(Unit) })
+            // Wait for a completion now that we've started animating
+            onCompleted.await()
+        }
+        emit(NotAnimating(value))
+    }
+
+/**
+ * Zip two [AnimatedValue]s together into a single [AnimatedValue], using [block] to combine the
+ * [value]s of each.
+ *
+ * If either [AnimatedValue] [isAnimating], then the result is also animating. Invoking
+ * [stopAnimating] on the result is equivalent to invoking [stopAnimating] on each input.
+ */
+inline fun <A, B, Z> zip(
+    valueA: AnimatedValue<A>,
+    valueB: AnimatedValue<B>,
+    block: (A, B) -> Z,
+): AnimatedValue<Z> {
+    val zippedValue = block(valueA.value, valueB.value)
+    return when (valueA) {
+        is Animating ->
+            when (valueB) {
+                is Animating ->
+                    Animating(zippedValue) {
+                        valueA.onStopAnimating()
+                        valueB.onStopAnimating()
+                    }
+                is NotAnimating -> Animating(zippedValue, valueA.onStopAnimating)
+            }
+        is NotAnimating ->
+            when (valueB) {
+                is Animating -> Animating(zippedValue, valueB.onStopAnimating)
+                is NotAnimating -> NotAnimating(zippedValue)
+            }
     }
 }
+
+/**
+ * Flattens a nested [AnimatedValue], the result of which holds the [value] of the inner
+ * [AnimatedValue].
+ *
+ * If either the outer or inner [AnimatedValue] [isAnimating], then the flattened result is also
+ * animating. Invoking [stopAnimating] on the result is equivalent to invoking [stopAnimating] on
+ * both the outer and inner values.
+ */
+@Suppress("NOTHING_TO_INLINE")
+inline fun <T> AnimatedValue<AnimatedValue<T>>.flatten(): AnimatedValue<T> = flatMap { it }
+
+/**
+ * Returns an [AnimatedValue], the [value] of which is the result of the given [value] applied to
+ * [block].
+ */
+inline fun <A, B> AnimatedValue<A>.map(block: (A) -> B): AnimatedValue<B> =
+    when (this) {
+        is Animating -> Animating(block(value), ::stopAnimating)
+        is NotAnimating -> NotAnimating(block(value))
+    }
+
+/**
+ * Returns an [AnimatedValue] from the result of [block] being invoked on the [value] original
+ * [AnimatedValue].
+ *
+ * If either the input [AnimatedValue] or the result of [block] [isAnimating], then the flattened
+ * result is also animating. Invoking [stopAnimating] on the result is equivalent to invoking
+ * [stopAnimating] on both values.
+ */
+inline fun <A, B> AnimatedValue<A>.flatMap(block: (A) -> AnimatedValue<B>): AnimatedValue<B> =
+    when (this) {
+        is NotAnimating -> block(value)
+        is Animating ->
+            when (val inner = block(value)) {
+                is Animating ->
+                    Animating(inner.value) {
+                        onStopAnimating()
+                        inner.onStopAnimating()
+                    }
+                is NotAnimating -> Animating(inner.value, onStopAnimating)
+            }
+    }
diff --git a/packages/SystemUI/tests/src/com/android/TestMocksModule.kt b/packages/SystemUI/tests/src/com/android/TestMocksModule.kt
index ff1d5b2ea3bfc3f2004c7b8bd8bd78ed1b564a3c..f49ba646e0a1423ce8d82173e39456e484f1b060 100644
--- a/packages/SystemUI/tests/src/com/android/TestMocksModule.kt
+++ b/packages/SystemUI/tests/src/com/android/TestMocksModule.kt
@@ -43,6 +43,7 @@ import com.android.systemui.statusbar.NotificationMediaManager
 import com.android.systemui.statusbar.NotificationShadeDepthController
 import com.android.systemui.statusbar.SysuiStatusBarStateController
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
+import com.android.systemui.statusbar.notification.collection.NotifCollection
 import com.android.systemui.statusbar.notification.stack.AmbientState
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
 import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator
@@ -75,6 +76,7 @@ data class TestMocksModule(
     @get:Provides val keyguardSecurityModel: KeyguardSecurityModel = mock(),
     @get:Provides val keyguardUpdateMonitor: KeyguardUpdateMonitor = mock(),
     @get:Provides val mediaHierarchyManager: MediaHierarchyManager = mock(),
+    @get:Provides val notifCollection: NotifCollection = mock(),
     @get:Provides val notificationListener: NotificationListener = mock(),
     @get:Provides val notificationLockscreenUserManager: NotificationLockscreenUserManager = mock(),
     @get:Provides val notificationMediaManager: NotificationMediaManager = mock(),
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt
index b31f630a43175df3fe136d71d0a1cabf86e0d84e..e429446f66cfc9d94ad53f856da408a333c6a5c7 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt
@@ -262,7 +262,7 @@ class ActiveUnlockConfigTest : SysuiTestCase() {
         // GIVEN fingerprint and face are NOT enrolled
         activeUnlockConfig.keyguardUpdateMonitor = keyguardUpdateMonitor
         `when`(keyguardUpdateMonitor.isFaceEnrolled).thenReturn(false)
-        `when`(keyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(0)).thenReturn(false)
+        `when`(keyguardUpdateMonitor.isUnlockWithFingerprintPossible(0)).thenReturn(false)
 
         // WHEN unlock intent is allowed when NO biometrics are enrolled (0)
 
@@ -292,7 +292,7 @@ class ActiveUnlockConfigTest : SysuiTestCase() {
         // GIVEN fingerprint and face are both enrolled
         activeUnlockConfig.keyguardUpdateMonitor = keyguardUpdateMonitor
         `when`(keyguardUpdateMonitor.isFaceEnrolled).thenReturn(true)
-        `when`(keyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(0)).thenReturn(true)
+        `when`(keyguardUpdateMonitor.isUnlockWithFingerprintPossible(0)).thenReturn(true)
 
         // WHEN unlock intent is allowed when ONLY fingerprint is enrolled or NO biometircs
         // are enrolled
@@ -315,7 +315,7 @@ class ActiveUnlockConfigTest : SysuiTestCase() {
 
         // WHEN fingerprint ONLY enrolled
         `when`(keyguardUpdateMonitor.isFaceEnrolled).thenReturn(false)
-        `when`(keyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(0)).thenReturn(true)
+        `when`(keyguardUpdateMonitor.isUnlockWithFingerprintPossible(0)).thenReturn(true)
 
         // THEN active unlock triggers allowed on unlock intent
         assertTrue(
@@ -326,7 +326,7 @@ class ActiveUnlockConfigTest : SysuiTestCase() {
 
         // WHEN face ONLY enrolled
         `when`(keyguardUpdateMonitor.isFaceEnrolled).thenReturn(true)
-        `when`(keyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(0)).thenReturn(false)
+        `when`(keyguardUpdateMonitor.isUnlockWithFingerprintPossible(0)).thenReturn(false)
 
         // THEN active unlock triggers allowed on unlock intent
         assertTrue(
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index aabdcb7fa6600a7b1ad2c851cd4e5fdc5dbc43ff..efb08876b4f30956d47c10dcba3471a0b74cc912 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -414,6 +414,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
     }
 
     private void setupFingerprintAuth(boolean isClass3) throws RemoteException {
+        when(mAuthController.isFingerprintEnrolled(anyInt())).thenReturn(true);
         when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
         when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
         mFingerprintSensorProperties = List.of(
@@ -2898,18 +2899,22 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
 
     @Test
     public void testFaceSensorProperties() throws RemoteException {
+        // GIVEN no face sensor properties
+        when(mAuthController.isFaceAuthEnrolled(anyInt())).thenReturn(true);
         mFaceAuthenticatorsRegisteredCallback.onAllAuthenticatorsRegistered(new ArrayList<>());
 
-        assertThat(mKeyguardUpdateMonitor.isFaceAuthEnabledForUser(
+        // THEN face is not possible
+        assertThat(mKeyguardUpdateMonitor.isUnlockWithFacePossible(
                 mSelectedUserInteractor.getSelectedUserId())).isFalse();
 
+        // WHEN there are face sensor properties
         mFaceAuthenticatorsRegisteredCallback.onAllAuthenticatorsRegistered(mFaceSensorProperties);
-        biometricsEnabledForCurrentUser();
 
+        // THEN face is possible but face does NOT start listening immediately
+        assertThat(mKeyguardUpdateMonitor.isUnlockWithFacePossible(
+                mSelectedUserInteractor.getSelectedUserId())).isTrue();
         verifyFaceAuthenticateNeverCalled();
         verifyFaceDetectNeverCalled();
-        assertThat(mKeyguardUpdateMonitor.isFaceAuthEnabledForUser(
-                mSelectedUserInteractor.getSelectedUserId())).isTrue();
     }
 
     @Test
@@ -3167,10 +3172,6 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
     }
 
     private void mockCanBypassLockscreen(boolean canBypass) {
-        // force update the isFaceEnrolled cache:
-        mKeyguardUpdateMonitor.isFaceAuthEnabledForUser(
-                mSelectedUserInteractor.getSelectedUserId());
-
         mKeyguardUpdateMonitor.setKeyguardBypassController(mKeyguardBypassController);
         when(mKeyguardBypassController.canBypass()).thenReturn(canBypass);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
index 22ebd995b472f1add3c083e214258d93f5d47ea5..f15164e3fdcca7ad66edf027a9e1f09d77470da6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
@@ -24,6 +24,7 @@ import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
 import android.animation.ValueAnimator;
@@ -33,8 +34,8 @@ import android.content.Context;
 import android.graphics.Rect;
 import android.os.Handler;
 import android.os.RemoteException;
-import android.os.SystemClock;
 import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
 import android.view.SurfaceControl;
 import android.view.View;
 import android.view.WindowManager;
@@ -46,13 +47,15 @@ import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.LargeTest;
 
 import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
-import com.android.systemui.res.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.animation.AnimatorTestRule;
 import com.android.systemui.model.SysUiState;
+import com.android.systemui.res.R;
 import com.android.systemui.util.settings.SecureSettings;
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Answers;
@@ -61,22 +64,18 @@ import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
 
 @LargeTest
 @RunWith(AndroidTestingRunner.class)
+@RunWithLooper(setAsMainLooper = true)
 public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
 
+    @Rule
+    public final AnimatorTestRule mAnimatorTestRule = new AnimatorTestRule();
     private static final float DEFAULT_SCALE = 4.0f;
     private static final float DEFAULT_CENTER_X = 400.0f;
     private static final float DEFAULT_CENTER_Y = 500.0f;
-    // The duration and period couldn't too short, otherwise the ValueAnimator and
-    //    Instrumentation.runOnMainSync won't work in expectation. (b/288926821)
-    private static final long ANIMATION_DURATION_MS = 600;
-    private static final long WAIT_FULL_ANIMATION_PERIOD = 1000;
-    private static final long WAIT_INTERMEDIATE_ANIMATION_PERIOD = 250;
 
     private AtomicReference<Float> mCurrentScale = new AtomicReference<>((float) 0);
     private AtomicReference<Float> mCurrentCenterX = new AtomicReference<>((float) 0);
@@ -105,10 +104,11 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
     private WindowMagnificationController mSpyController;
     private WindowMagnificationAnimationController mWindowMagnificationAnimationController;
     private Instrumentation mInstrumentation;
-    private long mWaitingAnimationPeriod;
-    private long mWaitIntermediateAnimationPeriod;
+    private long mWaitAnimationDuration;
+    private long mWaitPartialAnimationDuration;
 
     private TestableWindowManager mWindowManager;
+    private ValueAnimator mValueAnimator;
 
     @Before
     public void setUp() throws Exception {
@@ -118,10 +118,14 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
         mWindowManager = spy(new TestableWindowManager(wm));
         mContext.addMockSystemService(Context.WINDOW_SERVICE, mWindowManager);
 
-        mWaitingAnimationPeriod = WAIT_FULL_ANIMATION_PERIOD;
-        mWaitIntermediateAnimationPeriod = WAIT_INTERMEDIATE_ANIMATION_PERIOD;
+        // Using the animation duration in WindowMagnificationAnimationController for testing.
+        mWaitAnimationDuration = mContext.getResources()
+                .getInteger(com.android.internal.R.integer.config_longAnimTime);
+        mWaitPartialAnimationDuration = mWaitAnimationDuration / 2;
+
+        mValueAnimator = newValueAnimator();
         mWindowMagnificationAnimationController = new WindowMagnificationAnimationController(
-                mContext, newValueAnimator());
+                mContext, mValueAnimator);
         mController = new SpyWindowMagnificationController(mContext, mHandler,
                 mWindowMagnificationAnimationController,
                 mSfVsyncFrameProvider, null, new SurfaceControl.Transaction(),
@@ -131,13 +135,13 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
 
     @After
     public void tearDown() throws Exception {
-        mInstrumentation.runOnMainSync(() -> mController.deleteWindowMagnification());
+        mController.deleteWindowMagnification();
     }
 
     @Test
     public void enableWindowMagnification_disabled_expectedValuesAndInvokeCallback()
             throws RemoteException {
-        enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, mAnimationCallback);
+        enableWindowMagnificationAndWaitAnimating(mWaitAnimationDuration, mAnimationCallback);
 
         verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
                 mScaleCaptor.capture(),
@@ -161,16 +165,13 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
 
     @Test
     public void enableWindowMagnificationWithoutCallback_enabled_expectedValues() {
-        enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, mAnimationCallback);
+        enableWindowMagnificationAndWaitAnimating(mWaitAnimationDuration, mAnimationCallback);
         final float targetScale = DEFAULT_SCALE + 1.0f;
         final float targetCenterX = DEFAULT_CENTER_X + 100;
         final float targetCenterY = DEFAULT_CENTER_Y + 100;
 
-        mInstrumentation.runOnMainSync(
-                () -> {
-                    mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
-                            targetCenterX, targetCenterY, null);
-                });
+        mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
+                targetCenterX, targetCenterY, null);
 
         verifyFinalSpec(targetScale, targetCenterX, targetCenterY);
     }
@@ -178,12 +179,8 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
     @Test
     public void enableWindowMagnificationWithScaleOne_disabled_NoAnimationAndInvokeCallback()
             throws RemoteException {
-        mInstrumentation.runOnMainSync(
-                () -> {
-                    mWindowMagnificationAnimationController.enableWindowMagnification(1,
-                            DEFAULT_CENTER_X, DEFAULT_CENTER_Y, mAnimationCallback);
-                });
-        SystemClock.sleep(mWaitingAnimationPeriod);
+        mWindowMagnificationAnimationController.enableWindowMagnification(1,
+                DEFAULT_CENTER_X, DEFAULT_CENTER_Y, mAnimationCallback);
 
         verify(mSpyController).enableWindowMagnificationInternal(1, DEFAULT_CENTER_X,
                 DEFAULT_CENTER_Y, 0f, 0f);
@@ -193,22 +190,19 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
     @Test
     public void enableWindowMagnification_enabling_expectedValuesAndInvokeCallback()
             throws RemoteException {
-        enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
+        enableWindowMagnificationAndWaitAnimating(mWaitPartialAnimationDuration,
                 mAnimationCallback);
         final float targetScale = DEFAULT_SCALE + 1.0f;
         final float targetCenterX = DEFAULT_CENTER_X + 100;
         final float targetCenterY = DEFAULT_CENTER_Y + 100;
 
-        mInstrumentation.runOnMainSync(() -> {
-            Mockito.reset(mSpyController);
-            mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
-                    targetCenterX, targetCenterY, mAnimationCallback2);
-            mCurrentScale.set(mController.getScale());
-            mCurrentCenterX.set(mController.getCenterX());
-            mCurrentCenterY.set(mController.getCenterY());
-        });
-
-        SystemClock.sleep(mWaitingAnimationPeriod);
+        Mockito.reset(mSpyController);
+        mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
+                targetCenterX, targetCenterY, mAnimationCallback2);
+        mCurrentScale.set(mController.getScale());
+        mCurrentCenterX.set(mController.getCenterX());
+        mCurrentCenterY.set(mController.getCenterY());
+        advanceTimeBy(mWaitAnimationDuration);
 
         verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
                 mScaleCaptor.capture(),
@@ -226,24 +220,18 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
 
     @Test
     public void enableWindowMagnificationWithUnchanged_enabling_expectedValuesToDefault()
-            throws InterruptedException {
-        final CountDownLatch countDownLatch = new CountDownLatch(2);
-        final MockMagnificationAnimationCallback animationCallback =
-                new MockMagnificationAnimationCallback(countDownLatch);
-
-        enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
-                animationCallback);
-        mInstrumentation.runOnMainSync(
-                () -> {
-                    mWindowMagnificationAnimationController.enableWindowMagnification(Float.NaN,
-                            Float.NaN, Float.NaN, animationCallback);
-                });
-
-        assertTrue(countDownLatch.await(mWaitingAnimationPeriod, TimeUnit.MILLISECONDS));
+            throws RemoteException {
+        enableWindowMagnificationAndWaitAnimating(mWaitPartialAnimationDuration,
+                mAnimationCallback);
+
+        mWindowMagnificationAnimationController.enableWindowMagnification(Float.NaN,
+                Float.NaN, Float.NaN, mAnimationCallback2);
+        advanceTimeBy(mWaitAnimationDuration);
+
         // The callback in 2nd enableWindowMagnification will return true
-        assertEquals(1, animationCallback.getSuccessCount());
+        verify(mAnimationCallback2).onResult(true);
         // The callback in 1st enableWindowMagnification will return false
-        assertEquals(1, animationCallback.getFailedCount());
+        verify(mAnimationCallback).onResult(false);
         verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X, DEFAULT_CENTER_Y);
     }
 
@@ -256,16 +244,13 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
         final float targetCenterX = DEFAULT_CENTER_X + 100;
         final float targetCenterY = DEFAULT_CENTER_Y + 100;
 
-        mInstrumentation.runOnMainSync(() -> {
-            Mockito.reset(mSpyController);
-            mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
-                    targetCenterX, targetCenterY, mAnimationCallback);
-            mCurrentScale.set(mController.getScale());
-            mCurrentCenterX.set(mController.getCenterX());
-            mCurrentCenterY.set(mController.getCenterY());
-        });
-
-        SystemClock.sleep(mWaitingAnimationPeriod);
+        Mockito.reset(mSpyController);
+        mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
+                targetCenterX, targetCenterY, mAnimationCallback);
+        mCurrentScale.set(mController.getScale());
+        mCurrentCenterX.set(mController.getCenterX());
+        mCurrentCenterY.set(mController.getCenterY());
+        advanceTimeBy(mWaitAnimationDuration);
 
         verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
                 mScaleCaptor.capture(),
@@ -293,16 +278,13 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
         final float targetCenterX = DEFAULT_CENTER_X + 100;
         final float targetCenterY = DEFAULT_CENTER_Y + 100;
 
-        mInstrumentation.runOnMainSync(() -> {
-            Mockito.reset(mSpyController);
-            mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
-                    targetCenterX, targetCenterY, mAnimationCallback);
-            mCurrentScale.set(mController.getScale());
-            mCurrentCenterX.set(mController.getCenterX());
-            mCurrentCenterY.set(mController.getCenterY());
-        });
-
-        SystemClock.sleep(mWaitingAnimationPeriod);
+        Mockito.reset(mSpyController);
+        mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
+                targetCenterX, targetCenterY, mAnimationCallback);
+        mCurrentScale.set(mController.getScale());
+        mCurrentCenterX.set(mController.getCenterX());
+        mCurrentCenterY.set(mController.getCenterY());
+        advanceTimeBy(mWaitAnimationDuration);
 
         verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
                 mScaleCaptor.capture(),
@@ -331,11 +313,9 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
         final float targetCenterX = DEFAULT_CENTER_X + 100;
         final float targetCenterY = DEFAULT_CENTER_Y + 100;
 
-        mInstrumentation.runOnMainSync(() -> {
-            Mockito.reset(mSpyController);
-            mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
-                    targetCenterX, targetCenterY, null);
-        });
+        Mockito.reset(mSpyController);
+        mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
+                targetCenterX, targetCenterY, null);
 
         verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
         assertEquals(WindowMagnificationAnimationController.STATE_DISABLED,
@@ -346,17 +326,16 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
     public void
             enableMagnificationWithoutCallback_enabling_expectedValuesAndInvokeFormerCallback()
             throws RemoteException {
-        enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
+        enableWindowMagnificationAndWaitAnimating(mWaitPartialAnimationDuration,
                 mAnimationCallback);
         final float targetScale = DEFAULT_SCALE - 1.0f;
         final float targetCenterX = DEFAULT_CENTER_X + 100;
         final float targetCenterY = DEFAULT_CENTER_Y + 100;
 
-        mInstrumentation.runOnMainSync(() -> {
-            Mockito.reset(mSpyController);
-            mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
-                    targetCenterX, targetCenterY, null);
-        });
+        Mockito.reset(mSpyController);
+        mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
+                targetCenterX, targetCenterY, null);
+
         verifyFinalSpec(targetScale, targetCenterX, targetCenterY);
         verify(mAnimationCallback).onResult(false);
     }
@@ -364,15 +343,13 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
     @Test
     public void enableWindowMagnificationWithSameSpec_enabling_NoAnimationAndInvokeCallback()
             throws RemoteException {
-        enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
+        enableWindowMagnificationAndWaitAnimating(mWaitPartialAnimationDuration,
                 mAnimationCallback);
 
-        mInstrumentation.runOnMainSync(() -> {
-            Mockito.reset(mSpyController);
-            mWindowMagnificationAnimationController.enableWindowMagnification(Float.NaN,
-                    Float.NaN, Float.NaN, mAnimationCallback2);
-        });
-        SystemClock.sleep(mWaitingAnimationPeriod);
+        Mockito.reset(mSpyController);
+        mWindowMagnificationAnimationController.enableWindowMagnification(Float.NaN,
+                Float.NaN, Float.NaN, mAnimationCallback2);
+        advanceTimeBy(mWaitAnimationDuration);
 
         verify(mSpyController, never()).enableWindowMagnificationInternal(anyFloat(), anyFloat(),
                 anyFloat());
@@ -383,28 +360,30 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
     @Test
     public void enableWindowMagnification_disabling_expectedValuesAndInvokeCallback()
             throws RemoteException {
-        enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, null);
-        deleteWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
+        enableWindowMagnificationWithoutAnimation();
+        deleteWindowMagnificationAndWaitAnimating(mWaitPartialAnimationDuration,
                 mAnimationCallback);
         final float targetScale = DEFAULT_SCALE + 1.0f;
         final float targetCenterX = DEFAULT_CENTER_X + 100;
         final float targetCenterY = DEFAULT_CENTER_Y + 100;
 
-        mInstrumentation.runOnMainSync(
-                () -> {
-                    Mockito.reset(mSpyController);
-                    mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
-                            targetCenterX, targetCenterY, mAnimationCallback2);
-                    mCurrentScale.set(mController.getScale());
-                    mCurrentCenterX.set(mController.getCenterX());
-                    mCurrentCenterY.set(mController.getCenterY());
-                });
+        Mockito.reset(mSpyController);
+        mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
+                targetCenterX, targetCenterY, mAnimationCallback2);
+        mCurrentScale.set(mController.getScale());
+        mCurrentCenterX.set(mController.getCenterX());
+        mCurrentCenterY.set(mController.getCenterY());
+
         // Current spec shouldn't match given spec.
         verify(mAnimationCallback2, never()).onResult(anyBoolean());
         verify(mAnimationCallback).onResult(false);
-        SystemClock.sleep(mWaitingAnimationPeriod);
+        // ValueAnimator.reverse() could not work correctly with the AnimatorTestRule since it is
+        // using SystemClock in reverse() (b/305731398). Therefore, we call end() on the animator
+        // directly to verify the result of animation is correct instead of querying the animation
+        // frame at a specific timing.
+        mValueAnimator.end();
 
-        verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
+        verify(mSpyController).enableWindowMagnificationInternal(
                 mScaleCaptor.capture(),
                 mCenterXCaptor.capture(), mCenterYCaptor.capture(),
                 mOffsetXCaptor.capture(), mOffsetYCaptor.capture());
@@ -424,18 +403,15 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
             enableMagnificationWithoutCallback_disabling_expectedValuesAndInvokeFormerCallback()
             throws RemoteException {
         enableWindowMagnificationWithoutAnimation();
-        deleteWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
+        deleteWindowMagnificationAndWaitAnimating(mWaitPartialAnimationDuration,
                 mAnimationCallback);
         final float targetScale = DEFAULT_SCALE + 1.0f;
         final float targetCenterX = DEFAULT_CENTER_X + 100;
         final float targetCenterY = DEFAULT_CENTER_Y + 100;
 
-        mInstrumentation.runOnMainSync(
-                () -> {
-                    Mockito.reset(mSpyController);
-                    mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
-                            targetCenterX, targetCenterY, null);
-                });
+        Mockito.reset(mSpyController);
+        mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
+                targetCenterX, targetCenterY, null);
 
         verify(mAnimationCallback).onResult(false);
         verifyFinalSpec(targetScale, targetCenterX, targetCenterY);
@@ -444,16 +420,14 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
     @Test
     public void enableWindowMagnificationWithSameSpec_disabling_NoAnimationAndInvokeCallback()
             throws RemoteException {
-        enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, null);
-        deleteWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
+        enableWindowMagnificationWithoutAnimation();
+        deleteWindowMagnificationAndWaitAnimating(mWaitPartialAnimationDuration,
                 mAnimationCallback);
 
-        mInstrumentation.runOnMainSync(() -> {
-            Mockito.reset(mSpyController);
-            mWindowMagnificationAnimationController.enableWindowMagnification(Float.NaN,
-                    Float.NaN, Float.NaN, mAnimationCallback2);
-        });
-        SystemClock.sleep(mWaitingAnimationPeriod);
+        Mockito.reset(mSpyController);
+        mWindowMagnificationAnimationController.enableWindowMagnification(Float.NaN,
+                Float.NaN, Float.NaN, mAnimationCallback2);
+        advanceTimeBy(mWaitAnimationDuration);
 
         verify(mSpyController, never()).enableWindowMagnificationInternal(anyFloat(), anyFloat(),
                 anyFloat());
@@ -470,16 +444,13 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
         final float targetCenterX = DEFAULT_CENTER_X + 100;
         final float targetCenterY = DEFAULT_CENTER_Y + 100;
 
-        mInstrumentation.runOnMainSync(() -> {
-            Mockito.reset(mSpyController);
-            mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
-                    targetCenterX, targetCenterY, mAnimationCallback2);
-            mCurrentScale.set(mController.getScale());
-            mCurrentCenterX.set(mController.getCenterX());
-            mCurrentCenterY.set(mController.getCenterY());
-        });
-
-        SystemClock.sleep(mWaitingAnimationPeriod);
+        Mockito.reset(mSpyController);
+        mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
+                targetCenterX, targetCenterY, mAnimationCallback2);
+        mCurrentScale.set(mController.getScale());
+        mCurrentCenterX.set(mController.getCenterX());
+        mCurrentCenterY.set(mController.getCenterY());
+        advanceTimeBy(mWaitAnimationDuration);
 
         verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
                 mScaleCaptor.capture(),
@@ -498,129 +469,110 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
     public void enableWindowMagnificationWithOffset_expectedValues() {
         final float offsetRatio = -0.1f;
         final Rect windowBounds = new Rect(mWindowManager.getCurrentWindowMetrics().getBounds());
-        mInstrumentation.runOnMainSync(() -> {
-            Mockito.reset(mSpyController);
-            mWindowMagnificationAnimationController.enableWindowMagnification(DEFAULT_SCALE,
-                    windowBounds.exactCenterX(), windowBounds.exactCenterY(),
-                    offsetRatio, offsetRatio, mAnimationCallback);
-        });
-        SystemClock.sleep(mWaitingAnimationPeriod);
-        final View attachedView = mWindowManager.getAttachedView();
-        assertNotNull(attachedView);
-        final Rect mirrorViewBound = new Rect();
-        final View mirrorView = attachedView.findViewById(R.id.surface_view);
-        assertNotNull(mirrorView);
-        mirrorView.getBoundsOnScreen(mirrorViewBound);
-
-        assertEquals((int) (offsetRatio * mirrorViewBound.width() / 2),
-                (int) (mirrorViewBound.exactCenterX() - windowBounds.exactCenterX()));
-        assertEquals((int) (offsetRatio * mirrorViewBound.height() / 2),
-                (int) (mirrorViewBound.exactCenterY() - windowBounds.exactCenterY()));
-
-    }
-
-    @Test
-    public void moveWindowMagnifierToPosition_enabled_expectedValues()
-            throws InterruptedException {
-        final CountDownLatch countDownLatch = new CountDownLatch(1);
-        final MockMagnificationAnimationCallback animationCallback =
-                new MockMagnificationAnimationCallback(countDownLatch);
+
+        Mockito.reset(mSpyController);
+        mWindowMagnificationAnimationController.enableWindowMagnification(DEFAULT_SCALE,
+                windowBounds.exactCenterX(), windowBounds.exactCenterY(),
+                offsetRatio, offsetRatio, mAnimationCallback);
+        advanceTimeBy(mWaitAnimationDuration);
+
+        // We delay the time of verifying to wait for the measurement and layout of the view
+        mHandler.postDelayed(() -> {
+            final View attachedView = mWindowManager.getAttachedView();
+            assertNotNull(attachedView);
+            final Rect mirrorViewBound = new Rect();
+            final View mirrorView = attachedView.findViewById(R.id.surface_view);
+            assertNotNull(mirrorView);
+            mirrorView.getBoundsOnScreen(mirrorViewBound);
+
+            assertEquals((int) (offsetRatio * mirrorViewBound.width() / 2),
+                    (int) (mirrorViewBound.exactCenterX() - windowBounds.exactCenterX()));
+            assertEquals((int) (offsetRatio * mirrorViewBound.height() / 2),
+                    (int) (mirrorViewBound.exactCenterY() - windowBounds.exactCenterY()));
+        }, 100);
+    }
+
+    @Test
+    public void moveWindowMagnifierToPosition_enabled_expectedValues() throws RemoteException {
         final float targetCenterX = DEFAULT_CENTER_X + 100;
         final float targetCenterY = DEFAULT_CENTER_Y + 100;
         enableWindowMagnificationWithoutAnimation();
 
-        mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
-                    targetCenterX, targetCenterY, animationCallback);
-        });
+        mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
+                targetCenterX, targetCenterY, mAnimationCallback);
+        advanceTimeBy(mWaitAnimationDuration);
 
-        assertTrue(countDownLatch.await(mWaitingAnimationPeriod, TimeUnit.MILLISECONDS));
-        assertEquals(1, animationCallback.getSuccessCount());
-        assertEquals(0, animationCallback.getFailedCount());
+        verify(mAnimationCallback).onResult(true);
+        verify(mAnimationCallback, never()).onResult(false);
         verifyFinalSpec(DEFAULT_SCALE, targetCenterX, targetCenterY);
     }
 
     @Test
     public void moveWindowMagnifierToPositionMultipleTimes_enabled_expectedValuesToLastOne()
-            throws InterruptedException {
-        final CountDownLatch countDownLatch = new CountDownLatch(4);
-        final MockMagnificationAnimationCallback animationCallback =
-                new MockMagnificationAnimationCallback(countDownLatch);
+            throws RemoteException {
         enableWindowMagnificationWithoutAnimation();
 
-        mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
-                    DEFAULT_CENTER_X + 10, DEFAULT_CENTER_Y + 10, animationCallback);
-            mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
-                    DEFAULT_CENTER_X + 20, DEFAULT_CENTER_Y + 20, animationCallback);
-            mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
-                    DEFAULT_CENTER_X + 30, DEFAULT_CENTER_Y + 30, animationCallback);
-            mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
-                    DEFAULT_CENTER_X + 40, DEFAULT_CENTER_Y + 40, animationCallback);
-        });
-
-        assertTrue(countDownLatch.await(mWaitingAnimationPeriod, TimeUnit.MILLISECONDS));
+        mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
+                DEFAULT_CENTER_X + 10, DEFAULT_CENTER_Y + 10, mAnimationCallback);
+        mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
+                DEFAULT_CENTER_X + 20, DEFAULT_CENTER_Y + 20, mAnimationCallback);
+        mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
+                DEFAULT_CENTER_X + 30, DEFAULT_CENTER_Y + 30, mAnimationCallback);
+        mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
+                DEFAULT_CENTER_X + 40, DEFAULT_CENTER_Y + 40, mAnimationCallback2);
+        advanceTimeBy(mWaitAnimationDuration);
+
         // only the last one callback will return true
-        assertEquals(1, animationCallback.getSuccessCount());
+        verify(mAnimationCallback2).onResult(true);
         // the others will return false
-        assertEquals(3, animationCallback.getFailedCount());
+        verify(mAnimationCallback, times(3)).onResult(false);
         verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X + 40, DEFAULT_CENTER_Y + 40);
     }
 
     @Test
     public void moveWindowMagnifierToPosition_enabling_expectedValuesToLastOne()
-            throws InterruptedException {
-        final CountDownLatch countDownLatch = new CountDownLatch(2);
-        final MockMagnificationAnimationCallback animationCallback =
-                new MockMagnificationAnimationCallback(countDownLatch);
+            throws RemoteException {
         final float targetCenterX = DEFAULT_CENTER_X + 100;
         final float targetCenterY = DEFAULT_CENTER_Y + 100;
 
-        enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
-                animationCallback);
-        mInstrumentation.runOnMainSync(
-                () -> {
-                    mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
-                            targetCenterX, targetCenterY, animationCallback);
-                });
+        enableWindowMagnificationAndWaitAnimating(mWaitPartialAnimationDuration,
+                mAnimationCallback);
+
+        mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
+                targetCenterX, targetCenterY, mAnimationCallback2);
+        advanceTimeBy(mWaitAnimationDuration);
 
-        assertTrue(countDownLatch.await(mWaitingAnimationPeriod, TimeUnit.MILLISECONDS));
         // The callback in moveWindowMagnifierToPosition will return true
-        assertEquals(1, animationCallback.getSuccessCount());
+        verify(mAnimationCallback2).onResult(true);
         // The callback in enableWindowMagnification will return false
-        assertEquals(1, animationCallback.getFailedCount());
+        verify(mAnimationCallback).onResult(false);
         verifyFinalSpec(DEFAULT_SCALE, targetCenterX, targetCenterY);
     }
 
     @Test
     public void moveWindowMagnifierToPositionWithCenterUnchanged_enabling_expectedValuesToDefault()
-            throws InterruptedException {
-        final CountDownLatch countDownLatch = new CountDownLatch(2);
-        final MockMagnificationAnimationCallback animationCallback =
-                new MockMagnificationAnimationCallback(countDownLatch);
-
-        enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
-                animationCallback);
-        mInstrumentation.runOnMainSync(
-                () -> {
-                    mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
-                            Float.NaN, Float.NaN, animationCallback);
-                });
-
-        assertTrue(countDownLatch.await(mWaitingAnimationPeriod, TimeUnit.MILLISECONDS));
+            throws RemoteException {
+
+        enableWindowMagnificationAndWaitAnimating(mWaitPartialAnimationDuration,
+                mAnimationCallback);
+
+        mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
+                Float.NaN, Float.NaN, mAnimationCallback2);
+        advanceTimeBy(mWaitAnimationDuration);
+
         // The callback in moveWindowMagnifierToPosition will return true
-        assertEquals(1, animationCallback.getSuccessCount());
+        verify(mAnimationCallback2).onResult(true);
         // The callback in enableWindowMagnification will return false
-        assertEquals(1, animationCallback.getFailedCount());
+        verify(mAnimationCallback).onResult(false);
         verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X, DEFAULT_CENTER_Y);
     }
 
     @Test
     public void enableWindowMagnificationWithSameScale_enabled_doNothingButInvokeCallback()
             throws RemoteException {
-        enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, null);
+        enableWindowMagnificationWithoutAnimation();
 
-        enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, mAnimationCallback);
+        enableWindowMagnificationAndWaitAnimating(mWaitAnimationDuration, mAnimationCallback);
 
         verify(mSpyController, never()).enableWindowMagnificationInternal(anyFloat(), anyFloat(),
                 anyFloat());
@@ -632,7 +584,7 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
             throws RemoteException {
         enableWindowMagnificationWithoutAnimation();
 
-        deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, mAnimationCallback);
+        deleteWindowMagnificationAndWaitAnimating(mWaitAnimationDuration, mAnimationCallback);
 
         verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
                 mScaleCaptor.capture(),
@@ -659,7 +611,7 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
     @Test
     public void deleteWindowMagnification_disabled_doNothingAndInvokeCallback()
             throws RemoteException {
-        deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, mAnimationCallback);
+        deleteWindowMagnificationAndWaitAnimating(mWaitAnimationDuration, mAnimationCallback);
 
         Mockito.verifyNoMoreInteractions(mSpyController);
         verify(mAnimationCallback).onResult(true);
@@ -668,20 +620,23 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
     @Test
     public void deleteWindowMagnification_enabling_expectedValuesAndInvokeCallback()
             throws RemoteException {
-        enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
+
+        enableWindowMagnificationAndWaitAnimating(mWaitPartialAnimationDuration,
                 mAnimationCallback);
 
-        mInstrumentation.runOnMainSync(
-                () -> {
-                    Mockito.reset(mSpyController);
-                    mWindowMagnificationAnimationController.deleteWindowMagnification(
-                            mAnimationCallback2);
-                    mCurrentScale.set(mController.getScale());
-                    mCurrentCenterX.set(mController.getCenterX());
-                    mCurrentCenterY.set(mController.getCenterY());
-                });
-        SystemClock.sleep(mWaitingAnimationPeriod);
-        verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
+        Mockito.reset(mSpyController);
+        mWindowMagnificationAnimationController.deleteWindowMagnification(
+                mAnimationCallback2);
+        mCurrentScale.set(mController.getScale());
+        mCurrentCenterX.set(mController.getCenterX());
+        mCurrentCenterY.set(mController.getCenterY());
+        // ValueAnimator.reverse() could not work correctly with the AnimatorTestRule since it is
+        // using SystemClock in reverse() (b/305731398). Therefore, we call end() on the animator
+        // directly to verify the result of animation is correct instead of querying the animation
+        // frame at a specific timing.
+        mValueAnimator.end();
+
+        verify(mSpyController).enableWindowMagnificationInternal(
                 mScaleCaptor.capture(),
                 mCenterXCaptor.capture(), mCenterYCaptor.capture(),
                 mOffsetXCaptor.capture(), mOffsetYCaptor.capture());
@@ -702,14 +657,11 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
     @Test
     public void deleteWindowMagnificationWithoutCallback_enabling_expectedValuesAndInvokeCallback()
             throws RemoteException {
-        enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
+        enableWindowMagnificationAndWaitAnimating(mWaitPartialAnimationDuration,
                 mAnimationCallback);
 
-        mInstrumentation.runOnMainSync(
-                () -> {
-                    Mockito.reset(mSpyController);
-                    mWindowMagnificationAnimationController.deleteWindowMagnification(null);
-                });
+        Mockito.reset(mSpyController);
+        mWindowMagnificationAnimationController.deleteWindowMagnification(null);
 
         verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
         verify(mAnimationCallback).onResult(false);
@@ -717,13 +669,13 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
 
     @Test
     public void deleteWindowMagnification_disabling_checkStartAndValues() throws RemoteException {
-        enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, null);
-        deleteWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
+        enableWindowMagnificationWithoutAnimation();
+        deleteWindowMagnificationAndWaitAnimating(mWaitPartialAnimationDuration,
                 mAnimationCallback);
 
-        deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, mAnimationCallback2);
+        deleteWindowMagnificationAndWaitAnimating(mWaitAnimationDuration, mAnimationCallback2);
 
-        verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
+        verify(mSpyController).enableWindowMagnificationInternal(
                 mScaleCaptor.capture(),
                 mCenterXCaptor.capture(), mCenterYCaptor.capture(),
                 mOffsetXCaptor.capture(), mOffsetYCaptor.capture());
@@ -738,8 +690,8 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
     @Test
     public void deleteWindowMagnificationWithoutCallback_disabling_checkStartAndValues()
             throws RemoteException {
-        enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, null);
-        deleteWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
+        enableWindowMagnificationWithoutAnimation();
+        deleteWindowMagnificationAndWaitAnimating(mWaitPartialAnimationDuration,
                 mAnimationCallback);
 
         deleteWindowMagnificationAndWaitAnimating(0, null);
@@ -757,9 +709,9 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
         final float offsetX = 50.0f;
         final float offsetY =
                 (float) Math.ceil(offsetX * WindowMagnificationController.HORIZONTAL_LOCK_BASE)
-                + 1.0f;
-        mInstrumentation.runOnMainSync(
-                () -> mController.moveWindowMagnifier(offsetX, offsetY));
+                        + 1.0f;
+
+        mController.moveWindowMagnifier(offsetX, offsetY);
 
         verify(mSpyController).moveWindowMagnifier(offsetX, offsetY);
         verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X, DEFAULT_CENTER_Y + offsetY);
@@ -774,8 +726,8 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
         final float offsetY =
                 (float) Math.floor(offsetX * WindowMagnificationController.HORIZONTAL_LOCK_BASE)
                         - 1.0f;
-        mInstrumentation.runOnMainSync(
-                () -> mController.moveWindowMagnifier(offsetX, offsetY));
+
+        mController.moveWindowMagnifier(offsetX, offsetY);
 
         verify(mSpyController).moveWindowMagnifier(offsetX, offsetY);
         verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X + offsetX, DEFAULT_CENTER_Y);
@@ -790,11 +742,8 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
                 (float) Math.ceil(offsetX * WindowMagnificationController.HORIZONTAL_LOCK_BASE);
         // while diagonal scrolling enabled,
         //  should move with both offsetX and offsetY without regrading offsetY/offsetX
-        mInstrumentation.runOnMainSync(
-                () -> {
-                    mController.setDiagonalScrolling(true);
-                    mController.moveWindowMagnifier(offsetX, offsetY);
-                });
+        mController.setDiagonalScrolling(true);
+        mController.moveWindowMagnifier(offsetX, offsetY);
 
         verify(mSpyController).moveWindowMagnifier(offsetX, offsetY);
         verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X + offsetX, DEFAULT_CENTER_Y + offsetY);
@@ -806,14 +755,17 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
         final float targetCenterY = DEFAULT_CENTER_Y + 100;
         enableWindowMagnificationWithoutAnimation();
 
-        mInstrumentation.runOnMainSync(
-                () -> mController.moveWindowMagnifierToPosition(targetCenterX, targetCenterY,
-                        mAnimationCallback));
-        SystemClock.sleep(mWaitingAnimationPeriod);
+        mController.moveWindowMagnifierToPosition(targetCenterX, targetCenterY,
+                mAnimationCallback);
+        advanceTimeBy(mWaitAnimationDuration);
 
         verifyFinalSpec(DEFAULT_SCALE, targetCenterX, targetCenterY);
     }
 
+    private void advanceTimeBy(long timeDelta) {
+        mAnimatorTestRule.advanceTimeBy(timeDelta);
+    }
+
     private void verifyFinalSpec(float expectedScale, float expectedCenterX,
             float expectedCenterY) {
         assertEquals(expectedScale, mController.getScale(), 0f);
@@ -822,33 +774,24 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
     }
 
     private void enableWindowMagnificationWithoutAnimation() {
-        mInstrumentation.runOnMainSync(
-                () -> {
-                    Mockito.reset(mSpyController);
-                    mWindowMagnificationAnimationController.enableWindowMagnification(DEFAULT_SCALE,
-                            DEFAULT_CENTER_X, DEFAULT_CENTER_Y, null);
-                });
+        Mockito.reset(mSpyController);
+        mWindowMagnificationAnimationController.enableWindowMagnification(DEFAULT_SCALE,
+                DEFAULT_CENTER_X, DEFAULT_CENTER_Y, null);
     }
 
     private void enableWindowMagnificationAndWaitAnimating(long duration,
             @Nullable IRemoteMagnificationAnimationCallback callback) {
-        mInstrumentation.runOnMainSync(
-                () -> {
-                    Mockito.reset(mSpyController);
-                    mWindowMagnificationAnimationController.enableWindowMagnification(DEFAULT_SCALE,
-                            DEFAULT_CENTER_X, DEFAULT_CENTER_Y, callback);
-                });
-        SystemClock.sleep(duration);
+        Mockito.reset(mSpyController);
+        mWindowMagnificationAnimationController.enableWindowMagnification(DEFAULT_SCALE,
+                DEFAULT_CENTER_X, DEFAULT_CENTER_Y, callback);
+        advanceTimeBy(duration);
     }
 
     private void deleteWindowMagnificationAndWaitAnimating(long duration,
             @Nullable IRemoteMagnificationAnimationCallback callback) {
-        mInstrumentation.runOnMainSync(
-                () -> {
-                    resetMockObjects();
-                    mWindowMagnificationAnimationController.deleteWindowMagnification(callback);
-                });
-        SystemClock.sleep(duration);
+        resetMockObjects();
+        mWindowMagnificationAnimationController.deleteWindowMagnification(callback);
+        advanceTimeBy(duration);
     }
 
     private void verifyStartValue(ArgumentCaptor<Float> captor, float startValue) {
@@ -937,9 +880,9 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
         }
     }
 
-    private static ValueAnimator newValueAnimator() {
+    private ValueAnimator newValueAnimator() {
         final ValueAnimator valueAnimator = new ValueAnimator();
-        valueAnimator.setDuration(ANIMATION_DURATION_MS);
+        valueAnimator.setDuration(mWaitAnimationDuration);
         valueAnimator.setInterpolator(new AccelerateInterpolator(2.5f));
         valueAnimator.setFloatValues(0.0f, 1.0f);
         return valueAnimator;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt
index f6b284fffa3dd7c9742c9e0475a5cdba29d0f33c..d6aa9ac87d396429db0460fa8b9bd02189e55b41 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt
@@ -423,7 +423,7 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() {
         mainHandler.setMode(FakeHandler.Mode.QUEUEING)
 
         // GIVEN bouncer should be delayed due to face auth
-        whenever(keyguardStateController.isFaceAuthEnabled).thenReturn(true)
+        whenever(keyguardStateController.isFaceEnrolled).thenReturn(true)
         whenever(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(BiometricSourceType.FACE))
             .thenReturn(true)
         whenever(keyguardUpdateMonitor.doesCurrentPostureAllowFaceAuth()).thenReturn(true)
@@ -449,7 +449,7 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() {
 
         // GIVEN bouncer should not be delayed because device isn't in the right posture for
         // face auth
-        whenever(keyguardStateController.isFaceAuthEnabled).thenReturn(true)
+        whenever(keyguardStateController.isFaceEnrolled).thenReturn(true)
         whenever(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(BiometricSourceType.FACE))
             .thenReturn(true)
         whenever(keyguardUpdateMonitor.doesCurrentPostureAllowFaceAuth()).thenReturn(false)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
index 819d08a2086e9f65efdf46bdd8f089a3cca63510..9bb2434f84ac3c92921098509ce4c26ee31c51c0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
@@ -43,7 +43,6 @@ import com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_ALTERNATE_BIOMET
 import com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_NOTIFICATION_PANEL_CLICKED
 import com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER
 import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.systemui.res.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository
 import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository
@@ -82,6 +81,7 @@ import com.android.systemui.power.domain.interactor.PowerInteractor
 import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest
 import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest
 import com.android.systemui.power.domain.interactor.PowerInteractorFactory
+import com.android.systemui.res.R
 import com.android.systemui.statusbar.phone.FakeKeyguardStateController
 import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.user.data.model.SelectionStatus
@@ -94,6 +94,8 @@ import com.android.systemui.util.mockito.whenever
 import com.android.systemui.util.time.FakeSystemClock
 import com.android.systemui.util.time.SystemClock
 import com.google.common.truth.Truth.assertThat
+import java.io.PrintWriter
+import java.io.StringWriter
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.StandardTestDispatcher
 import kotlinx.coroutines.test.TestDispatcher
@@ -116,8 +118,6 @@ import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.verifyNoMoreInteractions
 import org.mockito.MockitoAnnotations
-import java.io.PrintWriter
-import java.io.StringWriter
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
@@ -195,9 +195,11 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
             }
 
         powerRepository = FakePowerRepository()
-        powerInteractor = PowerInteractorFactory.create(
-                repository = powerRepository,
-        ).powerInteractor
+        powerInteractor =
+            PowerInteractorFactory.create(
+                    repository = powerRepository,
+                )
+                .powerInteractor
 
         val withDeps =
             KeyguardInteractorFactory.create(
@@ -210,10 +212,10 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
 
         keyguardTransitionRepository = FakeKeyguardTransitionRepository()
         keyguardTransitionInteractor =
-                KeyguardTransitionInteractorFactory.create(
-                        scope = testScope.backgroundScope,
-                        repository = keyguardTransitionRepository,
-                        keyguardInteractor = keyguardInteractor,
+            KeyguardTransitionInteractorFactory.create(
+                    scope = testScope.backgroundScope,
+                    repository = keyguardTransitionRepository,
+                    keyguardInteractor = keyguardInteractor,
                 )
                 .keyguardTransitionInteractor
 
@@ -635,11 +637,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
 
     @Test
     fun authenticateDoesNotRunWhenDeviceIsGoingToSleep() =
-        testScope.runTest {
-            testGatingCheckForFaceAuth {
-                powerInteractor.setAsleepForTest()
-            }
-        }
+        testScope.runTest { testGatingCheckForFaceAuth { powerInteractor.setAsleepForTest() } }
 
     @Test
     fun authenticateDoesNotRunWhenSecureCameraIsActive() =
@@ -736,17 +734,21 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
             allPreconditionsToRunFaceAuthAreTrue()
 
             Log.i("TEST", "started waking")
-            keyguardTransitionRepository.sendTransitionStep(TransitionStep(
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
                     from = KeyguardState.LOCKSCREEN,
                     to = KeyguardState.OFF,
                     transitionState = TransitionState.FINISHED,
-            ))
+                )
+            )
             runCurrent()
-            keyguardTransitionRepository.sendTransitionStep(TransitionStep(
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
                     from = KeyguardState.OFF,
                     to = KeyguardState.LOCKSCREEN,
                     transitionState = TransitionState.STARTED,
-            ))
+                )
+            )
             runCurrent()
 
             Log.i("TEST", "sending display off")
@@ -766,11 +768,13 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
         testScope.runTest {
             testGatingCheckForFaceAuth {
                 powerInteractor.onFinishedWakingUp()
-                keyguardTransitionRepository.sendTransitionStep(TransitionStep(
+                keyguardTransitionRepository.sendTransitionStep(
+                    TransitionStep(
                         from = KeyguardState.OFF,
                         to = KeyguardState.LOCKSCREEN,
                         transitionState = TransitionState.FINISHED,
-                ))
+                    )
+                )
                 runCurrent()
 
                 displayRepository.emit(
@@ -919,11 +923,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
 
     @Test
     fun detectDoesNotRunWhenDeviceSleepingStartingToSleep() =
-        testScope.runTest {
-            testGatingCheckForDetect {
-                powerInteractor.setAsleepForTest()
-            }
-        }
+        testScope.runTest { testGatingCheckForDetect { powerInteractor.setAsleepForTest() } }
 
     @Test
     fun detectDoesNotRunWhenSecureCameraIsActive() =
@@ -1114,6 +1114,32 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
             biometricSettingsRepository.setIsFaceAuthCurrentlyAllowed(true)
             faceAuthenticateIsCalled()
         }
+    @Test
+    fun authFailedCallAfterAuthLockedOutErrorShouldBeIgnored() =
+        testScope.runTest {
+            initCollectors()
+            allPreconditionsToRunFaceAuthAreTrue()
+            runCurrent()
+            assertThat(canFaceAuthRun()).isTrue()
+
+            underTest.requestAuthenticate(FACE_AUTH_TRIGGERED_NOTIFICATION_PANEL_CLICKED, false)
+            runCurrent()
+
+            faceAuthenticateIsCalled()
+            authenticationCallback.value.onAuthenticationError(
+                FACE_ERROR_LOCKOUT_PERMANENT,
+                "Too many attempts, face not available"
+            )
+
+            val lockoutError = authStatus() as ErrorFaceAuthenticationStatus
+            assertThat(lockedOut()).isTrue()
+            assertThat(lockoutError.isLockoutError()).isTrue()
+
+            authenticationCallback.value.onAuthenticationFailed()
+            runCurrent()
+
+            assertThat(authStatus()).isEqualTo(lockoutError)
+        }
 
     private suspend fun TestScope.testGatingCheckForFaceAuth(
         gatingCheckModifier: suspend () -> Unit
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 43cf1b5ecc403a2ba23be6241cf834467229f2c3..ae47a7bfa63d2f72720c38e18837a67af4e7f4b2 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
@@ -37,7 +37,6 @@ import android.testing.TestableLooper
 import android.view.IWindowManager
 import android.view.View
 import com.android.internal.logging.MetricsLogger
-import com.android.systemui.res.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.ActivityLaunchAnimator
 import com.android.systemui.animation.view.LaunchableFrameLayout
@@ -48,6 +47,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.qs.QSHost
 import com.android.systemui.qs.QsEventLogger
 import com.android.systemui.qs.logging.QSLogger
+import com.android.systemui.res.R
 import com.android.systemui.settings.FakeDisplayTracker
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.eq
@@ -343,8 +343,7 @@ class CustomTileTest : SysuiTestCase() {
         testableLooper.processAllMessages()
 
         verify(activityStarter, never())
-            .startPendingIntentDismissingKeyguard(
-                any(), any(), any(ActivityLaunchAnimator.Controller::class.java))
+            .startPendingIntentMaybeDismissingKeyguard(any(), nullable(), nullable())
     }
 
     @Test
@@ -357,8 +356,7 @@ class CustomTileTest : SysuiTestCase() {
         testableLooper.processAllMessages()
 
         verify(activityStarter, never())
-            .startPendingIntentDismissingKeyguard(
-                any(), any(), any(ActivityLaunchAnimator.Controller::class.java))
+            .startPendingIntentMaybeDismissingKeyguard(any(), nullable(), nullable())
     }
 
     @Test
@@ -373,7 +371,7 @@ class CustomTileTest : SysuiTestCase() {
         testableLooper.processAllMessages()
 
         verify(activityStarter)
-            .startPendingIntentDismissingKeyguard(
+            .startPendingIntentMaybeDismissingKeyguard(
                 eq(pi), nullable(), nullable<ActivityLaunchAnimator.Controller>())
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
index e1345d28dbd0e4206519df738345b4f51e1a0764..c1f2d0cc518f5c57c6bd88983cdcf402b64dd5d2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
@@ -22,11 +22,11 @@ import android.os.PowerManager
 import android.view.Display
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.systemui.Flags as AconfigFlags
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.authentication.domain.model.AuthenticationMethodModel
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.flags.Flags
 import com.android.systemui.model.SysUiState
 import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest
 import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest
@@ -45,7 +45,7 @@ import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
-import org.junit.Assume.assumeTrue
+import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mockito.clearInvocations
@@ -87,6 +87,11 @@ class SceneContainerStartableTest : SysuiTestCase() {
             powerInteractor = powerInteractor,
         )
 
+    @Before
+    fun setUp() {
+        mSetFlagsRule.enableFlags(AconfigFlags.FLAG_SCENE_CONTAINER)
+    }
+
     @Test
     fun hydrateVisibility() =
         testScope.runTest {
@@ -520,7 +525,6 @@ class SceneContainerStartableTest : SysuiTestCase() {
         authenticationMethod: AuthenticationMethodModel? = null,
         startsAwake: Boolean = true,
     ): MutableStateFlow<ObservableTransitionState> {
-        assumeTrue(Flags.SCENE_CONTAINER_ENABLED)
         sceneContainerFlags.enabled = true
         utils.deviceEntryRepository.setUnlocked(isDeviceUnlocked)
         utils.deviceEntryRepository.setBypassEnabled(isBypassEnabled)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagsTest.kt
index f6195aa9c3f77c1dea4bb099159695169251c3c8..0bed4d0d376a353026c940af71624cf83b5a1e57 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagsTest.kt
@@ -16,7 +16,10 @@
 
 package com.android.systemui.scene.shared.flag
 
+import android.platform.test.flag.junit.SetFlagsRule
 import androidx.test.filters.SmallTest
+import com.android.systemui.FakeFeatureFlagsImpl
+import com.android.systemui.Flags as AconfigFlags
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.flags.FakeFeatureFlagsClassic
 import com.android.systemui.flags.Flags
@@ -24,8 +27,8 @@ import com.android.systemui.flags.ReleasedFlag
 import com.android.systemui.flags.ResourceBooleanFlag
 import com.android.systemui.flags.UnreleasedFlag
 import com.google.common.truth.Truth.assertThat
-import org.junit.Assume.assumeTrue
 import org.junit.Before
+import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
@@ -36,27 +39,50 @@ internal class SceneContainerFlagsTest(
     private val testCase: TestCase,
 ) : SysuiTestCase() {
 
+    @Rule @JvmField val setFlagsRule: SetFlagsRule = SetFlagsRule()
+
     private lateinit var underTest: SceneContainerFlags
 
     @Before
     fun setUp() {
+        // TODO(b/283300105): remove this reflection setting once the hard-coded
+        //  Flags.SCENE_CONTAINER_ENABLED is no longer needed.
+        val field = Flags::class.java.getField("SCENE_CONTAINER_ENABLED")
+        field.isAccessible = true
+        field.set(null, true)
+
         val featureFlags =
             FakeFeatureFlagsClassic().apply {
-                SceneContainerFlagsImpl.flags.forEach { flag ->
-                    when (flag) {
-                        is ResourceBooleanFlag -> set(flag, testCase.areAllFlagsSet)
-                        is ReleasedFlag -> set(flag, testCase.areAllFlagsSet)
-                        is UnreleasedFlag -> set(flag, testCase.areAllFlagsSet)
-                        else -> error("Unsupported flag type ${flag.javaClass}")
+                SceneContainerFlagsImpl.classicFlagTokens.forEach { flagToken ->
+                    when (flagToken) {
+                        is ResourceBooleanFlag -> set(flagToken, testCase.areAllFlagsSet)
+                        is ReleasedFlag -> set(flagToken, testCase.areAllFlagsSet)
+                        is UnreleasedFlag -> set(flagToken, testCase.areAllFlagsSet)
+                        else -> error("Unsupported flag type ${flagToken.javaClass}")
                     }
                 }
             }
-        underTest = SceneContainerFlagsImpl(featureFlags, testCase.isComposeAvailable)
+        // TODO(b/306421592): get the aconfig FeatureFlags from the SetFlagsRule.
+        val aconfigFlags = FakeFeatureFlagsImpl()
+
+        listOf(
+                AconfigFlags.FLAG_SCENE_CONTAINER,
+            )
+            .forEach { flagToken ->
+                setFlagsRule.enableFlags(flagToken)
+                aconfigFlags.setFlag(flagToken, testCase.areAllFlagsSet)
+            }
+
+        underTest =
+            SceneContainerFlagsImpl(
+                featureFlagsClassic = featureFlags,
+                featureFlags = aconfigFlags,
+                isComposeAvailable = testCase.isComposeAvailable,
+            )
     }
 
     @Test
     fun isEnabled() {
-        assumeTrue(Flags.SCENE_CONTAINER_ENABLED)
         assertThat(underTest.isEnabled()).isEqualTo(testCase.expectedEnabled)
     }
 
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 b421e1b454773e5c82e2cea122d06d8c769858fb..4e3e165c83bb6e392b6769edaddaad294d202038 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -79,7 +79,8 @@ import com.android.systemui.statusbar.NotificationInsetsController
 import com.android.systemui.statusbar.NotificationShadeDepthController
 import com.android.systemui.statusbar.NotificationShadeWindowController
 import com.android.systemui.statusbar.SysuiStatusBarStateController
-import com.android.systemui.statusbar.notification.data.repository.NotificationExpansionRepository
+import com.android.systemui.statusbar.notification.data.repository.NotificationLaunchAnimationRepository
+import com.android.systemui.statusbar.notification.domain.interactor.NotificationLaunchAnimationInteractor
 import com.android.systemui.statusbar.notification.stack.AmbientState
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
 import com.android.systemui.statusbar.phone.CentralSurfaces
@@ -163,7 +164,9 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
     @Mock lateinit var sysUIKeyEventHandler: SysUIKeyEventHandler
     @Mock lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor
     @Mock lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
-    private val notificationExpansionRepository = NotificationExpansionRepository()
+    private val notificationLaunchAnimationRepository = NotificationLaunchAnimationRepository()
+    private val notificationLaunchAnimationInteractor =
+            NotificationLaunchAnimationInteractor(notificationLaunchAnimationRepository)
 
     private lateinit var fakeClock: FakeSystemClock
     private lateinit var interactionEventHandlerCaptor: ArgumentCaptor<InteractionEventHandler>
@@ -234,7 +237,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
                 primaryBouncerToGoneTransitionViewModel,
                 mCommunalViewModel,
                 mCommunalRepository,
-                notificationExpansionRepository,
+                notificationLaunchAnimationInteractor,
                 featureFlagsClassic,
                 fakeClock,
                 BouncerMessageInteractor(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
index 9c571015f750da7b6f96896309b762e488605f84..3d5d26ab194e8023a88dab039eeff114c915b2de 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
@@ -69,7 +69,8 @@ import com.android.systemui.statusbar.NotificationInsetsController
 import com.android.systemui.statusbar.NotificationShadeDepthController
 import com.android.systemui.statusbar.NotificationShadeWindowController
 import com.android.systemui.statusbar.SysuiStatusBarStateController
-import com.android.systemui.statusbar.notification.data.repository.NotificationExpansionRepository
+import com.android.systemui.statusbar.notification.data.repository.NotificationLaunchAnimationRepository
+import com.android.systemui.statusbar.notification.domain.interactor.NotificationLaunchAnimationInteractor
 import com.android.systemui.statusbar.notification.stack.AmbientState
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
@@ -226,7 +227,7 @@ class NotificationShadeWindowViewTest : SysuiTestCase() {
                 primaryBouncerToGoneTransitionViewModel,
                 mCommunalViewModel,
                 mCommunalRepository,
-                NotificationExpansionRepository(),
+                NotificationLaunchAnimationInteractor(NotificationLaunchAnimationRepository()),
                 featureFlags,
                 FakeSystemClock(),
                 BouncerMessageInteractor(
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 2bcad1d27b62eee9b571ca809a6aa707ed04b0d7..dd3ac927ebdf7ea98e300742ac77249847ce76e4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -73,10 +73,10 @@ import androidx.test.filters.SmallTest;
 
 import com.android.keyguard.TrustGrantFlags;
 import com.android.settingslib.fuelgauge.BatteryStatus;
-import com.android.systemui.res.R;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.keyguard.KeyguardIndication;
 import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController;
+import com.android.systemui.res.R;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -1543,7 +1543,7 @@ public class KeyguardIndicationControllerTest extends KeyguardIndicationControll
 
     private void setupFingerprintUnlockPossible(boolean possible) {
         when(mKeyguardUpdateMonitor
-                .getCachedIsUnlockWithFingerprintPossible(getCurrentUser()))
+                .isUnlockWithFingerprintPossible(getCurrentUser()))
                 .thenReturn(possible);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
index 34126798e87e98aad3f5379cdc7cc8a778d0a24a..2b3fd34cedbf6d0b411deec2588fa4845257dde4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
@@ -37,8 +37,12 @@ import android.testing.AndroidTestingRunner;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.flags.FakeFeatureFlagsClassic;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.plugins.PluginManager;
 import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
+import com.android.systemui.statusbar.data.repository.NotificationListenerSettingsRepository;
+import com.android.systemui.statusbar.domain.interactor.SilentNotificationStatusIconsVisibilityInteractor;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.time.FakeSystemClock;
 
@@ -68,9 +72,14 @@ public class NotificationListenerTest extends SysuiTestCase {
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
+        FakeFeatureFlagsClassic featureFlags = new FakeFeatureFlagsClassic();
+        featureFlags.setDefault(Flags.NOTIFICATION_ICON_CONTAINER_REFACTOR);
         mListener = new NotificationListener(
                 mContext,
+                featureFlags,
                 mNotificationManager,
+                new SilentNotificationStatusIconsVisibilityInteractor(
+                        new NotificationListenerSettingsRepository()),
                 mFakeSystemClock,
                 mFakeExecutor,
                 mPluginManager);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt
index 235ac5c2e9cc33ca065d4dbb789926e9e0463a84..605936372e7acbe0874a4aad2aabf3c2888da7f9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt
@@ -11,7 +11,8 @@ import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.res.R
 import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
-import com.android.systemui.statusbar.notification.data.repository.NotificationExpansionRepository
+import com.android.systemui.statusbar.notification.data.repository.NotificationLaunchAnimationRepository
+import com.android.systemui.statusbar.notification.domain.interactor.NotificationLaunchAnimationInteractor
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer
@@ -44,7 +45,8 @@ class NotificationLaunchAnimatorControllerTest : SysuiTestCase() {
     private lateinit var notificationTestHelper: NotificationTestHelper
     private lateinit var notification: ExpandableNotificationRow
     private lateinit var controller: NotificationLaunchAnimatorController
-    private val notificationExpansionRepository = NotificationExpansionRepository()
+    private val notificationLaunchAnimationInteractor =
+        NotificationLaunchAnimationInteractor(NotificationLaunchAnimationRepository())
 
     private val testScope = TestScope()
 
@@ -57,16 +59,17 @@ class NotificationLaunchAnimatorControllerTest : SysuiTestCase() {
     fun setUp() {
         allowTestableLooperAsMainThread()
         notificationTestHelper =
-                NotificationTestHelper(mContext, mDependency, TestableLooper.get(this))
+            NotificationTestHelper(mContext, mDependency, TestableLooper.get(this))
         notification = notificationTestHelper.createRow()
-        controller = NotificationLaunchAnimatorController(
-                notificationExpansionRepository,
+        controller =
+            NotificationLaunchAnimatorController(
+                notificationLaunchAnimationInteractor,
                 notificationListContainer,
                 headsUpManager,
                 notification,
                 jankMonitor,
                 onFinishAnimationCallback
-        )
+            )
     }
 
     private fun flagNotificationAsHun() {
@@ -80,13 +83,14 @@ class NotificationLaunchAnimatorControllerTest : SysuiTestCase() {
 
         assertTrue(HeadsUpUtil.isClickedHeadsUpNotification(notification))
         assertFalse(notification.entry.isExpandAnimationRunning)
-        val isExpandAnimationRunning by testScope.collectLastValue(
-            notificationExpansionRepository.isExpandAnimationRunning
-        )
+        val isExpandAnimationRunning by
+            testScope.collectLastValue(
+                notificationLaunchAnimationInteractor.isLaunchAnimationRunning
+            )
         assertFalse(isExpandAnimationRunning!!)
 
-        verify(headsUpManager).removeNotification(
-                notificationKey, true /* releaseImmediately */, true /* animate */)
+        verify(headsUpManager)
+            .removeNotification(notificationKey, true /* releaseImmediately */, true /* animate */)
         verify(onFinishAnimationCallback).run()
     }
 
@@ -97,13 +101,14 @@ class NotificationLaunchAnimatorControllerTest : SysuiTestCase() {
 
         assertTrue(HeadsUpUtil.isClickedHeadsUpNotification(notification))
         assertFalse(notification.entry.isExpandAnimationRunning)
-        val isExpandAnimationRunning by testScope.collectLastValue(
-            notificationExpansionRepository.isExpandAnimationRunning
-        )
+        val isExpandAnimationRunning by
+            testScope.collectLastValue(
+                notificationLaunchAnimationInteractor.isLaunchAnimationRunning
+            )
         assertFalse(isExpandAnimationRunning!!)
 
-        verify(headsUpManager).removeNotification(
-                notificationKey, true /* releaseImmediately */, true /* animate */)
+        verify(headsUpManager)
+            .removeNotification(notificationKey, true /* releaseImmediately */, true /* animate */)
         verify(onFinishAnimationCallback).run()
     }
 
@@ -114,13 +119,14 @@ class NotificationLaunchAnimatorControllerTest : SysuiTestCase() {
 
         assertFalse(HeadsUpUtil.isClickedHeadsUpNotification(notification))
         assertFalse(notification.entry.isExpandAnimationRunning)
-        val isExpandAnimationRunning by testScope.collectLastValue(
-            notificationExpansionRepository.isExpandAnimationRunning
-        )
+        val isExpandAnimationRunning by
+            testScope.collectLastValue(
+                notificationLaunchAnimationInteractor.isLaunchAnimationRunning
+            )
         assertFalse(isExpandAnimationRunning!!)
 
-        verify(headsUpManager).removeNotification(
-                notificationKey, true /* releaseImmediately */, false /* animate */)
+        verify(headsUpManager)
+            .removeNotification(notificationKey, true /* releaseImmediately */, false /* animate */)
         verify(onFinishAnimationCallback).run()
     }
 
@@ -128,15 +134,21 @@ class NotificationLaunchAnimatorControllerTest : SysuiTestCase() {
     fun testAlertingSummaryHunRemovedOnNonAlertingChildLaunch() {
         val GROUP_KEY = "test_group_key"
 
-        val summary = NotificationEntryBuilder().setGroup(mContext, GROUP_KEY).setId(0).apply {
-            modifyNotification(mContext).setSmallIcon(R.drawable.ic_person)
-        }.build()
+        val summary =
+            NotificationEntryBuilder()
+                .setGroup(mContext, GROUP_KEY)
+                .setId(0)
+                .apply { modifyNotification(mContext).setSmallIcon(R.drawable.ic_person) }
+                .build()
         assertNotSame(summary.key, notification.entry.key)
 
         notificationTestHelper.createRow(summary)
 
-        GroupEntryBuilder().setKey(GROUP_KEY).setSummary(summary).addChild(notification.entry)
-                .build()
+        GroupEntryBuilder()
+            .setKey(GROUP_KEY)
+            .setSummary(summary)
+            .addChild(notification.entry)
+            .build()
         assertSame(summary, notification.entry.parent?.summary)
 
         `when`(headsUpManager.isAlerting(notificationKey)).thenReturn(false)
@@ -147,10 +159,14 @@ class NotificationLaunchAnimatorControllerTest : SysuiTestCase() {
 
         controller.onLaunchAnimationEnd(isExpandingFullyAbove = true)
 
-        verify(headsUpManager).removeNotification(
-                summary.key, true /* releaseImmediately */, false /* animate */)
-        verify(headsUpManager, never()).removeNotification(
-                notification.entry.key, true /* releaseImmediately */, false /* animate */)
+        verify(headsUpManager)
+            .removeNotification(summary.key, true /* releaseImmediately */, false /* animate */)
+        verify(headsUpManager, never())
+            .removeNotification(
+                notification.entry.key,
+                true /* releaseImmediately */,
+                false /* animate */
+            )
     }
 
     @Test
@@ -158,9 +174,10 @@ class NotificationLaunchAnimatorControllerTest : SysuiTestCase() {
         controller.onIntentStarted(willAnimate = true)
 
         assertTrue(notification.entry.isExpandAnimationRunning)
-        val isExpandAnimationRunning by testScope.collectLastValue(
-            notificationExpansionRepository.isExpandAnimationRunning
-        )
+        val isExpandAnimationRunning by
+            testScope.collectLastValue(
+                notificationLaunchAnimationInteractor.isLaunchAnimationRunning
+            )
         assertTrue(isExpandAnimationRunning!!)
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/data/repository/NotificationExpansionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationLaunchAnimationInteractorTest.kt
similarity index 55%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/data/repository/NotificationExpansionRepositoryTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationLaunchAnimationInteractorTest.kt
index f28d9ab06bc7c5b91a95162e3df45557c490c61f..a0faab56345204f8adec33707027f8c17e45a08a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/data/repository/NotificationExpansionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationLaunchAnimationInteractorTest.kt
@@ -14,42 +14,44 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.notification.data.repository
+package com.android.systemui.statusbar.notification.domain.interactor
 
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.statusbar.notification.data.repository.NotificationLaunchAnimationRepository
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.test.runTest
 import org.junit.Test
 
 @SmallTest
-class NotificationExpansionRepositoryTest : SysuiTestCase() {
-    private val underTest = NotificationExpansionRepository()
+class NotificationLaunchAnimationInteractorTest : SysuiTestCase() {
+    private val repository = NotificationLaunchAnimationRepository()
+    private val underTest = NotificationLaunchAnimationInteractor(repository)
 
     @Test
-    fun setIsExpandAnimationRunning_startsAsFalse() = runTest {
-        val latest by collectLastValue(underTest.isExpandAnimationRunning)
+    fun setIsLaunchAnimationRunning_startsAsFalse() = runTest {
+        val latest by collectLastValue(underTest.isLaunchAnimationRunning)
 
         assertThat(latest).isFalse()
     }
 
     @Test
-    fun setIsExpandAnimationRunning_false_emitsTrue() = runTest {
-        val latest by collectLastValue(underTest.isExpandAnimationRunning)
+    fun setIsLaunchAnimationRunning_false_emitsTrue() = runTest {
+        val latest by collectLastValue(underTest.isLaunchAnimationRunning)
 
-        underTest.setIsExpandAnimationRunning(true)
+        underTest.setIsLaunchAnimationRunning(true)
 
         assertThat(latest).isTrue()
     }
 
     @Test
-    fun setIsExpandAnimationRunning_false_emitsFalse() = runTest {
-        val latest by collectLastValue(underTest.isExpandAnimationRunning)
-        underTest.setIsExpandAnimationRunning(true)
+    fun setIsLaunchAnimationRunning_false_emitsFalse() = runTest {
+        val latest by collectLastValue(underTest.isLaunchAnimationRunning)
+        underTest.setIsLaunchAnimationRunning(true)
 
         // WHEN the animation is no longer running
-        underTest.setIsExpandAnimationRunning(false)
+        underTest.setIsLaunchAnimationRunning(false)
 
         // THEN the flow emits false
         assertThat(latest).isFalse()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationsListInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationsListInteractorTest.kt
index 8c5c43986f8ae30ded02fc311edb174d4c86ebd3..ca8ea4eb9d1a5d89d4944f3951a6dad9594cafd8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationsListInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationsListInteractorTest.kt
@@ -35,6 +35,7 @@ class RenderNotificationsListInteractorTest : SysuiTestCase() {
     private val underTest =
         RenderNotificationListInteractor(
             notifsRepository,
+            sectionStyleProvider = mock(),
         )
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterViewTest.java
index f72142ffc6d7cca5041bde553d6d242f896de3d5..cc87d7ce377b619690c5e26154dee38b8f551bf5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterViewTest.java
@@ -22,8 +22,15 @@ import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertTrue;
 
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
 
+import android.content.Context;
 import android.testing.AndroidTestingRunner;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -31,6 +38,7 @@ import android.widget.TextView;
 
 import androidx.test.filters.SmallTest;
 
+import com.android.systemui.Flags;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.res.R;
 
@@ -44,9 +52,13 @@ public class FooterViewTest extends SysuiTestCase {
 
     FooterView mView;
 
+    Context mSpyContext = spy(mContext);
+
     @Before
     public void setUp() {
-        mView = (FooterView) LayoutInflater.from(mContext).inflate(
+        mSetFlagsRule.enableFlags(Flags.FLAG_NOTIFICATIONS_FOOTER_VIEW_REFACTOR);
+
+        mView = (FooterView) LayoutInflater.from(mSpyContext).inflate(
                 R.layout.status_bar_notification_footer, null, false);
         mView.setDuration(0);
     }
@@ -101,6 +113,37 @@ public class FooterViewTest extends SysuiTestCase {
         mView.setSecondaryVisible(true /* visible */, true /* animate */);
     }
 
+    @Test
+    public void testSetMessageString_resourceOnlyFetchedOnce() {
+        mView.setMessageString(R.string.unlock_to_see_notif_text);
+        verify(mSpyContext).getString(eq(R.string.unlock_to_see_notif_text));
+
+        clearInvocations(mSpyContext);
+
+        assertThat(((TextView) mView.findViewById(R.id.unlock_prompt_footer))
+                .getText().toString()).contains("Unlock");
+
+        // Set it a few more times, it shouldn't lead to the resource being fetched again
+        mView.setMessageString(R.string.unlock_to_see_notif_text);
+        mView.setMessageString(R.string.unlock_to_see_notif_text);
+
+        verify(mSpyContext, never()).getString(anyInt());
+    }
+
+    @Test
+    public void testSetMessageIcon_resourceOnlyFetchedOnce() {
+        mView.setMessageIcon(R.drawable.ic_friction_lock_closed);
+        verify(mSpyContext).getDrawable(eq(R.drawable.ic_friction_lock_closed));
+
+        clearInvocations(mSpyContext);
+
+        // Set it a few more times, it shouldn't lead to the resource being fetched again
+        mView.setMessageIcon(R.drawable.ic_friction_lock_closed);
+        mView.setMessageIcon(R.drawable.ic_friction_lock_closed);
+
+        verify(mSpyContext, never()).getDrawable(anyInt());
+    }
+
     @Test
     public void testSetFooterLabelVisible() {
         mView.setFooterLabelVisible(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..57a7c3c7e2bfecc81a45b50aaaabcb73a2cd83d2
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt
@@ -0,0 +1,54 @@
+/*
+ * 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.footer.ui.viewmodel
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationListRepository
+import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class FooterViewModelTest : SysuiTestCase() {
+    private val repository = ActiveNotificationListRepository()
+    private val interactor = SeenNotificationsInteractor(repository)
+    private val underTest = FooterViewModel(interactor)
+
+    @Test
+    fun testMessageVisible_whenFilteredNotifications() = runTest {
+        val message by collectLastValue(underTest.message)
+
+        repository.hasFilteredOutSeenNotifications.value = true
+
+        assertThat(message?.visible).isTrue()
+    }
+
+    @Test
+    fun testMessageVisible_whenNoFilteredNotifications() = runTest {
+        val message by collectLastValue(underTest.message)
+
+        repository.hasFilteredOutSeenNotifications.value = false
+
+        assertThat(message?.visible).isFalse()
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..ec80e5f8821c26cd9072155412ebb3125e6b2e34
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt
@@ -0,0 +1,418 @@
+/*
+ * 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.icon.domain.interactor
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.SysUITestModule
+import com.android.TestMocksModule
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository
+import com.android.systemui.statusbar.data.repository.NotificationListenerSettingsRepository
+import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationListRepository
+import com.android.systemui.statusbar.notification.data.repository.FakeNotificationsKeyguardViewStateRepository
+import com.android.systemui.statusbar.notification.shared.activeNotificationModel
+import com.android.systemui.statusbar.notification.shared.byIsAmbient
+import com.android.systemui.statusbar.notification.shared.byIsLastMessageFromReply
+import com.android.systemui.statusbar.notification.shared.byIsPulsing
+import com.android.systemui.statusbar.notification.shared.byIsRowDismissed
+import com.android.systemui.statusbar.notification.shared.byIsSilent
+import com.android.systemui.statusbar.notification.shared.byIsSuppressedFromStatusBar
+import com.android.systemui.statusbar.notification.shared.byKey
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.android.wm.shell.bubbles.Bubbles
+import com.google.common.truth.Truth.assertThat
+import dagger.BindsInstance
+import dagger.Component
+import java.util.Optional
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class NotificationIconsInteractorTest : SysuiTestCase() {
+
+    private val bubbles: Bubbles = mock()
+
+    @Component(modules = [SysUITestModule::class])
+    @SysUISingleton
+    interface TestComponent {
+        val underTest: NotificationIconsInteractor
+
+        val activeNotificationListRepository: ActiveNotificationListRepository
+        val keyguardViewStateRepository: FakeNotificationsKeyguardViewStateRepository
+        val testScope: TestScope
+
+        @Component.Factory
+        interface Factory {
+            fun create(@BindsInstance test: SysuiTestCase, mocks: TestMocksModule): TestComponent
+        }
+    }
+
+    val testComponent: TestComponent =
+        DaggerNotificationIconsInteractorTest_TestComponent.factory()
+            .create(test = this, mocks = TestMocksModule(bubbles = Optional.of(bubbles)))
+
+    @Before
+    fun setup() =
+        with(testComponent) {
+            activeNotificationListRepository.activeNotifications.value =
+                testIcons.associateBy { it.key }
+        }
+
+    @Test
+    fun filteredEntrySet() =
+        with(testComponent) {
+            testScope.runTest {
+                val filteredSet by collectLastValue(underTest.filteredNotifSet())
+                assertThat(filteredSet).containsExactlyElementsIn(testIcons)
+            }
+        }
+
+    @Test
+    fun filteredEntrySet_noExpandedBubbles() =
+        with(testComponent) {
+            testScope.runTest {
+                whenever(bubbles.isBubbleExpanded(eq("notif1"))).thenReturn(true)
+                val filteredSet by collectLastValue(underTest.filteredNotifSet())
+                assertThat(filteredSet).comparingElementsUsing(byKey).doesNotContain("notif1")
+            }
+        }
+
+    @Test
+    fun filteredEntrySet_noAmbient() =
+        with(testComponent) {
+            testScope.runTest {
+                val filteredSet by collectLastValue(underTest.filteredNotifSet(showAmbient = false))
+                assertThat(filteredSet).comparingElementsUsing(byIsAmbient).doesNotContain(true)
+                assertThat(filteredSet)
+                    .comparingElementsUsing(byIsSuppressedFromStatusBar)
+                    .doesNotContain(true)
+            }
+        }
+
+    @Test
+    fun filteredEntrySet_noLowPriority() =
+        with(testComponent) {
+            testScope.runTest {
+                val filteredSet by
+                    collectLastValue(underTest.filteredNotifSet(showLowPriority = false))
+                assertThat(filteredSet).comparingElementsUsing(byIsSilent).doesNotContain(true)
+            }
+        }
+
+    @Test
+    fun filteredEntrySet_noDismissed() =
+        with(testComponent) {
+            testScope.runTest {
+                val filteredSet by
+                    collectLastValue(underTest.filteredNotifSet(showDismissed = false))
+                assertThat(filteredSet)
+                    .comparingElementsUsing(byIsRowDismissed)
+                    .doesNotContain(true)
+            }
+        }
+
+    @Test
+    fun filteredEntrySet_noRepliedMessages() =
+        with(testComponent) {
+            testScope.runTest {
+                val filteredSet by
+                    collectLastValue(underTest.filteredNotifSet(showRepliedMessages = false))
+                assertThat(filteredSet)
+                    .comparingElementsUsing(byIsLastMessageFromReply)
+                    .doesNotContain(true)
+            }
+        }
+
+    @Test
+    fun filteredEntrySet_noPulsing_notifsNotFullyHidden() =
+        with(testComponent) {
+            testScope.runTest {
+                val filteredSet by collectLastValue(underTest.filteredNotifSet(showPulsing = false))
+                keyguardViewStateRepository.setNotificationsFullyHidden(false)
+                assertThat(filteredSet).comparingElementsUsing(byIsPulsing).doesNotContain(true)
+            }
+        }
+
+    @Test
+    fun filteredEntrySet_noPulsing_notifsFullyHidden() =
+        with(testComponent) {
+            testScope.runTest {
+                val filteredSet by collectLastValue(underTest.filteredNotifSet(showPulsing = false))
+                keyguardViewStateRepository.setNotificationsFullyHidden(true)
+                assertThat(filteredSet).comparingElementsUsing(byIsPulsing).contains(true)
+            }
+        }
+}
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() {
+
+    private val bubbles: Bubbles = mock()
+
+    @Component(modules = [SysUITestModule::class])
+    @SysUISingleton
+    interface TestComponent {
+        val underTest: AlwaysOnDisplayNotificationIconsInteractor
+
+        val activeNotificationListRepository: ActiveNotificationListRepository
+        val deviceEntryRepository: FakeDeviceEntryRepository
+        val keyguardViewStateRepository: FakeNotificationsKeyguardViewStateRepository
+        val testScope: TestScope
+
+        @Component.Factory
+        interface Factory {
+            fun create(@BindsInstance test: SysuiTestCase, mocks: TestMocksModule): TestComponent
+        }
+    }
+
+    val testComponent: TestComponent =
+        DaggerAlwaysOnDisplayNotificationIconsInteractorTest_TestComponent.factory()
+            .create(test = this, mocks = TestMocksModule(bubbles = Optional.of(bubbles)))
+
+    @Before
+    fun setup() =
+        with(testComponent) {
+            activeNotificationListRepository.activeNotifications.value =
+                testIcons.associateBy { it.key }
+        }
+
+    @Test
+    fun filteredEntrySet_noExpandedBubbles() =
+        with(testComponent) {
+            testScope.runTest {
+                whenever(bubbles.isBubbleExpanded(eq("notif1"))).thenReturn(true)
+                val filteredSet by collectLastValue(underTest.aodNotifs)
+                assertThat(filteredSet).comparingElementsUsing(byKey).doesNotContain("notif1")
+            }
+        }
+
+    @Test
+    fun filteredEntrySet_noAmbient() =
+        with(testComponent) {
+            testScope.runTest {
+                val filteredSet by collectLastValue(underTest.aodNotifs)
+                assertThat(filteredSet).comparingElementsUsing(byIsAmbient).doesNotContain(true)
+                assertThat(filteredSet)
+                    .comparingElementsUsing(byIsSuppressedFromStatusBar)
+                    .doesNotContain(true)
+            }
+        }
+
+    @Test
+    fun filteredEntrySet_noDismissed() =
+        with(testComponent) {
+            testScope.runTest {
+                val filteredSet by collectLastValue(underTest.aodNotifs)
+                assertThat(filteredSet)
+                    .comparingElementsUsing(byIsRowDismissed)
+                    .doesNotContain(true)
+            }
+        }
+
+    @Test
+    fun filteredEntrySet_noRepliedMessages() =
+        with(testComponent) {
+            testScope.runTest {
+                val filteredSet by collectLastValue(underTest.aodNotifs)
+                assertThat(filteredSet)
+                    .comparingElementsUsing(byIsLastMessageFromReply)
+                    .doesNotContain(true)
+            }
+        }
+
+    @Test
+    fun filteredEntrySet_showPulsing_notifsNotFullyHidden_bypassDisabled() =
+        with(testComponent) {
+            testScope.runTest {
+                val filteredSet by collectLastValue(underTest.aodNotifs)
+                deviceEntryRepository.setBypassEnabled(false)
+                keyguardViewStateRepository.setNotificationsFullyHidden(false)
+                assertThat(filteredSet).comparingElementsUsing(byIsPulsing).contains(true)
+            }
+        }
+
+    @Test
+    fun filteredEntrySet_showPulsing_notifsFullyHidden_bypassDisabled() =
+        with(testComponent) {
+            testScope.runTest {
+                val filteredSet by collectLastValue(underTest.aodNotifs)
+                deviceEntryRepository.setBypassEnabled(false)
+                keyguardViewStateRepository.setNotificationsFullyHidden(true)
+                assertThat(filteredSet).comparingElementsUsing(byIsPulsing).contains(true)
+            }
+        }
+
+    @Test
+    fun filteredEntrySet_noPulsing_notifsNotFullyHidden_bypassEnabled() =
+        with(testComponent) {
+            testScope.runTest {
+                val filteredSet by collectLastValue(underTest.aodNotifs)
+                deviceEntryRepository.setBypassEnabled(true)
+                keyguardViewStateRepository.setNotificationsFullyHidden(false)
+                assertThat(filteredSet).comparingElementsUsing(byIsPulsing).doesNotContain(true)
+            }
+        }
+
+    @Test
+    fun filteredEntrySet_showPulsing_notifsFullyHidden_bypassEnabled() =
+        with(testComponent) {
+            testScope.runTest {
+                val filteredSet by collectLastValue(underTest.aodNotifs)
+                deviceEntryRepository.setBypassEnabled(true)
+                keyguardViewStateRepository.setNotificationsFullyHidden(true)
+                assertThat(filteredSet).comparingElementsUsing(byIsPulsing).contains(true)
+            }
+        }
+}
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class StatusBarNotificationIconsInteractorTest : SysuiTestCase() {
+
+    private val bubbles: Bubbles = mock()
+
+    @Component(modules = [SysUITestModule::class])
+    @SysUISingleton
+    interface TestComponent {
+        val underTest: StatusBarNotificationIconsInteractor
+
+        val activeNotificationListRepository: ActiveNotificationListRepository
+        val keyguardViewStateRepository: FakeNotificationsKeyguardViewStateRepository
+        val notificationListenerSettingsRepository: NotificationListenerSettingsRepository
+        val testScope: TestScope
+
+        @Component.Factory
+        interface Factory {
+            fun create(@BindsInstance test: SysuiTestCase, mocks: TestMocksModule): TestComponent
+        }
+    }
+
+    val testComponent: TestComponent =
+        DaggerStatusBarNotificationIconsInteractorTest_TestComponent.factory()
+            .create(test = this, mocks = TestMocksModule(bubbles = Optional.of(bubbles)))
+
+    @Before
+    fun setup() =
+        with(testComponent) {
+            activeNotificationListRepository.activeNotifications.value =
+                testIcons.associateBy { it.key }
+        }
+
+    @Test
+    fun filteredEntrySet_noExpandedBubbles() =
+        with(testComponent) {
+            testScope.runTest {
+                whenever(bubbles.isBubbleExpanded(eq("notif1"))).thenReturn(true)
+                val filteredSet by collectLastValue(underTest.statusBarNotifs)
+                assertThat(filteredSet).comparingElementsUsing(byKey).doesNotContain("notif1")
+            }
+        }
+
+    @Test
+    fun filteredEntrySet_noAmbient() =
+        with(testComponent) {
+            testScope.runTest {
+                val filteredSet by collectLastValue(underTest.statusBarNotifs)
+                assertThat(filteredSet).comparingElementsUsing(byIsAmbient).doesNotContain(true)
+                assertThat(filteredSet)
+                    .comparingElementsUsing(byIsSuppressedFromStatusBar)
+                    .doesNotContain(true)
+            }
+        }
+
+    @Test
+    fun filteredEntrySet_noLowPriority_whenDontShowSilentIcons() =
+        with(testComponent) {
+            testScope.runTest {
+                val filteredSet by collectLastValue(underTest.statusBarNotifs)
+                notificationListenerSettingsRepository.showSilentStatusIcons.value = false
+                assertThat(filteredSet).comparingElementsUsing(byIsSilent).doesNotContain(true)
+            }
+        }
+
+    @Test
+    fun filteredEntrySet_showLowPriority_whenShowSilentIcons() =
+        with(testComponent) {
+            testScope.runTest {
+                val filteredSet by collectLastValue(underTest.statusBarNotifs)
+                notificationListenerSettingsRepository.showSilentStatusIcons.value = true
+                assertThat(filteredSet).comparingElementsUsing(byIsSilent).contains(true)
+            }
+        }
+
+    @Test
+    fun filteredEntrySet_noDismissed() =
+        with(testComponent) {
+            testScope.runTest {
+                val filteredSet by collectLastValue(underTest.statusBarNotifs)
+                assertThat(filteredSet)
+                    .comparingElementsUsing(byIsRowDismissed)
+                    .doesNotContain(true)
+            }
+        }
+
+    @Test
+    fun filteredEntrySet_noRepliedMessages() =
+        with(testComponent) {
+            testScope.runTest {
+                val filteredSet by collectLastValue(underTest.statusBarNotifs)
+                assertThat(filteredSet)
+                    .comparingElementsUsing(byIsLastMessageFromReply)
+                    .doesNotContain(true)
+            }
+        }
+}
+
+private val testIcons =
+    listOf(
+        activeNotificationModel(
+            key = "notif1",
+        ),
+        activeNotificationModel(
+            key = "notif2",
+            isAmbient = true,
+        ),
+        activeNotificationModel(
+            key = "notif3",
+            isRowDismissed = true,
+        ),
+        activeNotificationModel(
+            key = "notif4",
+            isSilent = true,
+        ),
+        activeNotificationModel(
+            key = "notif5",
+            isLastMessageFromReply = true,
+        ),
+        activeNotificationModel(
+            key = "notif6",
+            isSuppressedFromStatusBar = true,
+        ),
+        activeNotificationModel(
+            key = "notif7",
+            isPulsing = true,
+        ),
+    )
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImplTest.kt
deleted file mode 100644
index e57986ddfa184c3bb715c7635f83e2ab78f1c2fa..0000000000000000000000000000000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImplTest.kt
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * 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.icon.ui.viewbinder
-
-import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper.RunWithLooper
-import androidx.test.filters.SmallTest
-import com.android.SysUITestModule
-import com.android.TestMocksModule
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.biometrics.domain.BiometricsDomainLayerModule
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.flags.FakeFeatureFlagsClassicModule
-import com.android.systemui.flags.Flags
-import com.android.systemui.statusbar.phone.DozeParameters
-import com.android.systemui.user.domain.UserDomainLayerModule
-import dagger.BindsInstance
-import dagger.Component
-import org.junit.Assert.assertFalse
-import org.junit.Assert.assertTrue
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.MockitoAnnotations
-
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-@RunWithLooper(setAsMainLooper = true)
-class NotificationIconAreaControllerViewBinderWrapperImplTest : SysuiTestCase() {
-
-    @Mock private lateinit var dozeParams: DozeParameters
-
-    private lateinit var testComponent: TestComponent
-    private val underTest
-        get() = testComponent.underTest
-
-    @Before
-    fun setup() {
-        MockitoAnnotations.initMocks(this)
-        allowTestableLooperAsMainThread()
-
-        testComponent =
-            DaggerNotificationIconAreaControllerViewBinderWrapperImplTest_TestComponent.factory()
-                .create(
-                    test = this,
-                    featureFlags =
-                        FakeFeatureFlagsClassicModule {
-                            set(Flags.FACE_AUTH_REFACTOR, value = false)
-                            set(Flags.MIGRATE_KEYGUARD_STATUS_VIEW, value = false)
-                        },
-                    mocks =
-                        TestMocksModule(
-                            dozeParameters = dozeParams,
-                        ),
-                )
-    }
-
-    @Test
-    fun testNotificationIcons_settingHideIcons() {
-        underTest.settingsListener.onStatusBarIconsBehaviorChanged(true)
-        assertFalse(underTest.shouldShowLowPriorityIcons())
-    }
-
-    @Test
-    fun testNotificationIcons_settingShowIcons() {
-        underTest.settingsListener.onStatusBarIconsBehaviorChanged(false)
-        assertTrue(underTest.shouldShowLowPriorityIcons())
-    }
-
-    @SysUISingleton
-    @Component(
-        modules =
-            [
-                SysUITestModule::class,
-                BiometricsDomainLayerModule::class,
-                UserDomainLayerModule::class,
-            ]
-    )
-    interface TestComponent {
-
-        val underTest: NotificationIconAreaControllerViewBinderWrapperImpl
-
-        @Component.Factory
-        interface Factory {
-            fun create(
-                @BindsInstance test: SysuiTestCase,
-                mocks: TestMocksModule,
-                featureFlags: FakeFeatureFlagsClassicModule,
-            ): TestComponent
-        }
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt
index 31efebbc5b60deeaad8cc866573e16c39358c57a..41c7071a616d3bd3fce864f6ffa12b859d07f60b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt
@@ -44,7 +44,9 @@ import com.android.systemui.statusbar.phone.ScreenOffAnimationController
 import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository
 import com.android.systemui.user.domain.UserDomainLayerModule
 import com.android.systemui.util.mockito.whenever
-import com.android.systemui.util.ui.AnimatedValue
+import com.android.systemui.util.ui.isAnimating
+import com.android.systemui.util.ui.stopAnimating
+import com.android.systemui.util.ui.value
 import com.google.common.truth.Truth.assertThat
 import dagger.BindsInstance
 import dagger.Component
@@ -243,6 +245,7 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() {
                 )
             )
             val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+            runCurrent()
 
             keyguardRepository.setKeyguardShowing(true)
             keyguardRepository.setKeyguardOccluded(false)
@@ -266,6 +269,7 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() {
     fun isDozing_startAodTransition() =
         scope.runTest {
             val isDozing by collectLastValue(underTest.isDozing)
+            runCurrent()
             keyguardTransitionRepository.sendTransitionStep(
                 TransitionStep(
                     from = KeyguardState.GONE,
@@ -274,13 +278,15 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() {
                 )
             )
             runCurrent()
-            assertThat(isDozing).isEqualTo(AnimatedValue(true, isAnimating = true))
+            assertThat(isDozing?.value).isTrue()
+            assertThat(isDozing?.isAnimating).isTrue()
         }
 
     @Test
     fun isDozing_startDozeTransition() =
         scope.runTest {
             val isDozing by collectLastValue(underTest.isDozing)
+            runCurrent()
             keyguardTransitionRepository.sendTransitionStep(
                 TransitionStep(
                     from = KeyguardState.GONE,
@@ -289,13 +295,15 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() {
                 )
             )
             runCurrent()
-            assertThat(isDozing).isEqualTo(AnimatedValue(true, isAnimating = false))
+            assertThat(isDozing?.value).isTrue()
+            assertThat(isDozing?.isAnimating).isFalse()
         }
 
     @Test
     fun isDozing_startDozeToAodTransition() =
         scope.runTest {
             val isDozing by collectLastValue(underTest.isDozing)
+            runCurrent()
             keyguardTransitionRepository.sendTransitionStep(
                 TransitionStep(
                     from = KeyguardState.DOZING,
@@ -304,13 +312,15 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() {
                 )
             )
             runCurrent()
-            assertThat(isDozing).isEqualTo(AnimatedValue(true, isAnimating = true))
+            assertThat(isDozing?.value).isTrue()
+            assertThat(isDozing?.isAnimating).isTrue()
         }
 
     @Test
     fun isNotDozing_startAodToGoneTransition() =
         scope.runTest {
             val isDozing by collectLastValue(underTest.isDozing)
+            runCurrent()
             keyguardTransitionRepository.sendTransitionStep(
                 TransitionStep(
                     from = KeyguardState.AOD,
@@ -319,13 +329,15 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() {
                 )
             )
             runCurrent()
-            assertThat(isDozing).isEqualTo(AnimatedValue(false, isAnimating = true))
+            assertThat(isDozing?.value).isFalse()
+            assertThat(isDozing?.isAnimating).isTrue()
         }
 
     @Test
     fun isDozing_stopAnimation() =
         scope.runTest {
             val isDozing by collectLastValue(underTest.isDozing)
+            runCurrent()
             keyguardTransitionRepository.sendTransitionStep(
                 TransitionStep(
                     from = KeyguardState.AOD,
@@ -335,7 +347,8 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() {
             )
             runCurrent()
 
-            underTest.completeDozeAnimation()
+            assertThat(isDozing?.isAnimating).isEqualTo(true)
+            isDozing?.stopAnimating()
             runCurrent()
 
             assertThat(isDozing?.isAnimating).isEqualTo(false)
@@ -345,6 +358,7 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() {
     fun isNotVisible_pulseExpanding() =
         scope.runTest {
             val isVisible by collectLastValue(underTest.isVisible)
+            runCurrent()
             notifsKeyguardRepository.setPulseExpanding(true)
             runCurrent()
 
@@ -355,6 +369,7 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() {
     fun isNotVisible_notOnKeyguard_dontShowAodIconsWhenShade() =
         scope.runTest {
             val isVisible by collectLastValue(underTest.isVisible)
+            runCurrent()
             keyguardTransitionRepository.sendTransitionStep(
                 TransitionStep(
                     to = KeyguardState.GONE,
@@ -364,13 +379,15 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() {
             whenever(screenOffAnimController.shouldShowAodIconsWhenShade()).thenReturn(false)
             runCurrent()
 
-            assertThat(isVisible).isEqualTo(AnimatedValue(false, isAnimating = false))
+            assertThat(isVisible?.value).isFalse()
+            assertThat(isVisible?.isAnimating).isFalse()
         }
 
     @Test
     fun isVisible_bypassEnabled() =
         scope.runTest {
             val isVisible by collectLastValue(underTest.isVisible)
+            runCurrent()
             deviceEntryRepository.setBypassEnabled(true)
             runCurrent()
 
@@ -381,6 +398,7 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() {
     fun isNotVisible_pulseExpanding_notBypassing() =
         scope.runTest {
             val isVisible by collectLastValue(underTest.isVisible)
+            runCurrent()
             notifsKeyguardRepository.setPulseExpanding(true)
             deviceEntryRepository.setBypassEnabled(false)
             runCurrent()
@@ -398,26 +416,30 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() {
             notifsKeyguardRepository.setNotificationsFullyHidden(true)
             runCurrent()
 
-            assertThat(isVisible).isEqualTo(AnimatedValue(true, isAnimating = true))
+            assertThat(isVisible?.value).isTrue()
+            assertThat(isVisible?.isAnimating).isTrue()
         }
 
     @Test
     fun isVisible_notifsFullyHidden_bypassDisabled_aodDisabled() =
         scope.runTest {
             val isVisible by collectLastValue(underTest.isVisible)
+            runCurrent()
             notifsKeyguardRepository.setPulseExpanding(false)
             deviceEntryRepository.setBypassEnabled(false)
             whenever(dozeParams.alwaysOn).thenReturn(false)
             notifsKeyguardRepository.setNotificationsFullyHidden(true)
             runCurrent()
 
-            assertThat(isVisible).isEqualTo(AnimatedValue(true, isAnimating = false))
+            assertThat(isVisible?.value).isTrue()
+            assertThat(isVisible?.isAnimating).isFalse()
         }
 
     @Test
     fun isVisible_notifsFullyHidden_bypassDisabled_displayNeedsBlanking() =
         scope.runTest {
             val isVisible by collectLastValue(underTest.isVisible)
+            runCurrent()
             notifsKeyguardRepository.setPulseExpanding(false)
             deviceEntryRepository.setBypassEnabled(false)
             whenever(dozeParams.alwaysOn).thenReturn(true)
@@ -425,7 +447,8 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() {
             notifsKeyguardRepository.setNotificationsFullyHidden(true)
             runCurrent()
 
-            assertThat(isVisible).isEqualTo(AnimatedValue(true, isAnimating = false))
+            assertThat(isVisible?.value).isTrue()
+            assertThat(isVisible?.isAnimating).isFalse()
         }
 
     @Test
@@ -440,13 +463,15 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() {
             notifsKeyguardRepository.setNotificationsFullyHidden(true)
             runCurrent()
 
-            assertThat(isVisible).isEqualTo(AnimatedValue(true, isAnimating = true))
+            assertThat(isVisible?.value).isTrue()
+            assertThat(isVisible?.isAnimating).isTrue()
         }
 
     @Test
     fun isVisible_stopAnimation() =
         scope.runTest {
             val isVisible by collectLastValue(underTest.isVisible)
+            runCurrent()
             notifsKeyguardRepository.setPulseExpanding(false)
             deviceEntryRepository.setBypassEnabled(false)
             whenever(dozeParams.alwaysOn).thenReturn(true)
@@ -454,7 +479,8 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() {
             notifsKeyguardRepository.setNotificationsFullyHidden(true)
             runCurrent()
 
-            underTest.completeVisibilityAnimation()
+            assertThat(isVisible?.isAnimating).isEqualTo(true)
+            isVisible?.stopAnimating()
             runCurrent()
 
             assertThat(isVisible?.isAnimating).isEqualTo(false)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt
index e21ebeb77f96f1d4a58e7609b1958800fa1300d4..ba68fbb981e6d0c73d2b73e99fa7fb4d8432e9f3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt
@@ -18,6 +18,7 @@
 package com.android.systemui.statusbar.notification.icon.ui.viewmodel
 
 import android.graphics.Rect
+import android.graphics.drawable.Icon
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.SysUITestModule
@@ -39,12 +40,19 @@ import com.android.systemui.plugins.DarkIconDispatcher
 import com.android.systemui.power.data.repository.FakePowerRepository
 import com.android.systemui.power.shared.model.WakeSleepReason
 import com.android.systemui.power.shared.model.WakefulnessState
+import com.android.systemui.shade.data.repository.FakeShadeRepository
+import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationListRepository
+import com.android.systemui.statusbar.notification.data.repository.HeadsUpNotificationIconViewStateRepository
+import com.android.systemui.statusbar.notification.shared.activeNotificationModel
 import com.android.systemui.statusbar.phone.DozeParameters
 import com.android.systemui.statusbar.phone.SysuiDarkIconDispatcher
 import com.android.systemui.statusbar.phone.data.repository.FakeDarkIconRepository
 import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository
 import com.android.systemui.user.domain.UserDomainLayerModule
+import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.ui.isAnimating
+import com.android.systemui.util.ui.value
 import com.google.common.truth.Truth.assertThat
 import dagger.BindsInstance
 import dagger.Component
@@ -327,6 +335,58 @@ class NotificationIconContainerStatusBarViewModelTest : SysuiTestCase() {
             }
         }
 
+    @Test
+    fun isolatedIcon_animateOnAppear_shadeCollapsed() =
+        with(testComponent) {
+            scope.runTest {
+                val icon: Icon = mock()
+                shadeRepository.setLegacyShadeExpansion(0f)
+                activeNotificationsRepository.activeNotifications.value =
+                    listOf(
+                            activeNotificationModel(
+                                key = "notif1",
+                                groupKey = "group",
+                                statusBarIcon = icon
+                            )
+                        )
+                        .associateBy { it.key }
+                val isolatedIcon by collectLastValue(underTest.isolatedIcon)
+                runCurrent()
+
+                headsUpViewStateRepository.isolatedNotification.value = "notif1"
+                runCurrent()
+
+                assertThat(isolatedIcon?.value?.notifKey).isEqualTo("notif1")
+                assertThat(isolatedIcon?.isAnimating).isTrue()
+            }
+        }
+
+    @Test
+    fun isolatedIcon_dontAnimateOnAppear_shadeExpanded() =
+        with(testComponent) {
+            scope.runTest {
+                val icon: Icon = mock()
+                shadeRepository.setLegacyShadeExpansion(.5f)
+                activeNotificationsRepository.activeNotifications.value =
+                    listOf(
+                            activeNotificationModel(
+                                key = "notif1",
+                                groupKey = "group",
+                                statusBarIcon = icon
+                            )
+                        )
+                        .associateBy { it.key }
+                val isolatedIcon by collectLastValue(underTest.isolatedIcon)
+                runCurrent()
+
+                headsUpViewStateRepository.isolatedNotification.value = "notif1"
+                runCurrent()
+
+                assertThat(isolatedIcon?.value?.notifKey).isEqualTo("notif1")
+                assertThat(isolatedIcon?.isAnimating).isFalse()
+            }
+        }
+
     @SysUISingleton
     @Component(
         modules =
@@ -340,11 +400,14 @@ class NotificationIconContainerStatusBarViewModelTest : SysuiTestCase() {
 
         val underTest: NotificationIconContainerStatusBarViewModel
 
+        val activeNotificationsRepository: ActiveNotificationListRepository
         val darkIconRepository: FakeDarkIconRepository
         val deviceProvisioningRepository: FakeDeviceProvisioningRepository
+        val headsUpViewStateRepository: HeadsUpNotificationIconViewStateRepository
         val keyguardTransitionRepository: FakeKeyguardTransitionRepository
         val keyguardRepository: FakeKeyguardRepository
         val powerRepository: FakePowerRepository
+        val shadeRepository: FakeShadeRepository
         val scope: TestScope
 
         @Component.Factory
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shared/TestActiveNotificationModel.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shared/TestActiveNotificationModel.kt
index ed9405814e6aa61baa96a3b85bd89784b09857c8..ca105f3e52ea08ae3ec58bce97202085bfe32d1a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shared/TestActiveNotificationModel.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shared/TestActiveNotificationModel.kt
@@ -15,7 +15,53 @@
 
 package com.android.systemui.statusbar.notification.shared
 
+import android.graphics.drawable.Icon
 import com.google.common.truth.Correspondence
 
 val byKey: Correspondence<ActiveNotificationModel, String> =
     Correspondence.transforming({ it?.key }, "has a key of")
+val byIsAmbient: Correspondence<ActiveNotificationModel, Boolean> =
+    Correspondence.transforming({ it?.isAmbient }, "has an isAmbient value of")
+val byIsSuppressedFromStatusBar: Correspondence<ActiveNotificationModel, Boolean> =
+    Correspondence.transforming(
+        { it?.isSuppressedFromStatusBar },
+        "has an isSuppressedFromStatusBar value of",
+    )
+val byIsSilent: Correspondence<ActiveNotificationModel, Boolean> =
+    Correspondence.transforming({ it?.isSilent }, "has an isSilent value of")
+val byIsRowDismissed: Correspondence<ActiveNotificationModel, Boolean> =
+    Correspondence.transforming({ it?.isRowDismissed }, "has an isRowDismissed value of")
+val byIsLastMessageFromReply: Correspondence<ActiveNotificationModel, Boolean> =
+    Correspondence.transforming(
+        { it?.isLastMessageFromReply },
+        "has an isLastMessageFromReply value of"
+    )
+val byIsPulsing: Correspondence<ActiveNotificationModel, Boolean> =
+    Correspondence.transforming({ it?.isPulsing }, "has an isPulsing value of")
+
+fun activeNotificationModel(
+    key: String,
+    groupKey: String? = null,
+    isAmbient: Boolean = false,
+    isRowDismissed: Boolean = false,
+    isSilent: Boolean = false,
+    isLastMessageFromReply: Boolean = false,
+    isSuppressedFromStatusBar: Boolean = false,
+    isPulsing: Boolean = false,
+    aodIcon: Icon? = null,
+    shelfIcon: Icon? = null,
+    statusBarIcon: Icon? = null,
+) =
+    ActiveNotificationModel(
+        key = key,
+        groupKey = groupKey,
+        isAmbient = isAmbient,
+        isRowDismissed = isRowDismissed,
+        isSilent = isSilent,
+        isLastMessageFromReply = isLastMessageFromReply,
+        isSuppressedFromStatusBar = isSuppressedFromStatusBar,
+        isPulsing = isPulsing,
+        aodIcon = aodIcon,
+        shelfIcon = shelfIcon,
+        statusBarIcon = statusBarIcon,
+    )
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 033c96ae84b0924e42bbcba800bf60219dde355e..8f36d4f5bf6c4ea1202849b35c813a2a9cd7def3 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
@@ -19,6 +19,8 @@ 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.Flags.FLAG_NOTIFICATIONS_FOOTER_VIEW_REFACTOR;
+import static com.android.systemui.flags.SetFlagsRuleExtensionsKt.setFlagDefault;
 import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;
 import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_GENTLE;
 import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.RUBBER_BAND_FACTOR_NORMAL;
@@ -165,6 +167,11 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
         mFeatureFlags.setDefault(Flags.NOTIFICATION_SHELF_REFACTOR);
         mFeatureFlags.setDefault(Flags.NEW_AOD_TRANSITION);
         mFeatureFlags.setDefault(Flags.UNCLEARED_TRANSIENT_HUN_FIX);
+        // Some tests in this file test the FooterView. Since we're refactoring the FooterView
+        // business logic out of the NSSL, the behavior tested in this file will eventually be
+        // tested directly in the new FooterView stack. For now, we just want to make sure that the
+        // old behavior is preserved when the flag is off.
+        setFlagDefault(mSetFlagsRule, FLAG_NOTIFICATIONS_FOOTER_VIEW_REFACTOR);
 
         // Inject dependencies before initializing the layout
         mDependency.injectTestDependency(FeatureFlags.class, mFeatureFlags);
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 49906dca03442e2fce30bec4bf06fa7d049f8f18..08ef477651748cb02e26e43828e43e8749949444 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
@@ -62,6 +62,10 @@ class StackScrollAlgorithmTest : SysuiTestCase() {
         )
 
     private val testableResources = mContext.getOrCreateTestableResources()
+    private val maxPanelHeight =
+        mContext.resources.displayMetrics.heightPixels -
+                px(R.dimen.notification_panel_margin_top) -
+                px(R.dimen.notification_panel_margin_bottom)
 
     private fun px(@DimenRes id: Int): Float =
             testableResources.resources.getDimensionPixelSize(id).toFloat()
@@ -147,7 +151,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() {
         stackScrollAlgorithm.initView(context)
         hostView.removeAllViews()
         hostView.addView(emptyShadeView)
-        ambientState.layoutMaxHeight = 1280
+        ambientState.layoutMaxHeight = maxPanelHeight.toInt()
 
         stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0)
 
@@ -155,7 +159,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() {
                 context.resources.getDimensionPixelSize(R.dimen.notification_panel_margin_bottom)
         val fullHeight = ambientState.layoutMaxHeight + marginBottom - ambientState.stackY
         val centeredY = ambientState.stackY + fullHeight / 2f - emptyShadeView.height / 2f
-        assertThat(emptyShadeView.viewState?.yTranslation).isEqualTo(centeredY)
+        assertThat(emptyShadeView.viewState.yTranslation).isEqualTo(centeredY)
     }
 
     @Test
@@ -356,7 +360,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() {
         whenever(notificationRow.canViewBeCleared()).thenReturn(false)
         ambientState.isClearAllInProgress = true
         ambientState.isShadeExpanded = true
-        ambientState.stackEndHeight = 1000f // plenty space for the footer in the stack
+        ambientState.stackEndHeight = maxPanelHeight // plenty space for the footer in the stack
         hostView.addView(footerView)
 
         stackScrollAlgorithm.resetViewStates(ambientState, 0)
@@ -370,7 +374,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() {
         whenever(notificationRow.canViewBeCleared()).thenReturn(true)
         ambientState.isClearAllInProgress = true
         ambientState.isShadeExpanded = true
-        ambientState.stackEndHeight = 1000f // plenty space for the footer in the stack
+        ambientState.stackEndHeight = maxPanelHeight // plenty space for the footer in the stack
         hostView.addView(footerView)
 
         stackScrollAlgorithm.resetViewStates(ambientState, 0)
@@ -382,7 +386,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() {
     fun resetViewStates_clearAllInProgress_allRowsRemoved_emptyShade_footerHidden() {
         ambientState.isClearAllInProgress = true
         ambientState.isShadeExpanded = true
-        ambientState.stackEndHeight = 1000f // plenty space for the footer in the stack
+        ambientState.stackEndHeight = maxPanelHeight // plenty space for the footer in the stack
         hostView.removeAllViews() // remove all rows
         hostView.addView(footerView)
 
@@ -1006,7 +1010,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() {
     }
 
     private fun resetViewStates_stackMargin_changesHunYTranslation() {
-        val stackTopMargin = 50
+        val stackTopMargin = bigGap.toInt() // a gap smaller than the headsUpInset
         val headsUpTranslationY = stackScrollAlgorithm.mHeadsUpInset - stackTopMargin
 
         // we need the shelf to mock the real-life behaviour of StackScrollAlgorithm#updateChild
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt
index 68f2728c9acee97a754fcd1c2845c1179aee2654..7de05add288490d379683f3b9cad98b9669264ba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt
@@ -19,11 +19,14 @@ import android.content.Intent
 import android.os.RemoteException
 import android.os.UserHandle
 import android.testing.AndroidTestingRunner
+import android.view.View
+import android.widget.FrameLayout
 import androidx.test.filters.SmallTest
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.systemui.ActivityIntentHelper
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.animation.LaunchableView
 import com.android.systemui.assist.AssistManager
 import com.android.systemui.keyguard.KeyguardViewMediator
 import com.android.systemui.keyguard.WakefulnessLifecycle
@@ -41,6 +44,7 @@ import com.android.systemui.statusbar.window.StatusBarWindowController
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.nullable
 import com.android.systemui.util.mockito.whenever
 import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
@@ -49,6 +53,7 @@ import java.util.Optional
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.Mock
 import org.mockito.Mockito.anyBoolean
 import org.mockito.Mockito.mock
@@ -116,15 +121,50 @@ class ActivityStarterImplTest : SysuiTestCase() {
     @Test
     fun startPendingIntentDismissingKeyguard_keyguardShowing_dismissWithAction() {
         val pendingIntent = mock(PendingIntent::class.java)
+        whenever(pendingIntent.isActivity).thenReturn(true)
         whenever(keyguardStateController.isShowing).thenReturn(true)
         whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
 
         underTest.startPendingIntentDismissingKeyguard(pendingIntent)
+        mainExecutor.runAllReady()
 
         verify(statusBarKeyguardViewManager)
             .dismissWithAction(any(OnDismissAction::class.java), eq(null), anyBoolean(), eq(null))
     }
 
+    @Test
+    fun startPendingIntentMaybeDismissingKeyguard_keyguardShowing_showOverLockscreen_activityLaunchAnimator() {
+        val pendingIntent = mock(PendingIntent::class.java)
+        val parent = FrameLayout(context)
+        val view =
+            object : View(context), LaunchableView {
+                override fun setShouldBlockVisibilityChanges(block: Boolean) {}
+            }
+        parent.addView(view)
+        val controller = ActivityLaunchAnimator.Controller.fromView(view)
+        whenever(pendingIntent.isActivity).thenReturn(true)
+        whenever(keyguardStateController.isShowing).thenReturn(true)
+        whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+        whenever(activityIntentHelper.wouldPendingShowOverLockscreen(eq(pendingIntent), anyInt()))
+            .thenReturn(true)
+
+        underTest.startPendingIntentMaybeDismissingKeyguard(
+            intent = pendingIntent,
+            animationController = controller,
+            intentSentUiThreadCallback = null,
+        )
+        mainExecutor.runAllReady()
+
+        verify(activityLaunchAnimator)
+            .startPendingIntentWithAnimation(
+                nullable(),
+                eq(true),
+                nullable(),
+                eq(true),
+                any(),
+            )
+    }
+
     @Test
     fun startPendingIntentDismissingKeyguard_associatedView_getAnimatorController() {
         val pendingIntent = mock(PendingIntent::class.java)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index cfd220b45f1a0469f0495815b3020f5125553392..164325a431a5644dc0b624b64c0ccd4e207b279c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -140,7 +140,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
         mFeatureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, false);
         when(mKeyguardStateController.isShowing()).thenReturn(true);
         when(mUpdateMonitor.isDeviceInteractive()).thenReturn(true);
-        when(mKeyguardStateController.isFaceAuthEnabled()).thenReturn(true);
+        when(mKeyguardStateController.isFaceEnrolled()).thenReturn(true);
         when(mKeyguardStateController.isUnlocked()).thenReturn(false);
         when(mKeyguardBypassController.onBiometricAuthenticated(any(), anyBoolean()))
                 .thenReturn(true);
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 a59cd87d78da769e34ac3a2f21334bf81630d19b..41eaf858f27a8566340667e1319fe4d11bb01906 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
@@ -158,7 +158,6 @@ import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
-import com.android.systemui.statusbar.notification.data.repository.NotificationExpansionRepository;
 import com.android.systemui.statusbar.notification.init.NotificationsController;
 import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptLogger;
@@ -502,7 +501,6 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
                 (Lazy<NotificationPresenter>) () -> mNotificationPresenter,
                 (Lazy<NotificationActivityStarter>) () -> mNotificationActivityStarter,
                 mNotifLaunchAnimControllerProvider,
-                new NotificationExpansionRepository(),
                 mDozeParameters,
                 mScrimController,
                 mBiometricUnlockControllerLazy,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
index 593c587c0f514d9b5d0bde6b7927d28830b1e937..472709cd622e04ab021f93dbb855685e460d1166 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
@@ -42,6 +42,8 @@ import com.android.systemui.assist.AssistManager;
 import com.android.systemui.biometrics.AuthController;
 import com.android.systemui.doze.DozeHost;
 import com.android.systemui.doze.DozeLog;
+import com.android.systemui.flags.FakeFeatureFlagsClassic;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.keyguard.domain.interactor.DozeInteractor;
 import com.android.systemui.shade.NotificationShadeWindowViewController;
@@ -96,18 +98,21 @@ public class DozeServiceHostTest extends SysuiTestCase {
     @Mock private BiometricUnlockController mBiometricUnlockController;
     @Mock private AuthController mAuthController;
     @Mock private DozeHost.Callback mCallback;
-
     @Mock private DozeInteractor mDozeInteractor;
+
+    private final FakeFeatureFlagsClassic mFeatureFlags = new FakeFeatureFlagsClassic();
+
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
+        mFeatureFlags.setDefault(Flags.NOTIFICATION_ICON_CONTAINER_REFACTOR);
         mDozeServiceHost = new DozeServiceHost(mDozeLog, mPowerManager, mWakefullnessLifecycle,
-                mStatusBarStateController, mDeviceProvisionedController, mHeadsUpManager,
-                mBatteryController, mScrimController, () -> mBiometricUnlockController,
-                () -> mAssistManager, mDozeScrimController,
-                mKeyguardUpdateMonitor, mPulseExpansionHandler,
-                mNotificationShadeWindowController, mNotificationWakeUpCoordinator,
-                mAuthController, mNotificationIconAreaController, mDozeInteractor);
+                mStatusBarStateController, mDeviceProvisionedController, mFeatureFlags,
+                mHeadsUpManager, mBatteryController, mScrimController,
+                () -> mBiometricUnlockController, () -> mAssistManager, mDozeScrimController,
+                mKeyguardUpdateMonitor, mPulseExpansionHandler, mNotificationShadeWindowController,
+                mNotificationWakeUpCoordinator, mAuthController, mNotificationIconAreaController,
+                mDozeInteractor);
 
         mDozeServiceHost.initialize(
                 mCentralSurfaces,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
index d84bb728a856954b8f8a136792d723d9a959affb..529e2c9a8e7ee36cbe650e329fabc2a200b0b2bb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
@@ -34,6 +34,8 @@ import android.widget.TextView;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.flags.FakeFeatureFlagsClassic;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.shade.ShadeHeadsUpTracker;
@@ -42,6 +44,7 @@ import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.HeadsUpStatusBarView;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationIconInteractor;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
 import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager;
@@ -82,10 +85,12 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
     private KeyguardStateController mKeyguardStateController;
     private CommandQueue mCommandQueue;
     private NotificationRoundnessManager mNotificationRoundnessManager;
+    private final FakeFeatureFlagsClassic mFeatureFlags = new FakeFeatureFlagsClassic();
 
     @Before
     public void setUp() throws Exception {
         allowTestableLooperAsMainThread();
+        mFeatureFlags.setDefault(Flags.NOTIFICATION_ICON_CONTAINER_REFACTOR);
         mTestHelper = new NotificationTestHelper(
                 mContext,
                 mDependency,
@@ -119,6 +124,8 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
                 mNotificationRoundnessManager,
                 mHeadsUpStatusBarView,
                 new Clock(mContext, null),
+                mFeatureFlags,
+                mock(HeadsUpNotificationIconInteractor.class),
                 Optional.of(mOperatorNameView));
         mHeadsUpAppearanceController.setAppearFraction(0.0f, 0.0f);
     }
@@ -203,6 +210,7 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
                 mNotificationRoundnessManager,
                 mHeadsUpStatusBarView,
                 new Clock(mContext, null),
+                mFeatureFlags, mock(HeadsUpNotificationIconInteractor.class),
                 Optional.empty());
 
         assertEquals(expandedHeight, newController.mExpandedHeight, 0.0f);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBypassControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBypassControllerTest.kt
index 6209f73f2e92f1f4e2269ee0bbf84067af619eb1..bd0dbeebd7529af597ff89637b584e1e72481d07 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBypassControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBypassControllerTest.kt
@@ -86,7 +86,7 @@ class KeyguardBypassControllerTest : SysuiTestCase() {
         featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true)
 
         whenever(packageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true)
-        whenever(keyguardStateController.isFaceAuthEnabled).thenReturn(true)
+        whenever(keyguardStateController.isFaceEnrolled).thenReturn(true)
     }
 
     @After
@@ -158,7 +158,7 @@ class KeyguardBypassControllerTest : SysuiTestCase() {
         keyguardBypassController.registerOnBypassStateChangedListener(bypassListener)
         verify(keyguardStateController).addCallback(callback.capture())
 
-        callback.value.onFaceAuthEnabledChanged()
+        callback.value.onFaceEnrolledChanged()
         verify(bypassListener).onBypassStateChanged(anyBoolean())
     }
 
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 beac995c893b493797ef8850ec41a6ad5620ad37..1e31977306267d2b972a368fa058a9191e70d7f7 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
@@ -86,7 +86,8 @@ import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorCon
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.provider.LaunchFullScreenIntentProvider;
 import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
-import com.android.systemui.statusbar.notification.data.repository.NotificationExpansionRepository;
+import com.android.systemui.statusbar.notification.data.repository.NotificationLaunchAnimationRepository;
+import com.android.systemui.statusbar.notification.domain.interactor.NotificationLaunchAnimationInteractor;
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
@@ -222,7 +223,8 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
         HeadsUpManager headsUpManager = mock(HeadsUpManager.class);
         NotificationLaunchAnimatorControllerProvider notificationAnimationProvider =
                 new NotificationLaunchAnimatorControllerProvider(
-                        new NotificationExpansionRepository(),
+                        new NotificationLaunchAnimationInteractor(
+                                new NotificationLaunchAnimationRepository()),
                         mock(NotificationListContainer.class),
                         headsUpManager,
                         mJankMonitor);
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 bcb34d6d93421e1c670a82c0745e838e53e17d21..9a77f0c0300dfe801aa5a61213e890a466d521c7 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
@@ -48,23 +48,29 @@ import android.widget.FrameLayout;
 import androidx.test.filters.SmallTest;
 
 import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.systemui.res.R;
 import com.android.systemui.SysuiBaseFragmentTest;
 import com.android.systemui.animation.AnimatorTestRule;
+import com.android.systemui.common.ui.ConfigurationState;
+import com.android.systemui.demomode.DemoModeController;
 import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.FeatureFlagsClassic;
 import com.android.systemui.log.LogBuffer;
 import com.android.systemui.log.LogcatEchoTracker;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.res.R;
 import com.android.systemui.shade.ShadeExpansionStateManager;
 import com.android.systemui.shade.ShadeViewController;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.OperatorNameViewController;
 import com.android.systemui.statusbar.disableflags.DisableFlagsLogger;
 import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
+import com.android.systemui.statusbar.notification.icon.ui.viewbinder.StatusBarNotificationIconViewStore;
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerStatusBarViewModel;
+import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
 import com.android.systemui.statusbar.phone.NotificationIconAreaController;
+import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
 import com.android.systemui.statusbar.phone.StatusBarHideIconsForBouncerManager;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.phone.StatusBarLocationPublisher;
@@ -72,6 +78,7 @@ import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentCom
 import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
 import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.FakeCollapsedStatusBarViewBinder;
 import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.FakeCollapsedStatusBarViewModel;
+import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.window.StatusBarWindowStateController;
 import com.android.systemui.statusbar.window.StatusBarWindowStateListener;
@@ -682,7 +689,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
                 mLocationPublisher,
                 mMockNotificationAreaController,
                 mShadeExpansionStateManager,
-                mock(FeatureFlags.class),
+                mock(FeatureFlagsClassic.class),
                 mStatusBarIconController,
                 mIconManagerFactory,
                 mCollapsedStatusBarViewModel,
@@ -702,7 +709,14 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
                 mExecutor,
                 mDumpManager,
                 mStatusBarWindowStateController,
-                mKeyguardUpdateMonitor);
+                mKeyguardUpdateMonitor,
+                mock(NotificationIconContainerStatusBarViewModel.class),
+                mock(ConfigurationState.class),
+                mock(ConfigurationController.class),
+                mock(DozeParameters.class),
+                mock(ScreenOffAnimationController.class),
+                mock(StatusBarNotificationIconViewStore.class),
+                mock(DemoModeController.class));
     }
 
     private void setUpDaggerComponent() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
index e6b09e36cae999b6292f9c323865a165baae858c..5c960b6633dbdebc378b1403786c419a2d17640d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
@@ -97,20 +97,20 @@ public class KeyguardStateControllerTest extends SysuiTestCase {
     }
 
     @Test
-    public void testFaceAuthEnabledChanged_calledWhenFaceEnrollmentStateChanges() {
+    public void testFaceAuthEnrolleddChanged_calledWhenFaceEnrollmentStateChanges() {
         KeyguardStateController.Callback callback = mock(KeyguardStateController.Callback.class);
 
-        when(mKeyguardUpdateMonitor.isFaceAuthEnabledForUser(anyInt())).thenReturn(false);
+        when(mKeyguardUpdateMonitor.isFaceEnrolled(anyInt())).thenReturn(false);
         verify(mKeyguardUpdateMonitor).registerCallback(mUpdateCallbackCaptor.capture());
         mKeyguardStateController.addCallback(callback);
-        assertThat(mKeyguardStateController.isFaceAuthEnabled()).isFalse();
+        assertThat(mKeyguardStateController.isFaceEnrolled()).isFalse();
 
-        when(mKeyguardUpdateMonitor.isFaceAuthEnabledForUser(anyInt())).thenReturn(true);
+        when(mKeyguardUpdateMonitor.isFaceEnrolled(anyInt())).thenReturn(true);
         mUpdateCallbackCaptor.getValue().onBiometricEnrollmentStateChanged(
                 BiometricSourceType.FACE);
 
-        assertThat(mKeyguardStateController.isFaceAuthEnabled()).isTrue();
-        verify(callback).onFaceAuthEnabledChanged();
+        assertThat(mKeyguardStateController.isFaceEnrolled()).isTrue();
+        verify(callback).onFaceEnrolledChanged();
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/ui/AnimatedValueTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/ui/AnimatedValueTest.kt
index 6e3a732aa8ec1623d498c7b0add88a5f8c4015e1..94100fe7f4c457d0e93b7e6488110963bcce538d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/ui/AnimatedValueTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/ui/AnimatedValueTest.kt
@@ -24,8 +24,6 @@ import com.android.systemui.coroutines.collectLastValue
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.MutableSharedFlow
-import kotlinx.coroutines.flow.emptyFlow
-import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Test
@@ -38,64 +36,193 @@ class AnimatedValueTest : SysuiTestCase() {
     @Test
     fun animatableEvent_updatesValue() = runTest {
         val events = MutableSharedFlow<AnimatableEvent<Int>>()
-        val values = events.toAnimatedValueFlow(completionEvents = emptyFlow())
+        val values = events.toAnimatedValueFlow()
         val value by collectLastValue(values)
         runCurrent()
 
         events.emit(AnimatableEvent(value = 1, startAnimating = false))
 
-        assertThat(value).isEqualTo(AnimatedValue(value = 1, isAnimating = false))
+        assertThat(value?.value).isEqualTo(1)
+        assertThat(value?.isAnimating).isFalse()
     }
 
     @Test
     fun animatableEvent_startAnimation() = runTest {
         val events = MutableSharedFlow<AnimatableEvent<Int>>()
-        val values = events.toAnimatedValueFlow(completionEvents = emptyFlow())
+        val values = events.toAnimatedValueFlow()
         val value by collectLastValue(values)
         runCurrent()
 
         events.emit(AnimatableEvent(value = 1, startAnimating = true))
 
-        assertThat(value).isEqualTo(AnimatedValue(value = 1, isAnimating = true))
+        assertThat(value?.value).isEqualTo(1)
+        assertThat(value?.isAnimating).isTrue()
     }
 
     @Test
     fun animatableEvent_startAnimation_alreadyAnimating() = runTest {
         val events = MutableSharedFlow<AnimatableEvent<Int>>()
-        val values = events.toAnimatedValueFlow(completionEvents = emptyFlow())
+        val values = events.toAnimatedValueFlow()
         val value by collectLastValue(values)
         runCurrent()
 
         events.emit(AnimatableEvent(value = 1, startAnimating = true))
         events.emit(AnimatableEvent(value = 2, startAnimating = true))
 
-        assertThat(value).isEqualTo(AnimatedValue(value = 2, isAnimating = true))
+        assertThat(value?.value).isEqualTo(2)
+        assertThat(value?.isAnimating).isTrue()
     }
 
     @Test
     fun animatedValue_stopAnimating() = runTest {
         val events = MutableSharedFlow<AnimatableEvent<Int>>()
-        val stopEvent = MutableSharedFlow<Unit>()
-        val values = events.toAnimatedValueFlow(completionEvents = stopEvent)
+        val values = events.toAnimatedValueFlow()
         val value by collectLastValue(values)
         runCurrent()
 
         events.emit(AnimatableEvent(value = 1, startAnimating = true))
-        stopEvent.emit(Unit)
+        assertThat(value?.isAnimating).isTrue()
+        value?.stopAnimating()
 
-        assertThat(value).isEqualTo(AnimatedValue(value = 1, isAnimating = false))
+        assertThat(value?.value).isEqualTo(1)
+        assertThat(value?.isAnimating).isFalse()
     }
 
     @Test
-    fun animatedValue_stopAnimating_notAnimating() = runTest {
+    fun animatedValue_stopAnimatingPrevValue_doesNothing() = runTest {
         val events = MutableSharedFlow<AnimatableEvent<Int>>()
-        val stopEvent = MutableSharedFlow<Unit>()
-        val values = events.toAnimatedValueFlow(completionEvents = stopEvent)
-        values.launchIn(backgroundScope)
+        val values = events.toAnimatedValueFlow()
+        val value by collectLastValue(values)
         runCurrent()
 
-        events.emit(AnimatableEvent(value = 1, startAnimating = false))
+        events.emit(AnimatableEvent(value = 1, startAnimating = true))
+        val prevValue = value
+        assertThat(prevValue?.isAnimating).isTrue()
+
+        events.emit(AnimatableEvent(value = 2, startAnimating = true))
+        assertThat(value?.isAnimating).isTrue()
+        prevValue?.stopAnimating()
+
+        assertThat(value?.value).isEqualTo(2)
+        assertThat(value?.isAnimating).isTrue()
+    }
+
+    @Test
+    fun zipValues_applyTransform() {
+        val animating = AnimatedValue.Animating(1) {}
+        val notAnimating = AnimatedValue.NotAnimating(2)
+        val sum = zip(animating, notAnimating) { a, b -> a + b }
+        assertThat(sum.value).isEqualTo(3)
+    }
+
+    @Test
+    fun zipValues_firstIsAnimating_resultIsAnimating() {
+        var stopped = false
+        val animating = AnimatedValue.Animating(1) { stopped = true }
+        val notAnimating = AnimatedValue.NotAnimating(2)
+        val sum = zip(animating, notAnimating) { a, b -> a + b }
+        assertThat(sum.isAnimating).isTrue()
+
+        sum.stopAnimating()
+        assertThat(stopped).isTrue()
+    }
+
+    @Test
+    fun zipValues_secondIsAnimating_resultIsAnimating() {
+        var stopped = false
+        val animating = AnimatedValue.Animating(1) { stopped = true }
+        val notAnimating = AnimatedValue.NotAnimating(2)
+        val sum = zip(notAnimating, animating) { a, b -> a + b }
+        assertThat(sum.isAnimating).isTrue()
+
+        sum.stopAnimating()
+        assertThat(stopped).isTrue()
+    }
+
+    @Test
+    fun zipValues_bothAnimating_resultIsAnimating() {
+        var firstStopped = false
+        var secondStopped = false
+        val first = AnimatedValue.Animating(1) { firstStopped = true }
+        val second = AnimatedValue.Animating(2) { secondStopped = true }
+        val sum = zip(first, second) { a, b -> a + b }
+        assertThat(sum.isAnimating).isTrue()
+
+        sum.stopAnimating()
+        assertThat(firstStopped).isTrue()
+        assertThat(secondStopped).isTrue()
+    }
 
-        assertThat(stopEvent.subscriptionCount.value).isEqualTo(0)
+    @Test
+    fun zipValues_neitherAnimating_resultIsNotAnimating() {
+        val first = AnimatedValue.NotAnimating(1)
+        val second = AnimatedValue.NotAnimating(2)
+        val sum = zip(first, second) { a, b -> a + b }
+        assertThat(sum.isAnimating).isFalse()
+    }
+
+    @Test
+    fun mapAnimatedValue_isAnimating() {
+        var stopped = false
+        val animating = AnimatedValue.Animating(3) { stopped = true }
+        val squared = animating.map { it * it }
+        assertThat(squared.value).isEqualTo(9)
+        assertThat(squared.isAnimating).isTrue()
+        squared.stopAnimating()
+        assertThat(stopped).isTrue()
+    }
+
+    @Test
+    fun mapAnimatedValue_notAnimating() {
+        val notAnimating = AnimatedValue.NotAnimating(3)
+        val squared = notAnimating.map { it * it }
+        assertThat(squared.value).isEqualTo(9)
+        assertThat(squared.isAnimating).isFalse()
+    }
+
+    @Test
+    fun flattenAnimatingValue_neitherAnimating() {
+        val nested = AnimatedValue.NotAnimating(AnimatedValue.NotAnimating(10))
+        val flattened = nested.flatten()
+        assertThat(flattened.value).isEqualTo(10)
+        assertThat(flattened.isAnimating).isFalse()
+    }
+
+    @Test
+    fun flattenAnimatingValue_outerAnimating() {
+        var stopped = false
+        val inner = AnimatedValue.NotAnimating(10)
+        val nested = AnimatedValue.Animating(inner) { stopped = true }
+        val flattened = nested.flatten()
+        assertThat(flattened.value).isEqualTo(10)
+        assertThat(flattened.isAnimating).isTrue()
+        flattened.stopAnimating()
+        assertThat(stopped).isTrue()
+    }
+
+    @Test
+    fun flattenAnimatingValue_innerAnimating() {
+        var stopped = false
+        val inner = AnimatedValue.Animating(10) { stopped = true }
+        val nested = AnimatedValue.NotAnimating(inner)
+        val flattened = nested.flatten()
+        assertThat(flattened.value).isEqualTo(10)
+        assertThat(flattened.isAnimating).isTrue()
+        flattened.stopAnimating()
+        assertThat(stopped).isTrue()
+    }
+
+    @Test
+    fun flattenAnimatingValue_bothAnimating() {
+        var innerStopped = false
+        var outerStopped = false
+        val inner = AnimatedValue.Animating(10) { innerStopped = true }
+        val nested = AnimatedValue.Animating(inner) { outerStopped = true }
+        val flattened = nested.flatten()
+        assertThat(flattened.value).isEqualTo(10)
+        assertThat(flattened.isAnimating).isTrue()
+        flattened.stopAnimating()
+        assertThat(innerStopped).isTrue()
+        assertThat(outerStopped).isTrue()
     }
 }
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index 65975e44ee2a36b1e51b582d38936dca23d35b75..76ebdf4d4c1ccc430ad1f2eedd3cb142e3eee4e4 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -103,9 +103,8 @@ import com.android.internal.os.BackgroundThread;
 import com.android.internal.os.IResultReceiver;
 import com.android.internal.util.DumpUtils;
 import com.android.server.LocalServices;
-import com.android.server.contentprotection.ContentProtectionBlocklistManager;
+import com.android.server.contentprotection.ContentProtectionAllowlistManager;
 import com.android.server.contentprotection.ContentProtectionConsentManager;
-import com.android.server.contentprotection.ContentProtectionPackageManager;
 import com.android.server.contentprotection.RemoteContentProtectionService;
 import com.android.server.infra.AbstractMasterSystemService;
 import com.android.server.infra.FrameworkResourcesServiceNameResolver;
@@ -206,9 +205,6 @@ public class ContentCaptureManagerService extends
     @GuardedBy("mLock")
     boolean mDevCfgEnableContentProtectionReceiver;
 
-    @GuardedBy("mLock")
-    int mDevCfgContentProtectionAppsBlocklistSize;
-
     @GuardedBy("mLock")
     int mDevCfgContentProtectionBufferSize;
 
@@ -237,7 +233,7 @@ public class ContentCaptureManagerService extends
 
     @Nullable private final ComponentName mContentProtectionServiceComponentName;
 
-    @Nullable private final ContentProtectionBlocklistManager mContentProtectionBlocklistManager;
+    @Nullable private final ContentProtectionAllowlistManager mContentProtectionAllowlistManager;
 
     @Nullable private final ContentProtectionConsentManager mContentProtectionConsentManager;
 
@@ -287,17 +283,15 @@ public class ContentCaptureManagerService extends
         if (getEnableContentProtectionReceiverLocked()) {
             mContentProtectionServiceComponentName = getContentProtectionServiceComponentName();
             if (mContentProtectionServiceComponentName != null) {
-                mContentProtectionBlocklistManager = createContentProtectionBlocklistManager();
-                mContentProtectionBlocklistManager.updateBlocklist(
-                        mDevCfgContentProtectionAppsBlocklistSize);
+                mContentProtectionAllowlistManager = createContentProtectionAllowlistManager();
                 mContentProtectionConsentManager = createContentProtectionConsentManager();
             } else {
-                mContentProtectionBlocklistManager = null;
+                mContentProtectionAllowlistManager = null;
                 mContentProtectionConsentManager = null;
             }
         } else {
             mContentProtectionServiceComponentName = null;
-            mContentProtectionBlocklistManager = null;
+            mContentProtectionAllowlistManager = null;
             mContentProtectionConsentManager = null;
         }
     }
@@ -445,8 +439,6 @@ public class ContentCaptureManagerService extends
                 case ContentCaptureManager
                         .DEVICE_CONFIG_PROPERTY_ENABLE_CONTENT_PROTECTION_RECEIVER:
                 case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_BUFFER_SIZE:
-                case ContentCaptureManager
-                        .DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_APPS_BLOCKLIST_SIZE:
                 case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_REQUIRED_GROUPS_CONFIG:
                 case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_CONFIG:
                 case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_THRESHOLD:
@@ -502,14 +494,6 @@ public class ContentCaptureManagerService extends
                             ContentCaptureManager
                                     .DEVICE_CONFIG_PROPERTY_ENABLE_CONTENT_PROTECTION_RECEIVER,
                             ContentCaptureManager.DEFAULT_ENABLE_CONTENT_PROTECTION_RECEIVER);
-            mDevCfgContentProtectionAppsBlocklistSize =
-                    DeviceConfig.getInt(
-                            DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
-                            ContentCaptureManager
-                                    .DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_APPS_BLOCKLIST_SIZE,
-                            ContentCaptureManager.DEFAULT_CONTENT_PROTECTION_APPS_BLOCKLIST_SIZE);
-            // mContentProtectionBlocklistManager.updateBlocklist not called on purpose here to keep
-            // it immutable at this point
             mDevCfgContentProtectionBufferSize =
                     DeviceConfig.getInt(
                             DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
@@ -542,7 +526,7 @@ public class ContentCaptureManagerService extends
                                 + mDevCfgMaxBufferSize
                                 + ", idleFlush="
                                 + mDevCfgIdleFlushingFrequencyMs
-                                + ", textFluxh="
+                                + ", textFlush="
                                 + mDevCfgTextChangeFlushingFrequencyMs
                                 + ", logHistory="
                                 + mDevCfgLogHistorySize
@@ -552,8 +536,6 @@ public class ContentCaptureManagerService extends
                                 + mDevCfgDisableFlushForViewTreeAppearing
                                 + ", enableContentProtectionReceiver="
                                 + mDevCfgEnableContentProtectionReceiver
-                                + ", contentProtectionAppsBlocklistSize="
-                                + mDevCfgContentProtectionAppsBlocklistSize
                                 + ", contentProtectionBufferSize="
                                 + mDevCfgContentProtectionBufferSize
                                 + ", contentProtectionRequiredGroupsConfig="
@@ -844,9 +826,6 @@ public class ContentCaptureManagerService extends
         pw.print("enableContentProtectionReceiver: ");
         pw.println(mDevCfgEnableContentProtectionReceiver);
         pw.print(prefix2);
-        pw.print("contentProtectionAppsBlocklistSize: ");
-        pw.println(mDevCfgContentProtectionAppsBlocklistSize);
-        pw.print(prefix2);
         pw.print("contentProtectionBufferSize: ");
         pw.println(mDevCfgContentProtectionBufferSize);
         pw.print(prefix2);
@@ -877,9 +856,8 @@ public class ContentCaptureManagerService extends
     /** @hide */
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
     @NonNull
-    protected ContentProtectionBlocklistManager createContentProtectionBlocklistManager() {
-        return new ContentProtectionBlocklistManager(
-                new ContentProtectionPackageManager(getContext()));
+    protected ContentProtectionAllowlistManager createContentProtectionAllowlistManager() {
+        return new ContentProtectionAllowlistManager();
     }
 
     /** @hide */
@@ -1429,7 +1407,7 @@ public class ContentCaptureManagerService extends
         private boolean isContentProtectionReceiverEnabled(
                 @UserIdInt int userId, @NonNull String packageName) {
             if (mContentProtectionServiceComponentName == null
-                    || mContentProtectionBlocklistManager == null
+                    || mContentProtectionAllowlistManager == null
                     || mContentProtectionConsentManager == null) {
                 return false;
             }
@@ -1443,7 +1421,7 @@ public class ContentCaptureManagerService extends
                 }
             }
             return mContentProtectionConsentManager.isConsentGranted(userId)
-                    && mContentProtectionBlocklistManager.isAllowed(packageName);
+                    && mContentProtectionAllowlistManager.isAllowed(packageName);
         }
     }
 
diff --git a/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionAllowlistManager.java b/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionAllowlistManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..59af5263fa9e8eddf445485d1274782c90d5e094
--- /dev/null
+++ b/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionAllowlistManager.java
@@ -0,0 +1,38 @@
+/*
+ * 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.server.contentprotection;
+
+import android.annotation.NonNull;
+import android.util.Slog;
+
+/**
+ * Manages whether the content protection is enabled for an app using a allowlist.
+ *
+ * @hide
+ */
+public class ContentProtectionAllowlistManager {
+
+    private static final String TAG = "ContentProtectionAllowlistManager";
+
+    public ContentProtectionAllowlistManager() {}
+
+    /** Returns true if the package is allowed. */
+    public boolean isAllowed(@NonNull String packageName) {
+        Slog.v(TAG, packageName);
+        return false;
+    }
+}
diff --git a/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionBlocklistManager.java b/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionBlocklistManager.java
deleted file mode 100644
index a0fd28b3f27992b7f58ef5cc39c14533c395b3a2..0000000000000000000000000000000000000000
--- a/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionBlocklistManager.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * 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.server.contentprotection;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.pm.PackageInfo;
-import android.util.Slog;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.io.BufferedReader;
-import java.io.FileReader;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-/**
- * Manages whether the content protection is enabled for an app using a blocklist.
- *
- * @hide
- */
-public class ContentProtectionBlocklistManager {
-
-    private static final String TAG = "ContentProtectionBlocklistManager";
-
-    private static final String PACKAGE_NAME_BLOCKLIST_FILENAME =
-            "/product/etc/res/raw/content_protection/package_name_blocklist.txt";
-
-    @NonNull private final ContentProtectionPackageManager mContentProtectionPackageManager;
-
-    @Nullable private Set<String> mPackageNameBlocklist;
-
-    public ContentProtectionBlocklistManager(
-            @NonNull ContentProtectionPackageManager contentProtectionPackageManager) {
-        mContentProtectionPackageManager = contentProtectionPackageManager;
-    }
-
-    public boolean isAllowed(@NonNull String packageName) {
-        if (mPackageNameBlocklist == null) {
-            // List not loaded or failed to load, don't run on anything
-            return false;
-        }
-        if (mPackageNameBlocklist.contains(packageName)) {
-            return false;
-        }
-        PackageInfo packageInfo = mContentProtectionPackageManager.getPackageInfo(packageName);
-        if (packageInfo == null) {
-            return false;
-        }
-        if (!mContentProtectionPackageManager.hasRequestedInternetPermissions(packageInfo)) {
-            return false;
-        }
-        if (mContentProtectionPackageManager.isSystemApp(packageInfo)) {
-            return false;
-        }
-        if (mContentProtectionPackageManager.isUpdatedSystemApp(packageInfo)) {
-            return false;
-        }
-        return true;
-    }
-
-    public void updateBlocklist(int blocklistSize) {
-        Slog.i(TAG, "Blocklist size updating to: " + blocklistSize);
-        mPackageNameBlocklist = readPackageNameBlocklist(blocklistSize);
-    }
-
-    @Nullable
-    private Set<String> readPackageNameBlocklist(int blocklistSize) {
-        if (blocklistSize <= 0) {
-            // Explicitly requested an empty blocklist
-            return Collections.emptySet();
-        }
-        List<String> lines = readLinesFromRawFile(PACKAGE_NAME_BLOCKLIST_FILENAME);
-        if (lines == null) {
-            return null;
-        }
-        return lines.stream().limit(blocklistSize).collect(Collectors.toSet());
-    }
-
-    @VisibleForTesting
-    @Nullable
-    protected List<String> readLinesFromRawFile(@NonNull String filename) {
-        try (FileReader fileReader = new FileReader(filename);
-                BufferedReader bufferedReader = new BufferedReader(fileReader)) {
-            return bufferedReader
-                    .lines()
-                    .map(line -> line.trim())
-                    .filter(line -> !line.isBlank())
-                    .collect(Collectors.toList());
-        } catch (Exception ex) {
-            Slog.e(TAG, "Failed to read: " + filename, ex);
-            return null;
-        }
-    }
-}
diff --git a/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionPackageManager.java b/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionPackageManager.java
deleted file mode 100644
index 4ebac07ec3ea71fc27bf6418a017ab99d9608231..0000000000000000000000000000000000000000
--- a/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionPackageManager.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * 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.server.contentprotection;
-
-import android.Manifest;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.PackageManager.PackageInfoFlags;
-import android.util.Slog;
-
-import java.util.Arrays;
-
-/**
- * Basic package manager for content protection using content capture.
- *
- * @hide
- */
-public class ContentProtectionPackageManager {
-
-    private static final String TAG = "ContentProtectionPackageManager";
-
-    private static final PackageInfoFlags PACKAGE_INFO_FLAGS =
-            PackageInfoFlags.of(PackageManager.GET_PERMISSIONS);
-
-    @NonNull private final PackageManager mPackageManager;
-
-    public ContentProtectionPackageManager(@NonNull Context context) {
-        mPackageManager = context.getPackageManager();
-    }
-
-    @Nullable
-    public PackageInfo getPackageInfo(@NonNull String packageName) {
-        try {
-            return mPackageManager.getPackageInfo(packageName, PACKAGE_INFO_FLAGS);
-        } catch (NameNotFoundException ex) {
-            Slog.w(TAG, "Package info not found for: " + packageName, ex);
-            return null;
-        }
-    }
-
-    public boolean isSystemApp(@NonNull PackageInfo packageInfo) {
-        return packageInfo.applicationInfo != null && isSystemApp(packageInfo.applicationInfo);
-    }
-
-    private boolean isSystemApp(@NonNull ApplicationInfo applicationInfo) {
-        return (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
-    }
-
-    public boolean isUpdatedSystemApp(@NonNull PackageInfo packageInfo) {
-        return packageInfo.applicationInfo != null
-                && isUpdatedSystemApp(packageInfo.applicationInfo);
-    }
-
-    private boolean isUpdatedSystemApp(@NonNull ApplicationInfo applicationInfo) {
-        return (applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
-    }
-
-    public boolean hasRequestedInternetPermissions(@NonNull PackageInfo packageInfo) {
-        return packageInfo.requestedPermissions != null
-                && Arrays.asList(packageInfo.requestedPermissions)
-                        .contains(Manifest.permission.INTERNET);
-    }
-}
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 4dca5a5c807b8f5d481f1b151bdf179e09bf3bcf..975b1e830ba6c9614c058afd30cecb254a298328 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -205,6 +205,7 @@ java_library_static {
         "com.android.sysprop.watchdog",
         "ImmutabilityAnnotation",
         "securebox",
+        "android.content.pm.flags-aconfig-java",
         "apache-commons-math",
         "backstage_power_flags_lib",
         "notification_flags_lib",
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index bdb5d9356a0d9d41bc8c30348b8f0126e74f1a8f..ef67cbe5024b32b2e62a87d80b0465f66e30a3e4 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -77,8 +77,10 @@ import static android.os.IServiceManager.DUMP_FLAG_PROTO;
 import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
 import static android.os.PowerExemptionManager.REASON_ACTIVITY_VISIBILITY_GRACE_PERIOD;
 import static android.os.PowerExemptionManager.REASON_BACKGROUND_ACTIVITY_PERMISSION;
+import static android.os.PowerExemptionManager.REASON_BOOT_COMPLETED;
 import static android.os.PowerExemptionManager.REASON_COMPANION_DEVICE_MANAGER;
 import static android.os.PowerExemptionManager.REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION;
+import static android.os.PowerExemptionManager.REASON_LOCKED_BOOT_COMPLETED;
 import static android.os.PowerExemptionManager.REASON_PROC_STATE_BTOP;
 import static android.os.PowerExemptionManager.REASON_PROC_STATE_PERSISTENT;
 import static android.os.PowerExemptionManager.REASON_PROC_STATE_PERSISTENT_UI;
@@ -4840,6 +4842,7 @@ public class ActivityManagerService extends IActivityManager.Stub
             if (!mConstants.mEnableWaitForFinishAttachApplication) {
                 finishAttachApplicationInner(startSeq, callingUid, pid);
             }
+            maybeSendBootCompletedLocked(app);
         } catch (Exception e) {
             // We need kill the process group here. (b/148588589)
             Slog.wtf(TAG, "Exception thrown during bind of " + app, e);
@@ -5066,6 +5069,45 @@ public class ActivityManagerService extends IActivityManager.Stub
         }
     }
 
+    /**
+     * Send LOCKED_BOOT_COMPLETED and BOOT_COMPLETED to the package explicitly when unstopped
+     */
+    private void maybeSendBootCompletedLocked(ProcessRecord app) {
+        // Nothing to do if it wasn't previously stopped
+        if (!android.content.pm.Flags.stayStopped() || !app.wasForceStopped()) return;
+
+        // Send LOCKED_BOOT_COMPLETED, if necessary
+        if (app.getApplicationInfo().isEncryptionAware()) {
+            sendBootBroadcastToAppLocked(app, new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED),
+                    REASON_LOCKED_BOOT_COMPLETED);
+        }
+        // Send BOOT_COMPLETED if the user is unlocked
+        if (StorageManager.isUserKeyUnlocked(app.userId)) {
+            sendBootBroadcastToAppLocked(app, new Intent(Intent.ACTION_BOOT_COMPLETED),
+                    REASON_BOOT_COMPLETED);
+        }
+        app.setWasForceStopped(false);
+    }
+
+    /** Send a boot_completed broadcast to app */
+    private void sendBootBroadcastToAppLocked(ProcessRecord app, Intent intent,
+            @PowerExemptionManager.ReasonCode int reason) {
+        intent.setPackage(app.info.packageName);
+        intent.putExtra(Intent.EXTRA_USER_HANDLE, app.userId);
+        intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
+                | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
+                | Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
+        final BroadcastOptions bOptions = mUserController.getTemporaryAppAllowlistBroadcastOptions(
+                reason);
+
+        broadcastIntentLocked(null, null, null, intent, null, null, 0, null, null,
+                new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
+                null, null, AppOpsManager.OP_NONE,
+                bOptions.toBundle(), true,
+                false, MY_PID, SYSTEM_UID,
+                SYSTEM_UID, MY_PID, app.userId);
+    }
+
     @Override
     public void showBootMessage(final CharSequence msg, final boolean always) {
         if (Binder.getCallingUid() != myUid()) {
diff --git a/services/core/java/com/android/server/am/LowMemDetector.java b/services/core/java/com/android/server/am/LowMemDetector.java
index 8f791331f0cf3dbe4d4aa8e924d7d18ec23510b4..016d3cddae31863010ff9cf7a3ca6fb409b305ce 100644
--- a/services/core/java/com/android/server/am/LowMemDetector.java
+++ b/services/core/java/com/android/server/am/LowMemDetector.java
@@ -23,6 +23,7 @@ import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_NOR
 import static com.android.internal.app.procstats.ProcessStats.ADJ_NOTHING;
 
 import android.annotation.IntDef;
+import android.os.Trace;
 
 import com.android.internal.annotations.GuardedBy;
 
@@ -90,17 +91,31 @@ public final class LowMemDetector {
     private native int waitForPressure();
 
     private final class LowMemThread extends Thread {
+        private boolean mIsTracingMemCriticalLow;
+
+        LowMemThread() {
+            super("LowMemThread");
+        }
+
         public void run() {
 
             while (true) {
                 // sleep waiting for a PSI event
                 int newPressureState = waitForPressure();
+                // PSI event detected
+                boolean isCriticalLowMemory = newPressureState == ADJ_MEM_FACTOR_CRITICAL;
+                if (isCriticalLowMemory && !mIsTracingMemCriticalLow) {
+                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "criticalLowMemory");
+                } else if (!isCriticalLowMemory && mIsTracingMemCriticalLow) {
+                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+                }
+                mIsTracingMemCriticalLow = isCriticalLowMemory;
                 if (newPressureState == -1) {
                     // epoll broke, tear this down
                     mAvailable = false;
                     break;
                 }
-                // got a PSI event? let's update lowmem info
+                // got an actual PSI event? let's update lowmem info
                 synchronized (mPressureStateLock) {
                     mPressureState = newPressureState;
                 }
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 59d8e7e96ba62283dbb42366bdc96eeb01f9394b..f04198ed39ec6e51a63dd89c9357974b95a5165f 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -3257,6 +3257,17 @@ public final class ProcessList {
                 hostingRecord.getDefiningUid(), hostingRecord.getDefiningProcessName());
         final ProcessStateRecord state = r.mState;
 
+        // Check if we should mark the processrecord for first launch after force-stopping
+        if ((r.getApplicationInfo().flags & ApplicationInfo.FLAG_STOPPED) != 0) {
+            final boolean wasPackageEverLaunched = mService.getPackageManagerInternal()
+                    .wasPackageEverLaunched(r.getApplicationInfo().packageName, r.userId);
+            // If the package was launched in the past but is currently stopped, only then it
+            // should be considered as stopped after use. Do not mark it if it's the first launch.
+            if (wasPackageEverLaunched) {
+                r.setWasForceStopped(true);
+            }
+        }
+
         if (!isolated && !isSdkSandbox
                 && userId == UserHandle.USER_SYSTEM
                 && (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index f02b8c737f90c7376feb633b9c70167e2a6710e8..2c6e598ef0a4a5d40e3e315f7637870ad6ccaa02 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -438,6 +438,9 @@ class ProcessRecord implements WindowProcessListener {
 
     final ProcessRecordNode[] mLinkedNodes = new ProcessRecordNode[NUM_NODE_TYPE];
 
+    /** Whether the app was launched from a stopped state and is being unstopped. */
+    volatile boolean mWasForceStopped;
+
     void setStartParams(int startUid, HostingRecord hostingRecord, String seInfo,
             long startUptime, long startElapsedTime) {
         this.mStartUid = startUid;
@@ -1602,4 +1605,12 @@ class ProcessRecord implements WindowProcessListener {
     List<ProcessRecord> getLruProcessList() {
         return mService.mProcessList.getLruProcessesLOSP();
     }
+
+    public void setWasForceStopped(boolean stopped) {
+        mWasForceStopped = stopped;
+    }
+
+    public boolean wasForceStopped() {
+        return mWasForceStopped;
+    }
 }
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index de4ad20bdcccd9363551db9888fcfc5adf546169..0dd579fd0b154f263ab8524e25a665c36ca0903d 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -3387,7 +3387,7 @@ class UserController implements Handler.Callback {
 
     }
 
-    private BroadcastOptions getTemporaryAppAllowlistBroadcastOptions(
+    BroadcastOptions getTemporaryAppAllowlistBroadcastOptions(
             @PowerWhitelistManager.ReasonCode int reasonCode) {
         long duration = 10_000;
         final ActivityManagerInternal amInternal =
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 74b7f0866b5484153a6d18bcd81ba4ba330a8d58..323cdc54edae6f584fca783e1b80dab2a5810bd8 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -474,13 +474,14 @@ public class LocationManagerService extends ILocationManager.Stub implements
                 // If we have a GNSS provider override, add the hardware provider as a standalone
                 // option for use by apps with the correct permission. Note the GNSS HAL can only
                 // support a single client, so mGnssManagerService.getGnssLocationProvider() can
-                // only be installed with a single provider.
+                // only be installed with a single provider. Locations from this provider won't
+                // be reported through the passive provider.
                 LocationProviderManager gnssHardwareManager =
                         new LocationProviderManager(
                                 mContext,
                                 mInjector,
                                 GPS_HARDWARE_PROVIDER,
-                                mPassiveManager,
+                                /*passiveManager=*/ null,
                                 Collections.singletonList(Manifest.permission.LOCATION_HARDWARE));
                 addLocationProviderManager(
                         gnssHardwareManager, mGnssManagerService.getGnssLocationProvider());
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 30017be96085106e9d3c2fe12081ddd6316c988b..510c06e9509e95fde589ad66f629dcb4b5ff7459 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -24,7 +24,6 @@ import static android.content.ContentProvider.isAuthorityRedirectedForCloneProfi
 import static android.content.Intent.ACTION_MAIN;
 import static android.content.Intent.CATEGORY_DEFAULT;
 import static android.content.Intent.CATEGORY_HOME;
-import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE;
 import static android.content.pm.PackageManager.CERT_INPUT_RAW_X509;
 import static android.content.pm.PackageManager.CERT_INPUT_SHA256;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
@@ -1525,9 +1524,6 @@ public class ComputerEngine implements Computer {
             ai.secondaryCpuAbi = ps.getSecondaryCpuAbiLegacy();
             ai.volumeUuid = ps.getVolumeUuid();
             ai.storageUuid = StorageManager.convert(ai.volumeUuid);
-            if (ps.isDefaultToDeviceProtectedStorage()) {
-                ai.privateFlags |= PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE;
-            }
             ai.setVersionCode(ps.getVersionCode());
             ai.flags = ps.getFlags();
             ai.privateFlags = ps.getPrivateFlags();
@@ -4596,6 +4592,7 @@ public class ComputerEngine implements Computer {
         flags = updateFlagsForApplication(flags, userId);
         final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0;
         final boolean listApex = (flags & MATCH_APEX) != 0;
+        final boolean listArchivedOnly = !listUninstalled && (flags & MATCH_ARCHIVED_PACKAGES) != 0;
 
         enforceCrossUserPermission(
                 callingUid,
@@ -4607,7 +4604,7 @@ public class ComputerEngine implements Computer {
         ArrayList<ApplicationInfo> list;
         final ArrayMap<String, ? extends PackageStateInternal> packageStates =
                 getPackageStates();
-        if (listUninstalled) {
+        if (listUninstalled || listArchivedOnly) {
             list = new ArrayList<>(packageStates.size());
             for (PackageStateInternal ps : packageStates.values()) {
                 ApplicationInfo ai;
@@ -4619,6 +4616,11 @@ public class ComputerEngine implements Computer {
                     if (!listApex && ps.getPkg().isApex()) {
                         continue;
                     }
+                    PackageUserStateInternal userState = ps.getUserStateOrDefault(userId);
+                    if (listArchivedOnly && !userState.isInstalled()
+                            && userState.getArchiveState() == null) {
+                        continue;
+                    }
                     if (filterSharedLibPackage(ps, callingUid, userId, flags)) {
                         continue;
                     }
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index a5c5ae2702614df996adccbd0e84557de6929d4a..7cac870088d8335d2b9d8495900cfe045af55a93 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -1630,7 +1630,8 @@ final class InstallPackageHelper {
                 synchronized (mPm.mLock) {
                     if (DEBUG_INSTALL) {
                         Slog.d(TAG,
-                                "replacePackageLI: new=" + parsedPackage + ", old=" + oldPackage);
+                                "replacePackageLI: new=" + parsedPackage
+                                        + ", old=" + oldPackageState.getName());
                     }
 
                     ps = mPm.mSettings.getPackageLPr(pkgName11);
@@ -1789,7 +1790,7 @@ final class InstallPackageHelper {
 
                     if (DEBUG_INSTALL) {
                         Slog.d(TAG, "replaceSystemPackageLI: new=" + parsedPackage
-                                + ", old=" + oldPackage);
+                                + ", old=" + oldPackageState.getName());
                     }
                     request.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
                     request.setApexModuleName(oldPackageState.getApexModuleName());
@@ -1799,7 +1800,7 @@ final class InstallPackageHelper {
                     if (DEBUG_INSTALL) {
                         Slog.d(TAG,
                                 "replaceNonSystemPackageLI: new=" + parsedPackage + ", old="
-                                        + oldPackage);
+                                        + oldPackageState.getName());
                     }
                 }
             } else { // new package install
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 1135466ae1d4d36e5aba2aa92fffe78e28047414..c260be9a51245c51b1d5b282b7f5815d92d4f721 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -56,6 +56,7 @@ import android.content.IntentSender;
 import android.content.LocusId;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.Flags;
 import android.content.pm.ILauncherApps;
 import android.content.pm.IOnAppsChangedListener;
 import android.content.pm.IPackageInstallerCallback;
@@ -94,6 +95,7 @@ import android.os.ShellCommand;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.Pair;
@@ -112,6 +114,8 @@ import com.android.internal.util.SizedInputStream;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.pm.pkg.AndroidPackage;
+import com.android.server.pm.pkg.ArchiveState;
+import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.wm.ActivityTaskManagerInternal;
 
 import java.io.DataInputStream;
@@ -513,18 +517,27 @@ public class LauncherAppsService extends SystemService {
 
         @Override
         public ParceledListSlice<LauncherActivityInfoInternal> getLauncherActivities(
-                String callingPackage, String packageName, UserHandle user) throws RemoteException {
+                String callingPackage, @Nullable String packageName, UserHandle user)
+                throws RemoteException {
             ParceledListSlice<LauncherActivityInfoInternal> launcherActivities =
-                    queryActivitiesForUser(callingPackage,
+                    queryActivitiesForUser(
+                            callingPackage,
                             new Intent(Intent.ACTION_MAIN)
                                     .addCategory(Intent.CATEGORY_LAUNCHER)
                                     .setPackage(packageName),
                             user);
-            if (Settings.Global.getInt(mContext.getContentResolver(),
-                    Settings.Global.SHOW_HIDDEN_LAUNCHER_ICON_APPS_ENABLED, 1) == 0) {
+            if (Flags.archiving()) {
+                launcherActivities =
+                        getActivitiesForArchivedApp(packageName, user, launcherActivities);
+            }
+            if (Settings.Global.getInt(
+                            mContext.getContentResolver(),
+                            Settings.Global.SHOW_HIDDEN_LAUNCHER_ICON_APPS_ENABLED,
+                            1)
+                    == 0) {
                 return launcherActivities;
             }
-            if (launcherActivities == null) {
+            if (launcherActivities == null || launcherActivities.getList().isEmpty()) {
                 // Cannot access profile, so we don't even return any hidden apps.
                 return null;
             }
@@ -565,15 +578,16 @@ public class LauncherAppsService extends SystemService {
                     visiblePackages.add(info.getActivityInfo().packageName);
                 }
                 final List<ApplicationInfo> installedPackages =
-                        mPackageManagerInternal.getInstalledApplications(/* flags= */ 0,
-                                user.getIdentifier(), callingUid);
+                        mPackageManagerInternal.getInstalledApplications(
+                                /* flags= */ 0, user.getIdentifier(), callingUid);
                 for (ApplicationInfo applicationInfo : installedPackages) {
                     if (!visiblePackages.contains(applicationInfo.packageName)) {
                         if (!shouldShowSyntheticActivity(user, applicationInfo)) {
                             continue;
                         }
-                        LauncherActivityInfoInternal info = getHiddenAppActivityInfo(
-                                applicationInfo.packageName, callingUid, user);
+                        LauncherActivityInfoInternal info =
+                                getHiddenAppActivityInfo(
+                                        applicationInfo.packageName, callingUid, user);
                         if (info != null) {
                             result.add(info);
                         }
@@ -585,6 +599,23 @@ public class LauncherAppsService extends SystemService {
             }
         }
 
+        private ParceledListSlice<LauncherActivityInfoInternal> getActivitiesForArchivedApp(
+                @Nullable String packageName,
+                UserHandle user,
+                ParceledListSlice<LauncherActivityInfoInternal> launcherActivities) {
+            final List<LauncherActivityInfoInternal> archivedActivities =
+                    generateLauncherActivitiesForArchivedApp(packageName, user);
+            if (archivedActivities.isEmpty()) {
+                return launcherActivities;
+            }
+            if (launcherActivities == null) {
+                return new ParceledListSlice(archivedActivities);
+            }
+            List<LauncherActivityInfoInternal> result = launcherActivities.getList();
+            result.addAll(archivedActivities);
+            return new ParceledListSlice(result);
+        }
+
         private boolean shouldShowSyntheticActivity(UserHandle user, ApplicationInfo appInfo) {
             if (appInfo == null || appInfo.isSystemApp() || appInfo.isUpdatedSystemApp()) {
                 return false;
@@ -650,23 +681,30 @@ public class LauncherAppsService extends SystemService {
                 return null;
             }
 
+            if (component == null || component.getPackageName() == null) {
+                // should not happen
+                return null;
+            }
+
             final int callingUid = injectBinderCallingUid();
             final long ident = Binder.clearCallingIdentity();
             try {
-                final ActivityInfo activityInfo = mPackageManagerInternal.getActivityInfo(component,
-                        PackageManager.MATCH_DIRECT_BOOT_AWARE
-                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
-                        callingUid, user.getIdentifier());
+                ActivityInfo activityInfo =
+                        mPackageManagerInternal.getActivityInfo(
+                                component,
+                                PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+                                callingUid,
+                                user.getIdentifier());
                 if (activityInfo == null) {
-                    return null;
-                }
-                if (component == null || component.getPackageName() == null) {
-                    // should not happen
+                    if (Flags.archiving()) {
+                        return getMatchingArchivedAppActivityInfo(component, user);
+                    }
                     return null;
                 }
                 final IncrementalStatesInfo incrementalStatesInfo =
-                        mPackageManagerInternal.getIncrementalStatesInfo(component.getPackageName(),
-                                callingUid, user.getIdentifier());
+                        mPackageManagerInternal.getIncrementalStatesInfo(
+                                component.getPackageName(), callingUid, user.getIdentifier());
                 if (incrementalStatesInfo == null) {
                     // package does not exist; should not happen
                     return null;
@@ -677,6 +715,26 @@ public class LauncherAppsService extends SystemService {
             }
         }
 
+        private @Nullable LauncherActivityInfoInternal getMatchingArchivedAppActivityInfo(
+                @NonNull ComponentName component, UserHandle user) {
+            List<LauncherActivityInfoInternal> archivedActivities =
+                    generateLauncherActivitiesForArchivedApp(component.getPackageName(), user);
+            if (archivedActivities.isEmpty()) {
+                return null;
+            }
+            for (int i = 0; i < archivedActivities.size(); i++) {
+                if (archivedActivities.get(i).getComponentName().equals(component)) {
+                    return archivedActivities.get(i);
+                }
+            }
+            Slog.w(
+                    TAG,
+                    TextUtils.formatSimple(
+                            "Expected archived app component name: %s" + " is not available!",
+                            component));
+            return null;
+        }
+
         @Override
         public ParceledListSlice getShortcutConfigActivities(
                 String callingPackage, String packageName, UserHandle user)
@@ -700,6 +758,96 @@ public class LauncherAppsService extends SystemService {
             }
         }
 
+        @NonNull
+        private List<LauncherActivityInfoInternal> generateLauncherActivitiesForArchivedApp(
+                @Nullable String packageName, UserHandle user) {
+            List<ApplicationInfo> applicationInfoList =
+                    (packageName == null)
+                            ? getApplicationInfoListForAllArchivedApps(user)
+                            : getApplicationInfoForArchivedApp(packageName, user);
+            List<LauncherActivityInfoInternal> launcherActivityList = new ArrayList<>();
+            for (int i = 0; i < applicationInfoList.size(); i++) {
+                ApplicationInfo applicationInfo = applicationInfoList.get(i);
+                PackageStateInternal packageState =
+                        mPackageManagerInternal.getPackageStateInternal(
+                                applicationInfo.packageName);
+                if (packageState == null) {
+                    continue;
+                }
+                ArchiveState archiveState =
+                        packageState.getUserStateOrDefault(user.getIdentifier()).getArchiveState();
+                if (archiveState == null) {
+                    Slog.w(
+                            TAG,
+                            TextUtils.formatSimple(
+                                    "Expected package: %s to be archived but missing ArchiveState"
+                                            + " in PackageState.",
+                                    applicationInfo.packageName));
+                    continue;
+                }
+                List<ArchiveState.ArchiveActivityInfo> archiveActivityInfoList =
+                        archiveState.getActivityInfos();
+                for (int j = 0; j < archiveActivityInfoList.size(); j++) {
+                    launcherActivityList.add(
+                            constructLauncherActivityInfoForArchivedApp(
+                                    user, applicationInfo, archiveActivityInfoList.get(j)));
+                }
+            }
+            return launcherActivityList;
+        }
+
+        private static LauncherActivityInfoInternal constructLauncherActivityInfoForArchivedApp(
+                UserHandle user,
+                ApplicationInfo applicationInfo,
+                ArchiveState.ArchiveActivityInfo archiveActivityInfo) {
+            ActivityInfo activityInfo = new ActivityInfo();
+            activityInfo.isArchived = applicationInfo.isArchived;
+            activityInfo.applicationInfo = applicationInfo;
+            activityInfo.packageName =
+                    archiveActivityInfo.getOriginalComponentName().getPackageName();
+            activityInfo.name = archiveActivityInfo.getOriginalComponentName().getClassName();
+            activityInfo.nonLocalizedLabel = archiveActivityInfo.getTitle();
+
+            return new LauncherActivityInfoInternal(
+                    activityInfo,
+                    new IncrementalStatesInfo(
+                            false /* isLoading */, 1 /* progress */, 0 /* loadingCompletedTime */),
+                    user);
+        }
+
+        @NonNull
+        private List<ApplicationInfo> getApplicationInfoListForAllArchivedApps(UserHandle user) {
+            final int callingUid = injectBinderCallingUid();
+            List<ApplicationInfo> installedApplicationInfoList =
+                    mPackageManagerInternal.getInstalledApplications(
+                            PackageManager.MATCH_ARCHIVED_PACKAGES,
+                            user.getIdentifier(),
+                            callingUid);
+            List<ApplicationInfo> archivedApplicationInfos = new ArrayList<>();
+            for (int i = 0; i < installedApplicationInfoList.size(); i++) {
+                ApplicationInfo installedApplicationInfo = installedApplicationInfoList.get(i);
+                if (installedApplicationInfo != null && installedApplicationInfo.isArchived) {
+                    archivedApplicationInfos.add(installedApplicationInfo);
+                }
+            }
+            return archivedApplicationInfos;
+        }
+
+        @NonNull
+        private List<ApplicationInfo> getApplicationInfoForArchivedApp(
+                @NonNull String packageName, UserHandle user) {
+            final int callingUid = injectBinderCallingUid();
+            ApplicationInfo applicationInfo = mPackageManagerInternal.getApplicationInfo(
+                    packageName,
+                    PackageManager.MATCH_ARCHIVED_PACKAGES,
+                    callingUid,
+                    user.getIdentifier());
+            if (applicationInfo == null || !applicationInfo.isArchived) {
+                return Collections.EMPTY_LIST;
+            }
+            return List.of(applicationInfo);
+        }
+
         private List<LauncherActivityInfoInternal> queryIntentLauncherActivities(
                 Intent intent, int callingUid, UserHandle user) {
             final List<ResolveInfo> apps = mPackageManagerInternal.queryIntentActivities(intent,
diff --git a/services/core/java/com/android/server/pm/PackageArchiver.java b/services/core/java/com/android/server/pm/PackageArchiver.java
index 781e5f891a43d32a8bc1c026fa134831f4b0c962..49228513064d159832deab2814154450d5b8aba0 100644
--- a/services/core/java/com/android/server/pm/PackageArchiver.java
+++ b/services/core/java/com/android/server/pm/PackageArchiver.java
@@ -17,6 +17,8 @@
 package com.android.server.pm;
 
 import static android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED;
+import static android.content.pm.ArchivedActivity.bytesFromBitmap;
+import static android.content.pm.ArchivedActivity.drawableToBitmap;
 import static android.content.pm.PackageManager.DELETE_ARCHIVE;
 import static android.content.pm.PackageManager.DELETE_KEEP_DATA;
 import static android.os.PowerExemptionManager.REASON_PACKAGE_UNARCHIVE;
@@ -43,9 +45,6 @@ import android.content.pm.ResolveInfo;
 import android.content.pm.VersionedPackage;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Environment;
@@ -64,7 +63,6 @@ import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageUserState;
 import com.android.server.pm.pkg.PackageUserStateInternal;
 
-import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -547,29 +545,6 @@ public class PackageArchiver {
         return new File(Environment.getDataSystemCeDirectory(userId), ARCHIVE_ICONS_DIR);
     }
 
-    private static Bitmap drawableToBitmap(Drawable drawable) {
-        if (drawable instanceof BitmapDrawable) {
-            return ((BitmapDrawable) drawable).getBitmap();
-
-        }
-
-        Bitmap bitmap;
-        if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
-            // Needed for drawables that are just a single color.
-            bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
-        } else {
-            bitmap =
-                    Bitmap.createBitmap(
-                            drawable.getIntrinsicWidth(),
-                            drawable.getIntrinsicHeight(),
-                            Bitmap.Config.ARGB_8888);
-        }
-        Canvas canvas = new Canvas(bitmap);
-        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
-        drawable.draw(canvas);
-        return bitmap;
-    }
-
     private static byte[] bytesFromBitmapFile(Path path) throws IOException {
         if (path == null) {
             return null;
@@ -579,18 +554,6 @@ public class PackageArchiver {
         return bytesFromBitmap(BitmapFactory.decodeFile(path.toString()));
     }
 
-    private static byte[] bytesFromBitmap(Bitmap bitmap) throws IOException {
-        if (bitmap == null) {
-            return null;
-        }
-
-        try (ByteArrayOutputStream baos = new ByteArrayOutputStream(
-                bitmap.getByteCount())) {
-            bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
-            return baos.toByteArray();
-        }
-    }
-
     /**
      * Creates serializable archived activities from existing ArchiveState.
      */
@@ -642,9 +605,8 @@ public class PackageArchiver {
             var archivedActivity = new ArchivedActivityParcel();
             archivedActivity.title = info.getLabel().toString();
             archivedActivity.originalComponentName = info.getComponentName();
-            archivedActivity.iconBitmap =
-                    info.getActivityInfo().getIconResource() == 0 ? null : bytesFromBitmap(
-                            drawableToBitmap(info.getIcon(/* density= */ 0)));
+            archivedActivity.iconBitmap = info.getActivityInfo().getIconResource() == 0 ? null :
+                    bytesFromBitmap(drawableToBitmap(info.getIcon(/* density= */ 0)));
             // TODO(b/298452477) Handle monochrome icons.
             archivedActivity.monochromeIconBitmap = null;
             activities.add(archivedActivity);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 1bb20b4769f5ffc2d118d30c1fdc872486fc4442..b9b590833f4ae74a133966e6be6b43a7f2671405 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -17,6 +17,7 @@
 package com.android.server.pm;
 
 import static android.app.admin.DevicePolicyResources.Strings.Core.PACKAGE_DELETED_BY_DO;
+import static android.content.pm.PackageInstaller.LOCATION_DATA_APP;
 import static android.os.Process.INVALID_UID;
 
 import static com.android.server.pm.PackageManagerService.SHELL_PACKAGE_NAME;
@@ -42,6 +43,7 @@ import android.content.Intent;
 import android.content.IntentSender;
 import android.content.IntentSender.SendIntentException;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.ArchivedPackageParcel;
 import android.content.pm.IPackageInstaller;
 import android.content.pm.IPackageInstallerCallback;
 import android.content.pm.IPackageInstallerSession;
@@ -621,6 +623,14 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
     public int createSession(SessionParams params, String installerPackageName,
             String callingAttributionTag, int userId) {
         try {
+            if (params.dataLoaderParams != null
+                    && mContext.checkCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2)
+                    != PackageManager.PERMISSION_GRANTED) {
+                throw new SecurityException("You need the "
+                        + "com.android.permission.USE_INSTALLER_V2 permission "
+                        + "to use a data loader");
+            }
+
             return createSessionInternal(params, installerPackageName, callingAttributionTag,
                     userId);
         } catch (IOException e) {
@@ -639,14 +649,6 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
             throw new SecurityException("User restriction prevents installing");
         }
 
-        if (params.dataLoaderParams != null
-                && mContext.checkCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2)
-                        != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("You need the "
-                    + "com.android.permission.USE_INSTALLER_V2 permission "
-                    + "to use a data loader");
-        }
-
         // INSTALL_REASON_ROLLBACK allows an app to be rolled back without requiring the ROLLBACK
         // capability; ensure if this is set as the install reason the app has one of the necessary
         // signature permissions to perform the rollback.
@@ -1043,7 +1045,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
         return false;
     }
 
-    private IPackageInstallerSession openSessionInternal(int sessionId) throws IOException {
+    private PackageInstallerSession openSessionInternal(int sessionId) throws IOException {
         synchronized (mSessions) {
             final PackageInstallerSession session = mSessions.get(sessionId);
             if (!checkOpenSessionAccess(session)) {
@@ -1523,6 +1525,61 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
         mPackageArchiver.requestUnarchive(packageName, callerPackageName, userHandle);
     }
 
+    @Override
+    public void installPackageArchived(
+            @NonNull ArchivedPackageParcel archivedPackageParcel,
+            @NonNull SessionParams params,
+            @NonNull IntentSender statusReceiver,
+            @NonNull String installerPackageName,
+            @NonNull UserHandle userHandle) {
+        Objects.requireNonNull(params);
+        Objects.requireNonNull(archivedPackageParcel);
+        Objects.requireNonNull(statusReceiver);
+        Objects.requireNonNull(installerPackageName);
+        Objects.requireNonNull(userHandle);
+
+        final int callingUid = Binder.getCallingUid();
+        final int userId = userHandle.getIdentifier();
+        final Computer snapshot = mPm.snapshotComputer();
+        snapshot.enforceCrossUserPermission(callingUid, userId, true, true,
+                "installPackageArchived");
+
+        if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("You need the "
+                    + "com.android.permission.INSTALL_PACKAGES permission "
+                    + "to request archived package install");
+        }
+
+        params.installFlags |= PackageManager.INSTALL_ARCHIVED;
+        if (params.dataLoaderParams != null) {
+            throw new IllegalArgumentException(
+                    "Incompatible session param: dataLoaderParams has to be null");
+        }
+
+        params.setDataLoaderParams(
+                PackageManagerShellCommandDataLoader.getStreamingDataLoaderParams(null));
+        var metadata = PackageManagerShellCommandDataLoader.Metadata.forArchived(
+                archivedPackageParcel);
+
+        // Create and commit install archived session.
+        PackageInstallerSession session = null;
+        try {
+            var sessionId = createSessionInternal(params, installerPackageName,
+                    null /*installerAttributionTag*/, userId);
+            session = openSessionInternal(sessionId);
+            session.addFile(LOCATION_DATA_APP, "base", 0 /*lengthBytes*/, metadata.toByteArray(),
+                    null /*signature*/);
+            session.commit(statusReceiver, false /*forTransfer*/);
+        } catch (IOException e) {
+            throw ExceptionUtils.wrap(e);
+        } finally {
+            if (session != null) {
+                session.close();
+            }
+        }
+    }
+
     private static int getSessionCount(SparseArray<PackageInstallerSession> sessions,
             int installerUid) {
         int count = 0;
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java b/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java
index 9e7f04351327456dae73781ed88281af13bc75c2..a09e71311125e6bb3f2927c7a9df54a66708c624 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java
@@ -304,10 +304,6 @@ public class PackageManagerShellCommandDataLoader extends DataLoaderService {
         public boolean onPrepareImage(@NonNull Collection<InstallationFile> addedFiles,
                 @NonNull Collection<String> removedFiles) {
             ShellCommand shellCommand = lookupShellCommand(mParams.getArguments());
-            if (shellCommand == null) {
-                Slog.e(TAG, "Missing shell command.");
-                return false;
-            }
             try {
                 for (InstallationFile file : addedFiles) {
                     Metadata metadata = Metadata.fromByteArray(file.getMetadata());
@@ -317,11 +313,19 @@ public class PackageManagerShellCommandDataLoader extends DataLoaderService {
                     }
                     switch (metadata.getMode()) {
                         case Metadata.STDIN: {
+                            if (shellCommand == null) {
+                                Slog.e(TAG, "Missing shell command for Metadata.STDIN.");
+                                return false;
+                            }
                             final ParcelFileDescriptor inFd = getStdInPFD(shellCommand);
                             mConnector.writeData(file.getName(), 0, file.getLengthBytes(), inFd);
                             break;
                         }
                         case Metadata.LOCAL_FILE: {
+                            if (shellCommand == null) {
+                                Slog.e(TAG, "Missing shell command for Metadata.LOCAL_FILE.");
+                                return false;
+                            }
                             ParcelFileDescriptor incomingFd = null;
                             try {
                                 final String filePath = new String(metadata.getData(),
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 42f4cfb8b4dfa084f4e65ce072a27e68250b27b2..ad26d1fa858728a4caaa9b29a54711e20583c07a 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -16,6 +16,7 @@
 
 package com.android.server.pm;
 
+import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
@@ -89,17 +90,14 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
     private static class Booleans {
         @IntDef({
                 INSTALL_PERMISSION_FIXED,
-                DEFAULT_TO_DEVICE_PROTECTED_STORAGE,
                 UPDATE_AVAILABLE,
                 FORCE_QUERYABLE_OVERRIDE
         })
         public @interface Flags {
         }
         private static final int INSTALL_PERMISSION_FIXED = 1;
-        private static final int DEFAULT_TO_DEVICE_PROTECTED_STORAGE = 1 << 1;
-        private static final int UPDATE_AVAILABLE = 1 << 2;
-        private static final int FORCE_QUERYABLE_OVERRIDE = 1 << 3;
-        private static final int PERSISTENT = 1 << 4;
+        private static final int UPDATE_AVAILABLE = 1 << 1;
+        private static final int FORCE_QUERYABLE_OVERRIDE = 1 << 2;
     }
     private int mBooleans;
 
@@ -500,13 +498,6 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
         return this;
     }
 
-    public PackageSetting setDefaultToDeviceProtectedStorage(
-            boolean defaultToDeviceProtectedStorage) {
-        setBoolean(Booleans.DEFAULT_TO_DEVICE_PROTECTED_STORAGE, defaultToDeviceProtectedStorage);
-        onChanged();
-        return this;
-    }
-
     @Override
     public boolean isExternalStorage() {
         return (getFlags() & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
@@ -524,12 +515,6 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
         return this;
     }
 
-    public PackageSetting setIsPersistent(boolean isPersistent) {
-        setBoolean(Booleans.PERSISTENT, isPersistent);
-        onChanged();
-        return this;
-    }
-
     public PackageSetting setTargetSdkVersion(int targetSdkVersion) {
         mTargetSdkVersion = targetSdkVersion;
         onChanged();
@@ -1585,12 +1570,12 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
      */
     @Override
     public boolean isDefaultToDeviceProtectedStorage() {
-        return getBoolean(Booleans.DEFAULT_TO_DEVICE_PROTECTED_STORAGE);
+        return (getPrivateFlags() & PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) != 0;
     }
 
     @Override
     public boolean isPersistent() {
-        return getBoolean(Booleans.PERSISTENT);
+        return (getFlags() & ApplicationInfo.FLAG_PERSISTENT) != 0;
     }
 
 
@@ -1746,10 +1731,10 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
     }
 
     @DataClass.Generated(
-            time = 1696979728639L,
+            time = 1698097434269L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/services/core/java/com/android/server/pm/PackageSetting.java",
-            inputSignatures = "private  int mBooleans\nprivate  int mSharedUserAppId\nprivate @android.annotation.Nullable java.util.Map<java.lang.String,java.util.Set<java.lang.String>> mimeGroups\nprivate @java.lang.Deprecated @android.annotation.Nullable java.util.Set<java.lang.String> mOldCodePaths\nprivate @android.annotation.Nullable java.lang.String[] usesSdkLibraries\nprivate @android.annotation.Nullable long[] usesSdkLibrariesVersionsMajor\nprivate @android.annotation.Nullable java.lang.String[] usesStaticLibraries\nprivate @android.annotation.Nullable long[] usesStaticLibrariesVersions\nprivate @android.annotation.Nullable @java.lang.Deprecated java.lang.String legacyNativeLibraryPath\nprivate @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.Nullable java.lang.String mRealName\nprivate  int mAppId\nprivate @android.annotation.Nullable com.android.server.pm.parsing.pkg.AndroidPackageInternal pkg\nprivate @android.annotation.NonNull java.io.File mPath\nprivate @android.annotation.NonNull java.lang.String mPathString\nprivate  float mLoadingProgress\nprivate  long mLoadingCompletedTime\nprivate @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate  long mLastModifiedTime\nprivate  long lastUpdateTime\nprivate  long versionCode\nprivate @android.annotation.NonNull com.android.server.pm.PackageSignatures signatures\nprivate @android.annotation.NonNull com.android.server.pm.PackageKeySetData keySetData\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.pkg.PackageUserStateImpl> mUserStates\nprivate @android.annotation.NonNull com.android.server.pm.InstallSource installSource\nprivate @android.annotation.Nullable java.lang.String volumeUuid\nprivate  int categoryOverride\nprivate final @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized pkgState\nprivate @android.annotation.NonNull java.util.UUID mDomainSetId\nprivate @android.annotation.Nullable java.lang.String mAppMetadataFilePath\nprivate  int mTargetSdkVersion\nprivate @android.annotation.Nullable byte[] mRestrictUpdateHash\nprivate final @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> mSnapshot\nprivate  void setBoolean(int,boolean)\nprivate  boolean getBoolean(int)\nprivate  com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> makeCache()\npublic  com.android.server.pm.PackageSetting snapshot()\npublic  void dumpDebug(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\npublic  com.android.server.pm.PackageSetting setAppId(int)\npublic  com.android.server.pm.PackageSetting setCpuAbiOverride(java.lang.String)\npublic  com.android.server.pm.PackageSetting setFirstInstallTimeFromReplaced(com.android.server.pm.pkg.PackageStateInternal,int[])\npublic  com.android.server.pm.PackageSetting setFirstInstallTime(long,int)\npublic  com.android.server.pm.PackageSetting setForceQueryableOverride(boolean)\npublic  com.android.server.pm.PackageSetting setInstallerPackage(java.lang.String,int)\npublic  com.android.server.pm.PackageSetting setUpdateOwnerPackage(java.lang.String)\npublic  com.android.server.pm.PackageSetting setInstallSource(com.android.server.pm.InstallSource)\n  com.android.server.pm.PackageSetting removeInstallerPackage(java.lang.String)\npublic  com.android.server.pm.PackageSetting setIsOrphaned(boolean)\npublic  com.android.server.pm.PackageSetting setKeySetData(com.android.server.pm.PackageKeySetData)\npublic  com.android.server.pm.PackageSetting setLastModifiedTime(long)\npublic  com.android.server.pm.PackageSetting setLastUpdateTime(long)\npublic  com.android.server.pm.PackageSetting setLongVersionCode(long)\npublic  boolean setMimeGroup(java.lang.String,android.util.ArraySet<java.lang.String>)\npublic  com.android.server.pm.PackageSetting setPkg(com.android.server.pm.pkg.AndroidPackage)\npublic  com.android.server.pm.PackageSetting setPkgStateLibraryFiles(java.util.Collection<java.lang.String>)\npublic  com.android.server.pm.PackageSetting setPrimaryCpuAbi(java.lang.String)\npublic  com.android.server.pm.PackageSetting setSecondaryCpuAbi(java.lang.String)\npublic  com.android.server.pm.PackageSetting setSignatures(com.android.server.pm.PackageSignatures)\npublic  com.android.server.pm.PackageSetting setVolumeUuid(java.lang.String)\npublic  com.android.server.pm.PackageSetting setDefaultToDeviceProtectedStorage(boolean)\npublic @java.lang.Override boolean isExternalStorage()\npublic  com.android.server.pm.PackageSetting setUpdateAvailable(boolean)\npublic  void setSharedUserAppId(int)\npublic  com.android.server.pm.PackageSetting setIsPersistent(boolean)\npublic  com.android.server.pm.PackageSetting setTargetSdkVersion(int)\npublic  com.android.server.pm.PackageSetting setRestrictUpdateHash(byte[])\npublic @java.lang.Override int getSharedUserAppId()\npublic @java.lang.Override boolean hasSharedUser()\npublic @java.lang.Override java.lang.String toString()\nprotected  void copyMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic  void updateFrom(com.android.server.pm.PackageSetting)\n  com.android.server.pm.PackageSetting updateMimeGroups(java.util.Set<java.lang.String>)\npublic @java.lang.Deprecated @java.lang.Override com.android.server.pm.permission.LegacyPermissionState getLegacyPermissionState()\npublic  com.android.server.pm.PackageSetting setInstallPermissionsFixed(boolean)\npublic  boolean isPrivileged()\npublic  boolean isOem()\npublic  boolean isVendor()\npublic  boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic  boolean isSystemExt()\npublic  boolean isOdm()\npublic  boolean isSystem()\npublic  boolean isRequestLegacyExternalStorage()\npublic  boolean isUserDataFragile()\npublic  android.content.pm.SigningDetails getSigningDetails()\npublic  com.android.server.pm.PackageSetting setSigningDetails(android.content.pm.SigningDetails)\npublic  void copyPackageSetting(com.android.server.pm.PackageSetting,boolean)\n @com.android.internal.annotations.VisibleForTesting com.android.server.pm.pkg.PackageUserStateImpl modifyUserState(int)\npublic  com.android.server.pm.pkg.PackageUserStateImpl getOrCreateUserState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateInternal readUserState(int)\n  void setEnabled(int,int,java.lang.String)\n  int getEnabled(int)\n  void setInstalled(boolean,int)\n  boolean getInstalled(int)\n  int getInstallReason(int)\n  void setInstallReason(int,int)\n  int getUninstallReason(int)\n  void setUninstallReason(int,int)\n @android.annotation.NonNull android.content.pm.overlay.OverlayPaths getOverlayPaths(int)\n  boolean setOverlayPathsForLibrary(java.lang.String,android.content.pm.overlay.OverlayPaths,int)\n  boolean isInstalledOrHasDataOnAnyOtherUser(int[],int)\n  int[] queryInstalledUsers(int[],boolean)\n  int[] queryUsersInstalledOrHasData(int[])\n  long getCeDataInode(int)\n  long getDeDataInode(int)\n  void setCeDataInode(long,int)\n  void setDeDataInode(long,int)\n  boolean getStopped(int)\n  void setStopped(boolean,int)\n  boolean getNotLaunched(int)\n  void setNotLaunched(boolean,int)\n  boolean getHidden(int)\n  void setHidden(boolean,int)\n  int getDistractionFlags(int)\n  void setDistractionFlags(int,int)\npublic  boolean getInstantApp(int)\n  void setInstantApp(boolean,int)\n  boolean getVirtualPreload(int)\n  void setVirtualPreload(boolean,int)\n  void setUserState(int,long,long,int,boolean,boolean,boolean,boolean,int,android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>,boolean,boolean,java.lang.String,android.util.ArraySet<java.lang.String>,android.util.ArraySet<java.lang.String>,int,int,java.lang.String,java.lang.String,long,int,com.android.server.pm.pkg.ArchiveState)\n  void setUserState(int,com.android.server.pm.pkg.PackageUserStateInternal)\n  com.android.server.utils.WatchedArraySet<java.lang.String> getEnabledComponents(int)\n  com.android.server.utils.WatchedArraySet<java.lang.String> getDisabledComponents(int)\n  void setEnabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n  void setDisabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n  void setEnabledComponentsCopy(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n  void setDisabledComponentsCopy(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n  com.android.server.pm.pkg.PackageUserStateImpl modifyUserStateComponents(int,boolean,boolean)\n  void addDisabledComponent(java.lang.String,int)\n  void addEnabledComponent(java.lang.String,int)\n  boolean enableComponentLPw(java.lang.String,int)\n  boolean disableComponentLPw(java.lang.String,int)\n  boolean restoreComponentLPw(java.lang.String,int)\n  int getCurrentEnabledStateLPr(java.lang.String,int)\n  void removeUser(int)\npublic  int[] getNotInstalledUserIds()\n  void writePackageUserPermissionsProto(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\nprotected  void writeUsersInfoToProto(android.util.proto.ProtoOutputStream,long)\nprivate static  void writeArchiveState(android.util.proto.ProtoOutputStream,com.android.server.pm.pkg.ArchiveState)\n  com.android.server.pm.PackageSetting setPath(java.io.File)\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideNonLocalizedLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer,int)\npublic  void resetOverrideComponentLabelIcon(int)\npublic @android.annotation.Nullable java.lang.String getSplashScreenTheme(int)\npublic  boolean isIncremental()\npublic  boolean isLoading()\npublic  com.android.server.pm.PackageSetting setLoadingProgress(float)\npublic  com.android.server.pm.PackageSetting setLoadingCompletedTime(long)\npublic  com.android.server.pm.PackageSetting setAppMetadataFilePath(java.lang.String)\npublic @android.annotation.NonNull @java.lang.Override long getVersionCode()\npublic @android.annotation.Nullable @java.lang.Override java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getMimeGroups()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String getPackageName()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.pm.pkg.AndroidPackage getAndroidPackage()\npublic @android.annotation.NonNull android.content.pm.SigningInfo getSigningInfo()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesSdkLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesSdkLibrariesVersionsMajor()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesStaticLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesStaticLibrariesVersions()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<com.android.server.pm.pkg.SharedLibrary> getSharedLibraryDependencies()\npublic @android.annotation.NonNull com.android.server.pm.PackageSetting addUsesLibraryInfo(android.content.pm.SharedLibraryInfo)\npublic @android.annotation.NonNull @java.lang.Override java.util.List<java.lang.String> getUsesLibraryFiles()\npublic @android.annotation.NonNull com.android.server.pm.PackageSetting addUsesLibraryFile(java.lang.String)\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @android.annotation.NonNull @java.lang.Override long[] getLastPackageUsageTime()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic @java.lang.Override boolean isApkInUpdatedApex()\npublic @android.annotation.Nullable @java.lang.Override java.lang.String getApexModuleName()\npublic  com.android.server.pm.PackageSetting setDomainSetId(java.util.UUID)\npublic  com.android.server.pm.PackageSetting setCategoryOverride(int)\npublic  com.android.server.pm.PackageSetting setLegacyNativeLibraryPath(java.lang.String)\npublic  com.android.server.pm.PackageSetting setMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic  com.android.server.pm.PackageSetting setOldCodePaths(java.util.Set<java.lang.String>)\npublic  com.android.server.pm.PackageSetting setUsesSdkLibraries(java.lang.String[])\npublic  com.android.server.pm.PackageSetting setUsesSdkLibrariesVersionsMajor(long[])\npublic  com.android.server.pm.PackageSetting setUsesStaticLibraries(java.lang.String[])\npublic  com.android.server.pm.PackageSetting setUsesStaticLibrariesVersions(long[])\npublic  com.android.server.pm.PackageSetting setApexModuleName(java.lang.String)\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageStateUnserialized getTransientState()\npublic @android.annotation.NonNull android.util.SparseArray<? extends PackageUserStateInternal> getUserStates()\npublic  com.android.server.pm.PackageSetting addMimeTypes(java.lang.String,java.util.Set<java.lang.String>)\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageUserState getStateForUser(android.os.UserHandle)\npublic @android.annotation.Nullable java.lang.String getPrimaryCpuAbi()\npublic @android.annotation.Nullable java.lang.String getSecondaryCpuAbi()\npublic @android.annotation.Nullable @java.lang.Override java.lang.String getSeInfo()\npublic @android.annotation.Nullable java.lang.String getPrimaryCpuAbiLegacy()\npublic @android.annotation.Nullable java.lang.String getSecondaryCpuAbiLegacy()\npublic @android.content.pm.ApplicationInfo.HiddenApiEnforcementPolicy @java.lang.Override int getHiddenApiEnforcementPolicy()\npublic @java.lang.Override boolean isApex()\npublic @java.lang.Override boolean isForceQueryableOverride()\npublic @java.lang.Override boolean isUpdateAvailable()\npublic @java.lang.Override boolean isInstallPermissionsFixed()\npublic @java.lang.Override boolean isDefaultToDeviceProtectedStorage()\npublic @java.lang.Override boolean isPersistent()\nclass PackageSetting extends com.android.server.pm.SettingBase implements [com.android.server.pm.pkg.PackageStateInternal]\nprivate static final  int INSTALL_PERMISSION_FIXED\nprivate static final  int DEFAULT_TO_DEVICE_PROTECTED_STORAGE\nprivate static final  int UPDATE_AVAILABLE\nprivate static final  int FORCE_QUERYABLE_OVERRIDE\nprivate static final  int PERSISTENT\nclass Booleans extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genGetters=true, genConstructor=false, genSetters=false, genBuilder=false)")
+            inputSignatures = "private  int mBooleans\nprivate  int mSharedUserAppId\nprivate @android.annotation.Nullable java.util.Map<java.lang.String,java.util.Set<java.lang.String>> mimeGroups\nprivate @java.lang.Deprecated @android.annotation.Nullable java.util.Set<java.lang.String> mOldCodePaths\nprivate @android.annotation.Nullable java.lang.String[] usesSdkLibraries\nprivate @android.annotation.Nullable long[] usesSdkLibrariesVersionsMajor\nprivate @android.annotation.Nullable java.lang.String[] usesStaticLibraries\nprivate @android.annotation.Nullable long[] usesStaticLibrariesVersions\nprivate @android.annotation.Nullable @java.lang.Deprecated java.lang.String legacyNativeLibraryPath\nprivate @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.Nullable java.lang.String mRealName\nprivate  int mAppId\nprivate @android.annotation.Nullable com.android.server.pm.parsing.pkg.AndroidPackageInternal pkg\nprivate @android.annotation.NonNull java.io.File mPath\nprivate @android.annotation.NonNull java.lang.String mPathString\nprivate  float mLoadingProgress\nprivate  long mLoadingCompletedTime\nprivate @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate  long mLastModifiedTime\nprivate  long lastUpdateTime\nprivate  long versionCode\nprivate @android.annotation.NonNull com.android.server.pm.PackageSignatures signatures\nprivate @android.annotation.NonNull com.android.server.pm.PackageKeySetData keySetData\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.pkg.PackageUserStateImpl> mUserStates\nprivate @android.annotation.NonNull com.android.server.pm.InstallSource installSource\nprivate @android.annotation.Nullable java.lang.String volumeUuid\nprivate  int categoryOverride\nprivate final @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized pkgState\nprivate @android.annotation.NonNull java.util.UUID mDomainSetId\nprivate @android.annotation.Nullable java.lang.String mAppMetadataFilePath\nprivate  int mTargetSdkVersion\nprivate @android.annotation.Nullable byte[] mRestrictUpdateHash\nprivate final @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> mSnapshot\nprivate  void setBoolean(int,boolean)\nprivate  boolean getBoolean(int)\nprivate  com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> makeCache()\npublic  com.android.server.pm.PackageSetting snapshot()\npublic  void dumpDebug(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\npublic  com.android.server.pm.PackageSetting setAppId(int)\npublic  com.android.server.pm.PackageSetting setCpuAbiOverride(java.lang.String)\npublic  com.android.server.pm.PackageSetting setFirstInstallTimeFromReplaced(com.android.server.pm.pkg.PackageStateInternal,int[])\npublic  com.android.server.pm.PackageSetting setFirstInstallTime(long,int)\npublic  com.android.server.pm.PackageSetting setForceQueryableOverride(boolean)\npublic  com.android.server.pm.PackageSetting setInstallerPackage(java.lang.String,int)\npublic  com.android.server.pm.PackageSetting setUpdateOwnerPackage(java.lang.String)\npublic  com.android.server.pm.PackageSetting setInstallSource(com.android.server.pm.InstallSource)\n  com.android.server.pm.PackageSetting removeInstallerPackage(java.lang.String)\npublic  com.android.server.pm.PackageSetting setIsOrphaned(boolean)\npublic  com.android.server.pm.PackageSetting setKeySetData(com.android.server.pm.PackageKeySetData)\npublic  com.android.server.pm.PackageSetting setLastModifiedTime(long)\npublic  com.android.server.pm.PackageSetting setLastUpdateTime(long)\npublic  com.android.server.pm.PackageSetting setLongVersionCode(long)\npublic  boolean setMimeGroup(java.lang.String,android.util.ArraySet<java.lang.String>)\npublic  com.android.server.pm.PackageSetting setPkg(com.android.server.pm.pkg.AndroidPackage)\npublic  com.android.server.pm.PackageSetting setPkgStateLibraryFiles(java.util.Collection<java.lang.String>)\npublic  com.android.server.pm.PackageSetting setPrimaryCpuAbi(java.lang.String)\npublic  com.android.server.pm.PackageSetting setSecondaryCpuAbi(java.lang.String)\npublic  com.android.server.pm.PackageSetting setSignatures(com.android.server.pm.PackageSignatures)\npublic  com.android.server.pm.PackageSetting setVolumeUuid(java.lang.String)\npublic @java.lang.Override boolean isExternalStorage()\npublic  com.android.server.pm.PackageSetting setUpdateAvailable(boolean)\npublic  com.android.server.pm.PackageSetting setSharedUserAppId(int)\npublic  com.android.server.pm.PackageSetting setTargetSdkVersion(int)\npublic  com.android.server.pm.PackageSetting setRestrictUpdateHash(byte[])\npublic @java.lang.Override int getSharedUserAppId()\npublic @java.lang.Override boolean hasSharedUser()\npublic @java.lang.Override java.lang.String toString()\nprivate  void copyMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic  void updateFrom(com.android.server.pm.PackageSetting)\n  com.android.server.pm.PackageSetting updateMimeGroups(java.util.Set<java.lang.String>)\npublic @java.lang.Deprecated @java.lang.Override com.android.server.pm.permission.LegacyPermissionState getLegacyPermissionState()\npublic  com.android.server.pm.PackageSetting setInstallPermissionsFixed(boolean)\npublic  boolean isPrivileged()\npublic  boolean isOem()\npublic  boolean isVendor()\npublic  boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic  boolean isSystemExt()\npublic  boolean isOdm()\npublic  boolean isSystem()\npublic  boolean isRequestLegacyExternalStorage()\npublic  boolean isUserDataFragile()\npublic  android.content.pm.SigningDetails getSigningDetails()\npublic  com.android.server.pm.PackageSetting setSigningDetails(android.content.pm.SigningDetails)\npublic  void copyPackageSetting(com.android.server.pm.PackageSetting,boolean)\n @com.android.internal.annotations.VisibleForTesting com.android.server.pm.pkg.PackageUserStateImpl modifyUserState(int)\npublic  com.android.server.pm.pkg.PackageUserStateImpl getOrCreateUserState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateInternal readUserState(int)\n  void setEnabled(int,int,java.lang.String)\n  int getEnabled(int)\n  void setInstalled(boolean,int)\n  boolean getInstalled(int)\n  int getInstallReason(int)\n  void setInstallReason(int,int)\n  int getUninstallReason(int)\n  void setUninstallReason(int,int)\n @android.annotation.NonNull android.content.pm.overlay.OverlayPaths getOverlayPaths(int)\n  boolean setOverlayPathsForLibrary(java.lang.String,android.content.pm.overlay.OverlayPaths,int)\n  boolean isInstalledOrHasDataOnAnyOtherUser(int[],int)\n  int[] queryInstalledUsers(int[],boolean)\n  int[] queryUsersInstalledOrHasData(int[])\n  long getCeDataInode(int)\n  long getDeDataInode(int)\n  void setCeDataInode(long,int)\n  void setDeDataInode(long,int)\n  boolean getStopped(int)\n  void setStopped(boolean,int)\n  boolean getNotLaunched(int)\n  void setNotLaunched(boolean,int)\n  boolean getHidden(int)\n  void setHidden(boolean,int)\n  int getDistractionFlags(int)\n  void setDistractionFlags(int,int)\npublic  boolean getInstantApp(int)\n  void setInstantApp(boolean,int)\n  boolean getVirtualPreload(int)\n  void setVirtualPreload(boolean,int)\n  void setUserState(int,long,long,int,boolean,boolean,boolean,boolean,int,android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>,boolean,boolean,java.lang.String,android.util.ArraySet<java.lang.String>,android.util.ArraySet<java.lang.String>,int,int,java.lang.String,java.lang.String,long,int,com.android.server.pm.pkg.ArchiveState)\n  void setUserState(int,com.android.server.pm.pkg.PackageUserStateInternal)\n  com.android.server.utils.WatchedArraySet<java.lang.String> getEnabledComponents(int)\n  com.android.server.utils.WatchedArraySet<java.lang.String> getDisabledComponents(int)\n  void setEnabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n  void setDisabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n  void setEnabledComponentsCopy(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n  void setDisabledComponentsCopy(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n  com.android.server.pm.pkg.PackageUserStateImpl modifyUserStateComponents(int,boolean,boolean)\n  void addDisabledComponent(java.lang.String,int)\n  void addEnabledComponent(java.lang.String,int)\n  boolean enableComponentLPw(java.lang.String,int)\n  boolean disableComponentLPw(java.lang.String,int)\n  boolean restoreComponentLPw(java.lang.String,int)\n  int getCurrentEnabledStateLPr(java.lang.String,int)\n  void removeUser(int)\npublic  int[] getNotInstalledUserIds()\n  void writePackageUserPermissionsProto(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\nprotected  void writeUsersInfoToProto(android.util.proto.ProtoOutputStream,long)\nprivate static  void writeArchiveState(android.util.proto.ProtoOutputStream,com.android.server.pm.pkg.ArchiveState)\npublic @com.android.internal.annotations.VisibleForTesting com.android.server.pm.PackageSetting setPath(java.io.File)\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideNonLocalizedLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer,int)\npublic  void resetOverrideComponentLabelIcon(int)\npublic @android.annotation.Nullable java.lang.String getSplashScreenTheme(int)\npublic  boolean isIncremental()\npublic  boolean isLoading()\npublic  com.android.server.pm.PackageSetting setLoadingProgress(float)\npublic  com.android.server.pm.PackageSetting setLoadingCompletedTime(long)\npublic  com.android.server.pm.PackageSetting setAppMetadataFilePath(java.lang.String)\npublic @android.annotation.NonNull @java.lang.Override long getVersionCode()\npublic @android.annotation.Nullable @java.lang.Override java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getMimeGroups()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String getPackageName()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.pm.pkg.AndroidPackage getAndroidPackage()\npublic @android.annotation.NonNull android.content.pm.SigningInfo getSigningInfo()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesSdkLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesSdkLibrariesVersionsMajor()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesStaticLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesStaticLibrariesVersions()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<com.android.server.pm.pkg.SharedLibrary> getSharedLibraryDependencies()\npublic @android.annotation.NonNull com.android.server.pm.PackageSetting addUsesLibraryInfo(android.content.pm.SharedLibraryInfo)\npublic @android.annotation.NonNull @java.lang.Override java.util.List<java.lang.String> getUsesLibraryFiles()\npublic @android.annotation.NonNull com.android.server.pm.PackageSetting addUsesLibraryFile(java.lang.String)\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @android.annotation.NonNull @java.lang.Override long[] getLastPackageUsageTime()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic @java.lang.Override boolean isApkInUpdatedApex()\npublic @android.annotation.Nullable @java.lang.Override java.lang.String getApexModuleName()\npublic  com.android.server.pm.PackageSetting setDomainSetId(java.util.UUID)\npublic  com.android.server.pm.PackageSetting setCategoryOverride(int)\npublic  com.android.server.pm.PackageSetting setLegacyNativeLibraryPath(java.lang.String)\npublic  com.android.server.pm.PackageSetting setMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic  com.android.server.pm.PackageSetting setOldCodePaths(java.util.Set<java.lang.String>)\npublic  com.android.server.pm.PackageSetting setUsesSdkLibraries(java.lang.String[])\npublic  com.android.server.pm.PackageSetting setUsesSdkLibrariesVersionsMajor(long[])\npublic  com.android.server.pm.PackageSetting setUsesStaticLibraries(java.lang.String[])\npublic  com.android.server.pm.PackageSetting setUsesStaticLibrariesVersions(long[])\npublic  com.android.server.pm.PackageSetting setApexModuleName(java.lang.String)\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageStateUnserialized getTransientState()\npublic @android.annotation.NonNull android.util.SparseArray<? extends PackageUserStateInternal> getUserStates()\npublic  com.android.server.pm.PackageSetting addMimeTypes(java.lang.String,java.util.Set<java.lang.String>)\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageUserState getStateForUser(android.os.UserHandle)\npublic @android.annotation.Nullable java.lang.String getPrimaryCpuAbi()\npublic @android.annotation.Nullable java.lang.String getSecondaryCpuAbi()\npublic @android.annotation.Nullable @java.lang.Override java.lang.String getSeInfo()\npublic @android.annotation.Nullable java.lang.String getPrimaryCpuAbiLegacy()\npublic @android.annotation.Nullable java.lang.String getSecondaryCpuAbiLegacy()\npublic @android.content.pm.ApplicationInfo.HiddenApiEnforcementPolicy @java.lang.Override int getHiddenApiEnforcementPolicy()\npublic @java.lang.Override boolean isApex()\npublic @java.lang.Override boolean isForceQueryableOverride()\npublic @java.lang.Override boolean isUpdateAvailable()\npublic @java.lang.Override boolean isInstallPermissionsFixed()\npublic @java.lang.Override boolean isDefaultToDeviceProtectedStorage()\npublic @java.lang.Override boolean isPersistent()\nclass PackageSetting extends com.android.server.pm.SettingBase implements [com.android.server.pm.pkg.PackageStateInternal]\nprivate static final  int INSTALL_PERMISSION_FIXED\nprivate static final  int UPDATE_AVAILABLE\nprivate static final  int FORCE_QUERYABLE_OVERRIDE\nclass Booleans extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genGetters=true, genConstructor=false, genSetters=false, genBuilder=false)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/services/core/java/com/android/server/pm/ScanPackageUtils.java b/services/core/java/com/android/server/pm/ScanPackageUtils.java
index 8d8acfd421dee02a37b57515988c52c4abb9611e..7ea9e3f529d0f0079b78bec1d37d6474c4403e85 100644
--- a/services/core/java/com/android/server/pm/ScanPackageUtils.java
+++ b/services/core/java/com/android/server/pm/ScanPackageUtils.java
@@ -220,7 +220,7 @@ final class ScanPackageUtils {
                     UserManagerService.getInstance(), usesSdkLibraries,
                     parsedPackage.getUsesSdkLibrariesVersionsMajor(), usesStaticLibraries,
                     parsedPackage.getUsesStaticLibrariesVersions(), parsedPackage.getMimeGroups(),
-                    newDomainSetId, parsedPackage.isPersistent(),
+                    newDomainSetId,
                     parsedPackage.getTargetSdkVersion(), parsedPackage.getRestrictUpdateHash());
         } else {
             // make a deep copy to avoid modifying any existing system state.
@@ -241,7 +241,7 @@ final class ScanPackageUtils {
                     UserManagerService.getInstance(),
                     usesSdkLibraries, parsedPackage.getUsesSdkLibrariesVersionsMajor(),
                     usesStaticLibraries, parsedPackage.getUsesStaticLibrariesVersions(),
-                    parsedPackage.getMimeGroups(), newDomainSetId, parsedPackage.isPersistent(),
+                    parsedPackage.getMimeGroups(), newDomainSetId,
                     parsedPackage.getTargetSdkVersion(), parsedPackage.getRestrictUpdateHash());
         }
 
@@ -464,8 +464,6 @@ final class ScanPackageUtils {
                             + " to " + volumeUuid);
             pkgSetting.setVolumeUuid(volumeUuid);
         }
-        pkgSetting.setDefaultToDeviceProtectedStorage(
-                parsedPackage.isDefaultToDeviceProtectedStorage());
 
         SharedLibraryInfo sdkLibraryInfo = null;
         if (!TextUtils.isEmpty(parsedPackage.getSdkLibraryName())) {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index a39178ec4baa84a41664d5450c461e3adc6c8001..440823c436073e9e6bf4d22d4288a617dad9f08b 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -946,7 +946,6 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
             ret.setMimeGroups(p.getMimeGroups());
             ret.setAppMetadataFilePath(p.getAppMetadataFilePath());
             ret.getPkgState().setUpdatedSystemApp(false);
-            ret.setIsPersistent(p.isPersistent());
             ret.setTargetSdkVersion(p.getTargetSdkVersion());
             ret.setRestrictUpdateHash(p.getRestrictUpdateHash());
         }
@@ -1061,7 +1060,7 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
             boolean virtualPreload, boolean isStoppedSystemApp, UserManagerService userManager,
             String[] usesSdkLibraries, long[] usesSdkLibrariesVersions,
             String[] usesStaticLibraries, long[] usesStaticLibrariesVersions,
-            Set<String> mimeGroupNames, @NonNull UUID domainSetId, boolean isPersistent,
+            Set<String> mimeGroupNames, @NonNull UUID domainSetId,
             int targetSdkVersion, byte[] restrictUpdatedHash) {
         final PackageSetting pkgSetting;
         if (originalPkg != null) {
@@ -1083,7 +1082,6 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
                     // Update new package state.
                     .setLastModifiedTime(codePath.lastModified())
                     .setDomainSetId(domainSetId)
-                    .setIsPersistent(isPersistent)
                     .setTargetSdkVersion(targetSdkVersion)
                     .setRestrictUpdateHash(restrictUpdatedHash);
             pkgSetting.setFlags(pkgFlags)
@@ -1103,7 +1101,6 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
                     .setSecondaryCpuAbi(secondaryCpuAbi)
                     .setLongVersionCode(versionCode)
                     .setMimeGroups(createMimeGroups(mimeGroupNames))
-                    .setIsPersistent(isPersistent)
                     .setTargetSdkVersion(targetSdkVersion)
                     .setRestrictUpdateHash(restrictUpdatedHash)
                     .setLastModifiedTime(codePath.lastModified());
@@ -1219,7 +1216,7 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
             int pkgPrivateFlags, @NonNull UserManagerService userManager,
             @Nullable String[] usesSdkLibraries, @Nullable long[] usesSdkLibrariesVersions,
             @Nullable String[] usesStaticLibraries, @Nullable long[] usesStaticLibrariesVersions,
-            @Nullable Set<String> mimeGroupNames, @NonNull UUID domainSetId, boolean isPersistent,
+            @Nullable Set<String> mimeGroupNames, @NonNull UUID domainSetId,
             int targetSdkVersion, byte[] restrictUpdatedHash)
                     throws PackageManagerException {
         final String pkgName = pkgSetting.getPackageName();
@@ -1273,7 +1270,6 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
                 .setSecondaryCpuAbi(secondaryCpuAbi)
                 .updateMimeGroups(mimeGroupNames)
                 .setDomainSetId(domainSetId)
-                .setIsPersistent(isPersistent)
                 .setTargetSdkVersion(targetSdkVersion)
                 .setRestrictUpdateHash(restrictUpdatedHash);
         // Update SDK library dependencies if needed.
@@ -3071,7 +3067,6 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
         serializer.attributeLongHex(null, "ft", pkg.getLastModifiedTime());
         serializer.attributeLongHex(null, "ut", pkg.getLastUpdateTime());
         serializer.attributeLong(null, "version", pkg.getVersionCode());
-        serializer.attributeBoolean(null, "isPersistent", pkg.isPersistent());
         serializer.attributeInt(null, "targetSdkVersion", pkg.getTargetSdkVersion());
         if (pkg.getRestrictUpdateHash() != null) {
             serializer.attributeBytesBase64(null, "restrictUpdateHash",
@@ -3140,7 +3135,6 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
         serializer.attributeLongHex(null, "ft", pkg.getLastModifiedTime());
         serializer.attributeLongHex(null, "ut", pkg.getLastUpdateTime());
         serializer.attributeLong(null, "version", pkg.getVersionCode());
-        serializer.attributeBoolean(null, "isPersistent", pkg.isPersistent());
         serializer.attributeInt(null, "targetSdkVersion", pkg.getTargetSdkVersion());
         if (pkg.getRestrictUpdateHash() != null) {
             serializer.attributeBytesBase64(null, "restrictUpdateHash",
@@ -3182,8 +3176,6 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
         if (pkg.getVolumeUuid() != null) {
             serializer.attribute(null, "volumeUuid", pkg.getVolumeUuid());
         }
-        serializer.attributeBoolean(null, "defaultToDeviceProtectedStorage",
-                pkg.isDefaultToDeviceProtectedStorage());
         if (pkg.getCategoryOverride() != ApplicationInfo.CATEGORY_UNDEFINED) {
             serializer.attributeInt(null, "categoryHint", pkg.getCategoryOverride());
         }
@@ -3878,7 +3870,6 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
         }
 
         long versionCode = parser.getAttributeLong(null, "version", 0);
-        boolean isPersistent = parser.getAttributeBoolean(null, "isPersistent", false);
         int targetSdkVersion = parser.getAttributeInt(null, "targetSdkVersion", 0);
         byte[] restrictUpdateHash = parser.getAttributeBytesBase64(null, "restrictUpdateHash",
                 null);
@@ -3901,7 +3892,6 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
                 .setSecondaryCpuAbi(secondaryCpuAbiStr)
                 .setCpuAbiOverride(cpuAbiOverrideStr)
                 .setLongVersionCode(versionCode)
-                .setIsPersistent(isPersistent)
                 .setTargetSdkVersion(targetSdkVersion)
                 .setRestrictUpdateHash(restrictUpdateHash);
         long timeStamp = parser.getAttributeLongHex(null, "ft", 0);
@@ -3982,7 +3972,6 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
         String installInitiatingPackageName = null;
         boolean installInitiatorUninstalled = false;
         String volumeUuid = null;
-        boolean defaultToDeviceProtectedStorage = false;
         boolean updateAvailable = false;
         int categoryHint = ApplicationInfo.CATEGORY_UNDEFINED;
         int pkgFlags = 0;
@@ -3997,7 +3986,6 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
         long loadingCompletedTime = 0;
         UUID domainSetId;
         String appMetadataFilePath = null;
-        boolean isPersistent = false;
         int targetSdkVersion = 0;
         byte[] restrictUpdateHash = null;
         try {
@@ -4023,7 +4011,6 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
             }
 
             versionCode = parser.getAttributeLong(null, "version", 0);
-            isPersistent = parser.getAttributeBoolean(null, "isPersistent", false);
             targetSdkVersion = parser.getAttributeInt(null, "targetSdkVersion", 0);
             restrictUpdateHash = parser.getAttributeBytesBase64(null, "restrictUpdateHash", null);
             installerPackageName = parser.getAttributeValue(null, "installer");
@@ -4038,8 +4025,6 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
             installInitiatorUninstalled = parser.getAttributeBoolean(null,
                     "installInitiatorUninstalled", false);
             volumeUuid = parser.getAttributeValue(null, "volumeUuid");
-            defaultToDeviceProtectedStorage = parser.getAttributeBoolean(
-                    null, "defaultToDeviceProtectedStorage", false);
             categoryHint = parser.getAttributeInt(null, "categoryHint",
                     ApplicationInfo.CATEGORY_UNDEFINED);
             appMetadataFilePath = parser.getAttributeValue(null, "appMetadataFilePath");
@@ -4179,7 +4164,6 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
                     installInitiatorUninstalled);
             packageSetting.setInstallSource(installSource)
                     .setVolumeUuid(volumeUuid)
-                    .setDefaultToDeviceProtectedStorage(defaultToDeviceProtectedStorage)
                     .setCategoryOverride(categoryHint)
                     .setLegacyNativeLibraryPath(legacyNativeLibraryPathStr)
                     .setPrimaryCpuAbi(primaryCpuAbiString)
@@ -4189,7 +4173,6 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
                     .setLoadingProgress(loadingProgress)
                     .setLoadingCompletedTime(loadingCompletedTime)
                     .setAppMetadataFilePath(appMetadataFilePath)
-                    .setIsPersistent(isPersistent)
                     .setTargetSdkVersion(targetSdkVersion)
                     .setRestrictUpdateHash(restrictUpdateHash);
             // Handle legacy string here for single-user mode
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index 61e96ca3dd59cccf8aa15e8052bc45411a00b6a5..2ad8bcf4739e9cb88c14075db2ef3f21a98b92c6 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -1016,8 +1016,8 @@ public class PackageInfoUtils {
             return;
         }
 
-        if (android.content.pm.Flags.nullableDataDir()
-                && !state.isInstalled() && !state.dataExists()) {
+        if (!state.isInstalled() && !state.dataExists()
+                && android.content.pm.Flags.nullableDataDir()) {
             // The data dir has been deleted
             output.dataDir = null;
             return;
@@ -1065,8 +1065,8 @@ public class PackageInfoUtils {
             return;
         }
 
-        if (android.content.pm.Flags.nullableDataDir()
-                && !state.isInstalled() && !state.dataExists()) {
+        if (!state.isInstalled() && !state.dataExists()
+                && android.content.pm.Flags.nullableDataDir()) {
             // The data dir has been deleted
             output.dataDir = null;
             return;
@@ -1113,9 +1113,9 @@ public class PackageInfoUtils {
             return Environment.getDataSystemDirectory();
         }
 
-        if (android.content.pm.Flags.nullableDataDir()
-                && !ps.getUserStateOrDefault(userId).isInstalled()
-                && !ps.getUserStateOrDefault(userId).dataExists()) {
+        if (!ps.getUserStateOrDefault(userId).isInstalled()
+                && !ps.getUserStateOrDefault(userId).dataExists()
+                && android.content.pm.Flags.nullableDataDir()) {
             // The app has been uninstalled for the user and the data dir has been deleted
             return null;
         }
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 7c0fc998abcfff7fd42e19b922af8a145165ba5a..b4396818c43ce94553b4a4c4a03aff460d75aa68 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2478,7 +2478,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                 com.android.internal.R.integer.config_keyguardDrawnTimeout);
         mKeyguardDelegate = injector.getKeyguardServiceDelegate();
         initKeyCombinationRules();
-        initSingleKeyGestureRules();
+        initSingleKeyGestureRules(injector.getLooper());
         mSideFpsEventHandler = new SideFpsEventHandler(mContext, mHandler, mPowerManager);
     }
 
@@ -2749,8 +2749,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
         }
     }
 
-    private void initSingleKeyGestureRules() {
-        mSingleKeyGestureDetector = SingleKeyGestureDetector.get(mContext);
+    private void initSingleKeyGestureRules(Looper looper) {
+        mSingleKeyGestureDetector = SingleKeyGestureDetector.get(mContext, looper);
         mSingleKeyGestureDetector.addRule(new PowerKeyRule());
         if (hasLongPressOnBackBehavior()) {
             mSingleKeyGestureDetector.addRule(new BackKeyRule());
diff --git a/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java b/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
index c5a9cdf4bacb8167c2a8ececb03a5d069317bbbd..047555ae491c3cc2cf5afdfd64b0f8f294a3a091 100644
--- a/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
+++ b/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
@@ -179,8 +179,8 @@ public final class SingleKeyGestureDetector {
         }
     }
 
-    static SingleKeyGestureDetector get(Context context) {
-        SingleKeyGestureDetector detector = new SingleKeyGestureDetector();
+    static SingleKeyGestureDetector get(Context context, Looper looper) {
+        SingleKeyGestureDetector detector = new SingleKeyGestureDetector(looper);
         sDefaultLongPressTimeout = context.getResources().getInteger(
                 com.android.internal.R.integer.config_globalActionsKeyTimeout);
         sDefaultVeryLongPressTimeout = context.getResources().getInteger(
@@ -188,8 +188,8 @@ public final class SingleKeyGestureDetector {
         return detector;
     }
 
-    private SingleKeyGestureDetector() {
-        mHandler = new KeyHandler();
+    private SingleKeyGestureDetector(Looper looper) {
+        mHandler = new KeyHandler(looper);
     }
 
     void addRule(SingleKeyRule rule) {
@@ -417,8 +417,8 @@ public final class SingleKeyGestureDetector {
     }
 
     private class KeyHandler extends Handler {
-        KeyHandler() {
-            super(Looper.myLooper());
+        KeyHandler(Looper looper) {
+            super(looper);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 9fa5ed2cfde97a45bc2716c810739b94d03df752..fd8f6bfd1cc881dac8f499d56da1589ca74f34d3 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -3055,7 +3055,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
 
     @Override
     boolean providesOrientation() {
-        return mStyleFillsParent;
+        return mStyleFillsParent || mOccludesParent;
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java
index 823fbc9b0f3ec1781df7d249d4327de08cb17ca2..2fabb0ea686abe6ed38c8b1915217586ac322f7e 100644
--- a/services/core/java/com/android/server/wm/Dimmer.java
+++ b/services/core/java/com/android/server/wm/Dimmer.java
@@ -29,7 +29,7 @@ import com.android.window.flags.Flags;
  */
 public abstract class Dimmer {
 
-    static final boolean DIMMER_REFACTOR = Flags.dimmerRefactor();
+    static final boolean DIMMER_REFACTOR = Flags.introduceSmootherDimmer();
 
     /**
      * The {@link WindowContainer} that our Dims are bounded to. We may be dimming on behalf of the
diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java
index f9fa9e6d4a7bdc79cc0b49f85cb67ed48c82ca61..f6aad4c86220b29075baf51b57ea7873da42f987 100644
--- a/services/core/java/com/android/server/wm/Letterbox.java
+++ b/services/core/java/com/android/server/wm/Letterbox.java
@@ -36,7 +36,10 @@ import android.view.WindowManager;
 
 import com.android.server.UiThread;
 
+import java.util.function.BooleanSupplier;
+import java.util.function.DoubleSupplier;
 import java.util.function.IntConsumer;
+import java.util.function.IntSupplier;
 import java.util.function.Supplier;
 
 /**
@@ -50,12 +53,12 @@ public class Letterbox {
 
     private final Supplier<SurfaceControl.Builder> mSurfaceControlFactory;
     private final Supplier<SurfaceControl.Transaction> mTransactionFactory;
-    private final Supplier<Boolean> mAreCornersRounded;
+    private final BooleanSupplier mAreCornersRounded;
     private final Supplier<Color> mColorSupplier;
     // Parameters for "blurred wallpaper" letterbox background.
-    private final Supplier<Boolean> mHasWallpaperBackgroundSupplier;
-    private final Supplier<Integer> mBlurRadiusSupplier;
-    private final Supplier<Float> mDarkScrimAlphaSupplier;
+    private final BooleanSupplier mHasWallpaperBackgroundSupplier;
+    private final IntSupplier mBlurRadiusSupplier;
+    private final DoubleSupplier mDarkScrimAlphaSupplier;
     private final Supplier<SurfaceControl> mParentSurfaceSupplier;
 
     private final Rect mOuter = new Rect();
@@ -82,11 +85,11 @@ public class Letterbox {
      */
     public Letterbox(Supplier<SurfaceControl.Builder> surfaceControlFactory,
             Supplier<SurfaceControl.Transaction> transactionFactory,
-            Supplier<Boolean> areCornersRounded,
+            BooleanSupplier areCornersRounded,
             Supplier<Color> colorSupplier,
-            Supplier<Boolean> hasWallpaperBackgroundSupplier,
-            Supplier<Integer> blurRadiusSupplier,
-            Supplier<Float> darkScrimAlphaSupplier,
+            BooleanSupplier hasWallpaperBackgroundSupplier,
+            IntSupplier blurRadiusSupplier,
+            DoubleSupplier darkScrimAlphaSupplier,
             IntConsumer doubleTapCallbackX,
             IntConsumer doubleTapCallbackY,
             Supplier<SurfaceControl> parentSurface) {
@@ -247,7 +250,7 @@ public class Letterbox {
      * Returns {@code true} when using {@link #mFullWindowSurface} instead of {@link mSurfaces}.
      */
     private boolean useFullWindowSurface() {
-        return mAreCornersRounded.get() || mHasWallpaperBackgroundSupplier.get();
+        return mAreCornersRounded.getAsBoolean() || mHasWallpaperBackgroundSupplier.getAsBoolean();
     }
 
     private final class TapEventReceiver extends InputEventReceiver {
@@ -424,7 +427,7 @@ public class Letterbox {
                         mSurfaceFrameRelative.height());
                 t.reparent(mSurface, mParentSurface);
 
-                mHasWallpaperBackground = mHasWallpaperBackgroundSupplier.get();
+                mHasWallpaperBackground = mHasWallpaperBackgroundSupplier.getAsBoolean();
                 updateAlphaAndBlur(t);
 
                 t.show(mSurface);
@@ -445,17 +448,17 @@ public class Letterbox {
                 t.setBackgroundBlurRadius(mSurface, 0);
                 return;
             }
-            final float alpha = mDarkScrimAlphaSupplier.get();
+            final float alpha = (float) mDarkScrimAlphaSupplier.getAsDouble();
             t.setAlpha(mSurface, alpha);
 
             // Translucent dark scrim can be shown without blur.
-            if (mBlurRadiusSupplier.get() <= 0) {
+            if (mBlurRadiusSupplier.getAsInt() <= 0) {
                 // Removing pre-exesting blur
                 t.setBackgroundBlurRadius(mSurface, 0);
                 return;
             }
 
-            t.setBackgroundBlurRadius(mSurface, mBlurRadiusSupplier.get());
+            t.setBackgroundBlurRadius(mSurface, mBlurRadiusSupplier.getAsInt());
         }
 
         private float[] getRgbColorArray() {
@@ -472,7 +475,7 @@ public class Letterbox {
                     // and mParentSurface may never be updated in applySurfaceChanges but this
                     // doesn't mean that update is needed.
                     || !mSurfaceFrameRelative.isEmpty()
-                    && (mHasWallpaperBackgroundSupplier.get() != mHasWallpaperBackground
+                    && (mHasWallpaperBackgroundSupplier.getAsBoolean() != mHasWallpaperBackground
                     || !mColorSupplier.get().equals(mColor)
                     || mParentSurfaceSupplier.get() != mParentSurface);
         }
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 71dbd29a0410f61e8cecef73110cc721bbadc5b7..6c31e3e6935067f497336ae52c27e9bdc2f3cc90 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -199,7 +199,6 @@ import com.android.server.Watchdog;
 import com.android.server.am.ActivityManagerService;
 import com.android.server.am.AppTimeTracker;
 import com.android.server.uri.NeededUriGrants;
-import com.android.window.flags.Flags;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -241,7 +240,6 @@ class Task extends TaskFragment {
     private static final String ATTR_ROOT_AFFINITY = "root_affinity";
     private static final String ATTR_ROOTHASRESET = "root_has_reset";
     private static final String ATTR_AUTOREMOVERECENTS = "auto_remove_recents";
-    private static final String ATTR_ASKEDCOMPATMODE = "asked_compat_mode";
     private static final String ATTR_USERID = "user_id";
     private static final String ATTR_USER_SETUP_COMPLETE = "user_setup_complete";
     private static final String ATTR_EFFECTIVE_UID = "effective_uid";
@@ -344,7 +342,6 @@ class Task extends TaskFragment {
                             // the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag.
     boolean autoRemoveRecents;  // If true, we should automatically remove the task from
                                 // recents when activity finishes
-    boolean askedCompatMode;// Have asked the user about compat mode for this task.
     private boolean mHasBeenVisible; // Set if any activities in the task have been visible
 
     String stringName;      // caching of toString() result.
@@ -617,7 +614,7 @@ class Task extends TaskFragment {
     private Task(ActivityTaskManagerService atmService, int _taskId, Intent _intent,
             Intent _affinityIntent, String _affinity, String _rootAffinity,
             ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
-            boolean _autoRemoveRecents, boolean _askedCompatMode, int _userId, int _effectiveUid,
+            boolean _autoRemoveRecents, int _userId, int _effectiveUid,
             String _lastDescription, long lastTimeMoved, boolean neverRelinquishIdentity,
             TaskDescription _lastTaskDescription, PersistedTaskSnapshotData _lastSnapshotData,
             int taskAffiliation, int prevTaskId, int nextTaskId, int callingUid,
@@ -652,7 +649,6 @@ class Task extends TaskFragment {
         rootWasReset = _rootWasReset;
         isAvailable = true;
         autoRemoveRecents = _autoRemoveRecents;
-        askedCompatMode = _askedCompatMode;
         mUserSetupComplete = userSetupComplete;
         effectiveUid = _effectiveUid;
         touchActiveTime();
@@ -3304,7 +3300,7 @@ class Task extends TaskFragment {
         // Once at the root task level, we want to check {@link #isTranslucent(ActivityRecord)}.
         // If true, we want to get the Dimmer from the level above since we don't want to animate
         // the dim with the Task.
-        if (!isRootTask() || (Flags.dimmerRefactor() && isTranslucentAndVisible())
+        if (!isRootTask() || (Dimmer.DIMMER_REFACTOR && isTranslucentAndVisible())
                 || isTranslucent(null)) {
             return super.getDimmer();
         }
@@ -3768,8 +3764,8 @@ class Task extends TaskFragment {
             pw.println(")");
         }
         pw.print(prefix); pw.print("Activities="); pw.println(mChildren);
-        if (!askedCompatMode || !inRecents || !isAvailable) {
-            pw.print(prefix); pw.print("askedCompatMode="); pw.print(askedCompatMode);
+        if (!inRecents || !isAvailable) {
+            pw.print(prefix);
             pw.print(" inRecents="); pw.print(inRecents);
             pw.print(" isAvailable="); pw.println(isAvailable);
         }
@@ -3877,7 +3873,6 @@ class Task extends TaskFragment {
         }
         out.attributeBoolean(null, ATTR_ROOTHASRESET, rootWasReset);
         out.attributeBoolean(null, ATTR_AUTOREMOVERECENTS, autoRemoveRecents);
-        out.attributeBoolean(null, ATTR_ASKEDCOMPATMODE, askedCompatMode);
         out.attributeInt(null, ATTR_USERID, mUserId);
         out.attributeBoolean(null, ATTR_USER_SETUP_COMPLETE, mUserSetupComplete);
         out.attributeInt(null, ATTR_EFFECTIVE_UID, effectiveUid);
@@ -3975,7 +3970,6 @@ class Task extends TaskFragment {
         String windowLayoutAffinity = null;
         boolean rootHasReset = false;
         boolean autoRemoveRecents = false;
-        boolean askedCompatMode = false;
         int taskType = 0;
         int userId = 0;
         boolean userSetupComplete = true;
@@ -4036,9 +4030,6 @@ class Task extends TaskFragment {
                 case ATTR_AUTOREMOVERECENTS:
                     autoRemoveRecents = Boolean.parseBoolean(attrValue);
                     break;
-                case ATTR_ASKEDCOMPATMODE:
-                    askedCompatMode = Boolean.parseBoolean(attrValue);
-                    break;
                 case ATTR_USERID:
                     userId = Integer.parseInt(attrValue);
                     break;
@@ -4192,7 +4183,6 @@ class Task extends TaskFragment {
                 .setOrigActivity(origActivity)
                 .setRootWasReset(rootHasReset)
                 .setAutoRemoveRecents(autoRemoveRecents)
-                .setAskedCompatMode(askedCompatMode)
                 .setUserId(userId)
                 .setEffectiveUid(effectiveUid)
                 .setLastDescription(lastDescription)
@@ -6269,7 +6259,6 @@ class Task extends TaskFragment {
         private ComponentName mOrigActivity;
         private boolean mRootWasReset;
         private boolean mAutoRemoveRecents;
-        private boolean mAskedCompatMode;
         private int mUserId;
         private int mEffectiveUid;
         private String mLastDescription;
@@ -6524,11 +6513,6 @@ class Task extends TaskFragment {
             return this;
         }
 
-        private Builder setAskedCompatMode(boolean askedCompatMode) {
-            mAskedCompatMode = askedCompatMode;
-            return this;
-        }
-
         private Builder setAffinityIntent(Intent affinityIntent) {
             mAffinityIntent = affinityIntent;
             return this;
@@ -6661,7 +6645,7 @@ class Task extends TaskFragment {
         Task buildInner() {
             return new Task(mAtmService, mTaskId, mIntent, mAffinityIntent, mAffinity,
                     mRootAffinity, mRealActivity, mOrigActivity, mRootWasReset, mAutoRemoveRecents,
-                    mAskedCompatMode, mUserId, mEffectiveUid, mLastDescription, mLastTimeMoved,
+                    mUserId, mEffectiveUid, mLastDescription, mLastTimeMoved,
                     mNeverRelinquishIdentity, mLastTaskDescription, mLastSnapshotData,
                     mTaskAffiliation, mPrevAffiliateTaskId, mNextAffiliateTaskId, mCallingUid,
                     mCallingPackage, mCallingFeatureId, mResizeMode, mSupportsPictureInPicture,
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 906b3b55e015361f9b69e58896dacc24fab68de4..82d34246f8571f33bca35d6f0a117acbcb9f1e34 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -103,7 +103,6 @@ import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.server.am.HostingRecord;
 import com.android.server.pm.pkg.AndroidPackage;
-import com.android.window.flags.Flags;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -210,7 +209,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
      */
     int mMinHeight;
 
-    Dimmer mDimmer = Flags.dimmerRefactor()
+    Dimmer mDimmer = Dimmer.DIMMER_REFACTOR
             ? new SmoothDimmer(this) : new LegacyDimmer(this);
 
     /** Apply the dim layer on the embedded TaskFragment. */
@@ -391,41 +390,6 @@ class TaskFragment extends WindowContainer<WindowContainer> {
 
     private final EnsureActivitiesVisibleHelper mEnsureActivitiesVisibleHelper =
             new EnsureActivitiesVisibleHelper(this);
-    private final EnsureVisibleActivitiesConfigHelper mEnsureVisibleActivitiesConfigHelper =
-            new EnsureVisibleActivitiesConfigHelper();
-    private class EnsureVisibleActivitiesConfigHelper implements Predicate<ActivityRecord> {
-        private boolean mUpdateConfig;
-        private boolean mPreserveWindow;
-        private boolean mBehindFullscreen;
-
-        void reset(boolean preserveWindow) {
-            mPreserveWindow = preserveWindow;
-            mUpdateConfig = false;
-            mBehindFullscreen = false;
-        }
-
-        void process(ActivityRecord start, boolean preserveWindow) {
-            if (start == null || !start.isVisibleRequested()) {
-                return;
-            }
-            reset(preserveWindow);
-            forAllActivities(this, start, true /* includeBoundary */,
-                    true /* traverseTopToBottom */);
-
-            if (mUpdateConfig) {
-                // Ensure the resumed state of the focus activity if we updated the configuration of
-                // any activity.
-                mRootWindowContainer.resumeFocusedTasksTopActivities();
-            }
-        }
-
-        @Override
-        public boolean test(ActivityRecord r) {
-            mUpdateConfig |= r.ensureActivityConfiguration(0 /*globalChanges*/, mPreserveWindow);
-            mBehindFullscreen |= r.occludesParent();
-            return mBehindFullscreen;
-        }
-    }
 
     /** Creates an embedded task fragment. */
     TaskFragment(ActivityTaskManagerService atmService, IBinder fragmentToken,
@@ -2163,13 +2127,6 @@ class TaskFragment extends WindowContainer<WindowContainer> {
         return getTask() != null ? getTask().mTaskId : INVALID_TASK_ID;
     }
 
-    /**
-     * Ensures all visible activities at or below the input activity have the right configuration.
-     */
-    void ensureVisibleActivitiesConfiguration(ActivityRecord start, boolean preserveWindow) {
-        mEnsureVisibleActivitiesConfigHelper.process(start, preserveWindow);
-    }
-
     void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
             @NonNull Configuration parentConfig) {
         computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */,
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 924e2f8ec65481b5bf7d8322e657ae689a90e2e2..0d024d6a4c587e8043ce20a2696969eebd5f999a 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -2083,17 +2083,14 @@ public final class SystemServer implements Dumpable {
                 t.traceEnd();
             }
 
-            // Devices without WebView/JavaScript cannot support PAC proxies.
-            if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WEBVIEW)) {
-                t.traceBegin("StartPacProxyService");
-                try {
-                    pacProxyService = new PacProxyService(context);
-                    ServiceManager.addService(Context.PAC_PROXY_SERVICE, pacProxyService);
-                } catch (Throwable e) {
-                    reportWtf("starting PacProxyService", e);
-                }
-                t.traceEnd();
+            t.traceBegin("StartPacProxyService");
+            try {
+                pacProxyService = new PacProxyService(context);
+                ServiceManager.addService(Context.PAC_PROXY_SERVICE, pacProxyService);
+            } catch (Throwable e) {
+                reportWtf("starting PacProxyService", e);
             }
+            t.traceEnd();
 
             t.traceBegin("StartConnectivityService");
             // This has to be called after NetworkManagementService, NetworkStatsService
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java
index aaad669d5b8daafa1ff754579e68ea640a386096..2810145c08a9fb5e9cc1322f2d29fb5341802b9e 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -1051,7 +1051,6 @@ public class PackageManagerSettingsTests {
                 null /*usesStaticLibrariesVersions*/,
                 null /*mimeGroups*/,
                 UUID.randomUUID(),
-                false /*isPersistent*/,
                 34 /*targetSdkVersion*/,
                 null /*restrictUpdateHash*/);
         assertThat(testPkgSetting01.getPrimaryCpuAbi(), is("arm64-v8a"));
@@ -1092,7 +1091,6 @@ public class PackageManagerSettingsTests {
                 null /*usesStaticLibrariesVersions*/,
                 null /*mimeGroups*/,
                 UUID.randomUUID(),
-                false /*isPersistent*/,
                 34 /*targetSdkVersion*/,
                 null /*restrictUpdateHash*/);
         assertThat(testPkgSetting01.getPrimaryCpuAbi(), is("arm64-v8a"));
@@ -1135,7 +1133,6 @@ public class PackageManagerSettingsTests {
                     null /*usesStaticLibrariesVersions*/,
                     null /*mimeGroups*/,
                     UUID.randomUUID(),
-                    false /*isPersistent*/,
                     34 /*targetSdkVersion*/,
                     null /*restrictUpdateHash*/);
             fail("Expected a PackageManagerException");
@@ -1174,7 +1171,6 @@ public class PackageManagerSettingsTests {
                 null /*usesStaticLibrariesVersions*/,
                 null /*mimeGroups*/,
                 UUID.randomUUID(),
-                false /*isPersistent*/,
                 34 /*targetSdkVersion*/,
                 null /*restrictUpdateHash*/);
         assertThat(testPkgSetting01.getPath(), is(UPDATED_CODE_PATH));
@@ -1222,7 +1218,6 @@ public class PackageManagerSettingsTests {
                 null /*usesStaticLibrariesVersions*/,
                 null /*mimeGroups*/,
                 UUID.randomUUID(),
-                false /*isPersistent*/,
                 34 /*targetSdkVersion*/,
                 null /*restrictUpdateHash*/);
         assertThat(testPkgSetting01.getAppId(), is(0));
@@ -1270,7 +1265,6 @@ public class PackageManagerSettingsTests {
                 null /*usesStaticLibrariesVersions*/,
                 null /*mimeGroups*/,
                 UUID.randomUUID(),
-                false /*isPersistent*/,
                 34 /*targetSdkVersion*/,
                 null /*restrictUpdateHash*/);
         assertThat(testPkgSetting01.getAppId(), is(10064));
@@ -1319,7 +1313,6 @@ public class PackageManagerSettingsTests {
                 null /*usesStaticLibrariesVersions*/,
                 null /*mimeGroups*/,
                 UUID.randomUUID(),
-                false /*isPersistent*/,
                 34 /*targetSdkVersion*/,
                 null /*restrictUpdateHash*/);
         assertThat(testPkgSetting01.getAppId(), is(10064));
@@ -1365,7 +1358,6 @@ public class PackageManagerSettingsTests {
                 null /*usesStaticLibrariesVersions*/,
                 null /*mimeGroups*/,
                 UUID.randomUUID(),
-                false /*isPersistent*/,
                 34 /*targetSdkVersion*/,
                 null /*restrictUpdateHash*/);
         assertThat(testPkgSetting01.getAppId(), is(0));
diff --git a/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java
index 5cc84b197e0327346a0ca863bd785db4ab1c3629..78bf9b0bc828f43c3b1adada86e44483a23e7c19 100644
--- a/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java
@@ -24,7 +24,6 @@ import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 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;
 
@@ -44,7 +43,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.server.LocalServices;
-import com.android.server.contentprotection.ContentProtectionBlocklistManager;
+import com.android.server.contentprotection.ContentProtectionAllowlistManager;
 import com.android.server.contentprotection.ContentProtectionConsentManager;
 import com.android.server.contentprotection.RemoteContentProtectionService;
 import com.android.server.pm.UserManagerInternal;
@@ -94,7 +93,7 @@ public class ContentCaptureManagerServiceTest {
 
     @Mock private UserManagerInternal mMockUserManagerInternal;
 
-    @Mock private ContentProtectionBlocklistManager mMockContentProtectionBlocklistManager;
+    @Mock private ContentProtectionAllowlistManager mMockContentProtectionAllowlistManager;
 
     @Mock private ContentCaptureServiceInfo mMockContentCaptureServiceInfo;
 
@@ -108,7 +107,7 @@ public class ContentCaptureManagerServiceTest {
 
     private List<List<String>> mDevCfgContentProtectionOptionalGroups = Collections.emptyList();
 
-    private int mContentProtectionBlocklistManagersCreated;
+    private int mContentProtectionAllowlistManagersCreated;
 
     private int mContentProtectionServiceInfosCreated;
 
@@ -132,10 +131,10 @@ public class ContentCaptureManagerServiceTest {
 
     @Test
     public void constructor_contentProtection_flagDisabled_noManagers() {
-        assertThat(mContentProtectionBlocklistManagersCreated).isEqualTo(0);
+        assertThat(mContentProtectionAllowlistManagersCreated).isEqualTo(0);
         assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0);
         assertThat(mContentProtectionConsentManagersCreated).isEqualTo(0);
-        verifyZeroInteractions(mMockContentProtectionBlocklistManager);
+        verifyZeroInteractions(mMockContentProtectionAllowlistManager);
         verifyZeroInteractions(mMockContentProtectionConsentManager);
     }
 
@@ -145,10 +144,10 @@ public class ContentCaptureManagerServiceTest {
 
         mContentCaptureManagerService = new TestContentCaptureManagerService();
 
-        assertThat(mContentProtectionBlocklistManagersCreated).isEqualTo(0);
+        assertThat(mContentProtectionAllowlistManagersCreated).isEqualTo(0);
         assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0);
         assertThat(mContentProtectionConsentManagersCreated).isEqualTo(0);
-        verifyZeroInteractions(mMockContentProtectionBlocklistManager);
+        verifyZeroInteractions(mMockContentProtectionAllowlistManager);
         verifyZeroInteractions(mMockContentProtectionConsentManager);
     }
 
@@ -158,10 +157,10 @@ public class ContentCaptureManagerServiceTest {
 
         mContentCaptureManagerService = new TestContentCaptureManagerService();
 
-        assertThat(mContentProtectionBlocklistManagersCreated).isEqualTo(0);
+        assertThat(mContentProtectionAllowlistManagersCreated).isEqualTo(0);
         assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0);
         assertThat(mContentProtectionConsentManagersCreated).isEqualTo(0);
-        verifyZeroInteractions(mMockContentProtectionBlocklistManager);
+        verifyZeroInteractions(mMockContentProtectionAllowlistManager);
         verifyZeroInteractions(mMockContentProtectionConsentManager);
     }
 
@@ -171,25 +170,12 @@ public class ContentCaptureManagerServiceTest {
 
         mContentCaptureManagerService = new TestContentCaptureManagerService();
 
-        assertThat(mContentProtectionBlocklistManagersCreated).isEqualTo(1);
+        assertThat(mContentProtectionAllowlistManagersCreated).isEqualTo(1);
         assertThat(mContentProtectionConsentManagersCreated).isEqualTo(1);
         assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0);
-        verify(mMockContentProtectionBlocklistManager).updateBlocklist(anyInt());
         verifyZeroInteractions(mMockContentProtectionConsentManager);
     }
 
-    @Test
-    public void setFineTuneParamsFromDeviceConfig_doesNotUpdateContentProtectionBlocklist() {
-        mDevCfgEnableContentProtectionReceiver = true;
-        mContentCaptureManagerService = new TestContentCaptureManagerService();
-        mContentCaptureManagerService.mDevCfgContentProtectionAppsBlocklistSize += 100;
-        verify(mMockContentProtectionBlocklistManager).updateBlocklist(anyInt());
-
-        mContentCaptureManagerService.setFineTuneParamsFromDeviceConfig();
-
-        verifyNoMoreInteractions(mMockContentProtectionBlocklistManager);
-    }
-
     @Test
     public void getOptions_contentCaptureDisabled_contentProtectionDisabled() {
         mDevCfgEnableContentProtectionReceiver = true;
@@ -201,13 +187,13 @@ public class ContentCaptureManagerServiceTest {
 
         assertThat(actual).isNull();
         verify(mMockContentProtectionConsentManager).isConsentGranted(USER_ID);
-        verify(mMockContentProtectionBlocklistManager, never()).isAllowed(anyString());
+        verify(mMockContentProtectionAllowlistManager, never()).isAllowed(anyString());
     }
 
     @Test
     public void getOptions_contentCaptureDisabled_contentProtectionEnabled() {
         when(mMockContentProtectionConsentManager.isConsentGranted(USER_ID)).thenReturn(true);
-        when(mMockContentProtectionBlocklistManager.isAllowed(PACKAGE_NAME)).thenReturn(true);
+        when(mMockContentProtectionAllowlistManager.isAllowed(PACKAGE_NAME)).thenReturn(true);
         mDevCfgEnableContentProtectionReceiver = true;
         mContentCaptureManagerService = new TestContentCaptureManagerService();
 
@@ -239,13 +225,13 @@ public class ContentCaptureManagerServiceTest {
         assertThat(actual.contentProtectionOptions.enableReceiver).isFalse();
         assertThat(actual.whitelistedComponents).isNull();
         verify(mMockContentProtectionConsentManager).isConsentGranted(USER_ID);
-        verify(mMockContentProtectionBlocklistManager, never()).isAllowed(anyString());
+        verify(mMockContentProtectionAllowlistManager, never()).isAllowed(anyString());
     }
 
     @Test
     public void getOptions_contentCaptureEnabled_contentProtectionEnabled() {
         when(mMockContentProtectionConsentManager.isConsentGranted(USER_ID)).thenReturn(true);
-        when(mMockContentProtectionBlocklistManager.isAllowed(PACKAGE_NAME)).thenReturn(true);
+        when(mMockContentProtectionAllowlistManager.isAllowed(PACKAGE_NAME)).thenReturn(true);
         mDevCfgEnableContentProtectionReceiver = true;
         mContentCaptureManagerService = new TestContentCaptureManagerService();
         mContentCaptureManagerService.mGlobalContentCaptureOptions.setWhitelist(
@@ -273,7 +259,7 @@ public class ContentCaptureManagerServiceTest {
 
         assertThat(actual).isFalse();
         verify(mMockContentProtectionConsentManager).isConsentGranted(USER_ID);
-        verify(mMockContentProtectionBlocklistManager, never()).isAllowed(anyString());
+        verify(mMockContentProtectionAllowlistManager, never()).isAllowed(anyString());
     }
 
     @Test
@@ -287,13 +273,13 @@ public class ContentCaptureManagerServiceTest {
                         USER_ID, PACKAGE_NAME);
 
         assertThat(actual).isFalse();
-        verify(mMockContentProtectionBlocklistManager).isAllowed(PACKAGE_NAME);
+        verify(mMockContentProtectionAllowlistManager).isAllowed(PACKAGE_NAME);
     }
 
     @Test
     public void isWhitelisted_packageName_contentCaptureDisabled_contentProtectionEnabled() {
         when(mMockContentProtectionConsentManager.isConsentGranted(USER_ID)).thenReturn(true);
-        when(mMockContentProtectionBlocklistManager.isAllowed(PACKAGE_NAME)).thenReturn(true);
+        when(mMockContentProtectionAllowlistManager.isAllowed(PACKAGE_NAME)).thenReturn(true);
         mDevCfgEnableContentProtectionReceiver = true;
         mContentCaptureManagerService = new TestContentCaptureManagerService();
 
@@ -317,7 +303,7 @@ public class ContentCaptureManagerServiceTest {
 
         assertThat(actual).isTrue();
         verify(mMockContentProtectionConsentManager, never()).isConsentGranted(anyInt());
-        verify(mMockContentProtectionBlocklistManager, never()).isAllowed(anyString());
+        verify(mMockContentProtectionAllowlistManager, never()).isAllowed(anyString());
     }
 
     @Test
@@ -331,7 +317,7 @@ public class ContentCaptureManagerServiceTest {
 
         assertThat(actual).isFalse();
         verify(mMockContentProtectionConsentManager).isConsentGranted(USER_ID);
-        verify(mMockContentProtectionBlocklistManager, never()).isAllowed(anyString());
+        verify(mMockContentProtectionAllowlistManager, never()).isAllowed(anyString());
     }
 
     @Test
@@ -345,13 +331,13 @@ public class ContentCaptureManagerServiceTest {
                         USER_ID, COMPONENT_NAME);
 
         assertThat(actual).isFalse();
-        verify(mMockContentProtectionBlocklistManager).isAllowed(PACKAGE_NAME);
+        verify(mMockContentProtectionAllowlistManager).isAllowed(PACKAGE_NAME);
     }
 
     @Test
     public void isWhitelisted_componentName_contentCaptureDisabled_contentProtectionEnabled() {
         when(mMockContentProtectionConsentManager.isConsentGranted(USER_ID)).thenReturn(true);
-        when(mMockContentProtectionBlocklistManager.isAllowed(PACKAGE_NAME)).thenReturn(true);
+        when(mMockContentProtectionAllowlistManager.isAllowed(PACKAGE_NAME)).thenReturn(true);
         mDevCfgEnableContentProtectionReceiver = true;
         mContentCaptureManagerService = new TestContentCaptureManagerService();
 
@@ -375,13 +361,13 @@ public class ContentCaptureManagerServiceTest {
 
         assertThat(actual).isTrue();
         verify(mMockContentProtectionConsentManager, never()).isConsentGranted(anyInt());
-        verify(mMockContentProtectionBlocklistManager, never()).isAllowed(anyString());
+        verify(mMockContentProtectionAllowlistManager, never()).isAllowed(anyString());
     }
 
     @Test
     public void isContentProtectionReceiverEnabled_true() {
         when(mMockContentProtectionConsentManager.isConsentGranted(USER_ID)).thenReturn(true);
-        when(mMockContentProtectionBlocklistManager.isAllowed(PACKAGE_NAME)).thenReturn(true);
+        when(mMockContentProtectionAllowlistManager.isAllowed(PACKAGE_NAME)).thenReturn(true);
         mDevCfgEnableContentProtectionReceiver = true;
         mContentCaptureManagerService = new TestContentCaptureManagerService();
 
@@ -400,7 +386,7 @@ public class ContentCaptureManagerServiceTest {
 
         assertThat(actual).isFalse();
         verify(mMockContentProtectionConsentManager, never()).isConsentGranted(anyInt());
-        verify(mMockContentProtectionBlocklistManager, never()).isAllowed(anyString());
+        verify(mMockContentProtectionAllowlistManager, never()).isAllowed(anyString());
     }
 
     @Test
@@ -415,7 +401,7 @@ public class ContentCaptureManagerServiceTest {
 
         assertThat(actual).isFalse();
         verify(mMockContentProtectionConsentManager, never()).isConsentGranted(anyInt());
-        verify(mMockContentProtectionBlocklistManager, never()).isAllowed(anyString());
+        verify(mMockContentProtectionAllowlistManager, never()).isAllowed(anyString());
     }
 
     @Test
@@ -431,7 +417,7 @@ public class ContentCaptureManagerServiceTest {
 
         assertThat(actual).isFalse();
         verify(mMockContentProtectionConsentManager, never()).isConsentGranted(anyInt());
-        verify(mMockContentProtectionBlocklistManager, never()).isAllowed(anyString());
+        verify(mMockContentProtectionAllowlistManager, never()).isAllowed(anyString());
     }
 
     @Test
@@ -572,9 +558,9 @@ public class ContentCaptureManagerServiceTest {
         }
 
         @Override
-        protected ContentProtectionBlocklistManager createContentProtectionBlocklistManager() {
-            mContentProtectionBlocklistManagersCreated++;
-            return mMockContentProtectionBlocklistManager;
+        protected ContentProtectionAllowlistManager createContentProtectionAllowlistManager() {
+            mContentProtectionAllowlistManagersCreated++;
+            return mMockContentProtectionAllowlistManager;
         }
 
         @Override
diff --git a/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionAllowlistManagerTest.java b/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionAllowlistManagerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..6767a85035feaab1e2415547f2a505d7a911239f
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionAllowlistManagerTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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.server.contentprotection;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+/**
+ * Test for {@link ContentProtectionAllowlistManager}.
+ *
+ * <p>Run with: {@code atest FrameworksServicesTests:
+ * com.android.server.contentprotection.ContentProtectionAllowlistManagerTest}
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ContentProtectionAllowlistManagerTest {
+
+    private static final String PACKAGE_NAME = "com.test.package.name";
+
+    @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+    private ContentProtectionAllowlistManager mContentProtectionAllowlistManager;
+
+    @Before
+    public void setup() {
+        mContentProtectionAllowlistManager = new ContentProtectionAllowlistManager();
+    }
+
+    @Test
+    public void isAllowed() {
+        boolean actual = mContentProtectionAllowlistManager.isAllowed(PACKAGE_NAME);
+
+        assertThat(actual).isFalse();
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionBlocklistManagerTest.java b/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionBlocklistManagerTest.java
deleted file mode 100644
index ba9956a63dca829115678f491fcb00cfc4e81cd6..0000000000000000000000000000000000000000
--- a/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionBlocklistManagerTest.java
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * 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.server.contentprotection;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-
-import android.annotation.NonNull;
-import android.content.pm.PackageInfo;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import com.google.common.collect.ImmutableList;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Test for {@link ContentProtectionBlocklistManager}.
- *
- * <p>Run with: {@code atest
- * FrameworksServicesTests:
- * com.android.server.contentprotection.ContentProtectionBlocklistManagerTest}
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class ContentProtectionBlocklistManagerTest {
-
-    private static final String FIRST_PACKAGE_NAME = "com.test.first.package.name";
-
-    private static final String SECOND_PACKAGE_NAME = "com.test.second.package.name";
-
-    private static final String UNLISTED_PACKAGE_NAME = "com.test.unlisted.package.name";
-
-    private static final String PACKAGE_NAME_BLOCKLIST_FILENAME =
-            "/product/etc/res/raw/content_protection/package_name_blocklist.txt";
-
-    private static final PackageInfo PACKAGE_INFO = new PackageInfo();
-
-    private static final List<String> LINES =
-            ImmutableList.of(FIRST_PACKAGE_NAME, SECOND_PACKAGE_NAME);
-
-    @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
-
-    @Mock private ContentProtectionPackageManager mMockContentProtectionPackageManager;
-
-    private final List<String> mReadRawFiles = new ArrayList<>();
-
-    private ContentProtectionBlocklistManager mContentProtectionBlocklistManager;
-
-    @Before
-    public void setup() {
-        mContentProtectionBlocklistManager = new TestContentProtectionBlocklistManager();
-    }
-
-    @Test
-    public void isAllowed_blocklistNotLoaded() {
-        boolean actual = mContentProtectionBlocklistManager.isAllowed(FIRST_PACKAGE_NAME);
-
-        assertThat(actual).isFalse();
-        assertThat(mReadRawFiles).isEmpty();
-        verifyZeroInteractions(mMockContentProtectionPackageManager);
-    }
-
-    @Test
-    public void isAllowed_inBlocklist() {
-        mContentProtectionBlocklistManager.updateBlocklist(LINES.size());
-
-        boolean actual = mContentProtectionBlocklistManager.isAllowed(FIRST_PACKAGE_NAME);
-
-        assertThat(actual).isFalse();
-        verifyZeroInteractions(mMockContentProtectionPackageManager);
-    }
-
-    @Test
-    public void isAllowed_packageInfoNotFound() {
-        mContentProtectionBlocklistManager.updateBlocklist(LINES.size());
-        when(mMockContentProtectionPackageManager.getPackageInfo(UNLISTED_PACKAGE_NAME))
-                .thenReturn(null);
-
-        boolean actual = mContentProtectionBlocklistManager.isAllowed(UNLISTED_PACKAGE_NAME);
-
-        assertThat(actual).isFalse();
-        verify(mMockContentProtectionPackageManager, never())
-                .hasRequestedInternetPermissions(any());
-        verify(mMockContentProtectionPackageManager, never()).isSystemApp(any());
-        verify(mMockContentProtectionPackageManager, never()).isUpdatedSystemApp(any());
-    }
-
-    @Test
-    public void isAllowed_notRequestedInternet() {
-        mContentProtectionBlocklistManager.updateBlocklist(LINES.size());
-        when(mMockContentProtectionPackageManager.getPackageInfo(UNLISTED_PACKAGE_NAME))
-                .thenReturn(PACKAGE_INFO);
-        when(mMockContentProtectionPackageManager.hasRequestedInternetPermissions(PACKAGE_INFO))
-                .thenReturn(false);
-
-        boolean actual = mContentProtectionBlocklistManager.isAllowed(UNLISTED_PACKAGE_NAME);
-
-        assertThat(actual).isFalse();
-        verify(mMockContentProtectionPackageManager, never()).isSystemApp(any());
-        verify(mMockContentProtectionPackageManager, never()).isUpdatedSystemApp(any());
-    }
-
-    @Test
-    public void isAllowed_systemApp() {
-        mContentProtectionBlocklistManager.updateBlocklist(LINES.size());
-        when(mMockContentProtectionPackageManager.getPackageInfo(UNLISTED_PACKAGE_NAME))
-                .thenReturn(PACKAGE_INFO);
-        when(mMockContentProtectionPackageManager.hasRequestedInternetPermissions(PACKAGE_INFO))
-                .thenReturn(true);
-        when(mMockContentProtectionPackageManager.isSystemApp(PACKAGE_INFO)).thenReturn(true);
-
-        boolean actual = mContentProtectionBlocklistManager.isAllowed(UNLISTED_PACKAGE_NAME);
-
-        assertThat(actual).isFalse();
-        verify(mMockContentProtectionPackageManager, never()).isUpdatedSystemApp(any());
-    }
-
-    @Test
-    public void isAllowed_updatedSystemApp() {
-        mContentProtectionBlocklistManager.updateBlocklist(LINES.size());
-        when(mMockContentProtectionPackageManager.getPackageInfo(UNLISTED_PACKAGE_NAME))
-                .thenReturn(PACKAGE_INFO);
-        when(mMockContentProtectionPackageManager.hasRequestedInternetPermissions(PACKAGE_INFO))
-                .thenReturn(true);
-        when(mMockContentProtectionPackageManager.isSystemApp(PACKAGE_INFO)).thenReturn(true);
-        when(mMockContentProtectionPackageManager.isUpdatedSystemApp(PACKAGE_INFO))
-                .thenReturn(true);
-
-        boolean actual = mContentProtectionBlocklistManager.isAllowed(UNLISTED_PACKAGE_NAME);
-
-        assertThat(actual).isFalse();
-    }
-
-    @Test
-    public void isAllowed_allowed() {
-        mContentProtectionBlocklistManager.updateBlocklist(LINES.size());
-        when(mMockContentProtectionPackageManager.getPackageInfo(UNLISTED_PACKAGE_NAME))
-                .thenReturn(PACKAGE_INFO);
-        when(mMockContentProtectionPackageManager.hasRequestedInternetPermissions(PACKAGE_INFO))
-                .thenReturn(true);
-        when(mMockContentProtectionPackageManager.isSystemApp(PACKAGE_INFO)).thenReturn(false);
-        when(mMockContentProtectionPackageManager.isUpdatedSystemApp(PACKAGE_INFO))
-                .thenReturn(false);
-
-        boolean actual = mContentProtectionBlocklistManager.isAllowed(UNLISTED_PACKAGE_NAME);
-
-        assertThat(actual).isTrue();
-    }
-
-    @Test
-    public void updateBlocklist_negativeSize() {
-        mContentProtectionBlocklistManager.updateBlocklist(/* blocklistSize= */ -1);
-        assertThat(mReadRawFiles).isEmpty();
-
-        mContentProtectionBlocklistManager.isAllowed(FIRST_PACKAGE_NAME);
-        verify(mMockContentProtectionPackageManager).getPackageInfo(FIRST_PACKAGE_NAME);
-    }
-
-    @Test
-    public void updateBlocklist_zeroSize() {
-        mContentProtectionBlocklistManager.updateBlocklist(/* blocklistSize= */ 0);
-        assertThat(mReadRawFiles).isEmpty();
-
-        mContentProtectionBlocklistManager.isAllowed(FIRST_PACKAGE_NAME);
-        verify(mMockContentProtectionPackageManager).getPackageInfo(FIRST_PACKAGE_NAME);
-    }
-
-    @Test
-    public void updateBlocklist_positiveSize_belowTotal() {
-        mContentProtectionBlocklistManager.updateBlocklist(/* blocklistSize= */ 1);
-        assertThat(mReadRawFiles).containsExactly(PACKAGE_NAME_BLOCKLIST_FILENAME);
-
-        mContentProtectionBlocklistManager.isAllowed(FIRST_PACKAGE_NAME);
-        mContentProtectionBlocklistManager.isAllowed(SECOND_PACKAGE_NAME);
-
-        verify(mMockContentProtectionPackageManager, never()).getPackageInfo(FIRST_PACKAGE_NAME);
-        verify(mMockContentProtectionPackageManager).getPackageInfo(SECOND_PACKAGE_NAME);
-    }
-
-    @Test
-    public void updateBlocklist_positiveSize_aboveTotal() {
-        mContentProtectionBlocklistManager.updateBlocklist(LINES.size() + 1);
-        assertThat(mReadRawFiles).containsExactly(PACKAGE_NAME_BLOCKLIST_FILENAME);
-
-        mContentProtectionBlocklistManager.isAllowed(FIRST_PACKAGE_NAME);
-        mContentProtectionBlocklistManager.isAllowed(SECOND_PACKAGE_NAME);
-
-        verify(mMockContentProtectionPackageManager, never()).getPackageInfo(FIRST_PACKAGE_NAME);
-        verify(mMockContentProtectionPackageManager, never()).getPackageInfo(SECOND_PACKAGE_NAME);
-    }
-
-    private final class TestContentProtectionBlocklistManager
-            extends ContentProtectionBlocklistManager {
-
-        TestContentProtectionBlocklistManager() {
-            super(mMockContentProtectionPackageManager);
-        }
-
-        @Override
-        protected List<String> readLinesFromRawFile(@NonNull String filename) {
-            mReadRawFiles.add(filename);
-            return LINES;
-        }
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionPackageManagerTest.java b/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionPackageManagerTest.java
deleted file mode 100644
index 7d45ea4ce39aa8a1baa248c0eaeedc95445da4bc..0000000000000000000000000000000000000000
--- a/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionPackageManagerTest.java
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * 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.server.contentprotection;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.when;
-
-import android.Manifest.permission;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.PackageManager.PackageInfoFlags;
-import android.testing.TestableContext;
-
-import androidx.test.core.app.ApplicationProvider;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-/**
- * Test for {@link ContentProtectionPackageManager}.
- *
- * <p>Run with: {@code atest
- * FrameworksServicesTests:com.android.server.contentprotection.ContentProtectionPackageManagerTest}
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class ContentProtectionPackageManagerTest {
-    private static final String PACKAGE_NAME = "PACKAGE_NAME";
-
-    private static final PackageInfo EMPTY_PACKAGE_INFO = new PackageInfo();
-
-    private static final PackageInfo SYSTEM_APP_PACKAGE_INFO = createSystemAppPackageInfo();
-
-    private static final PackageInfo UPDATED_SYSTEM_APP_PACKAGE_INFO =
-            createUpdatedSystemAppPackageInfo();
-
-    @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
-
-    @Rule
-    public final TestableContext mContext =
-            new TestableContext(ApplicationProvider.getApplicationContext());
-
-    @Mock private PackageManager mMockPackageManager;
-
-    private ContentProtectionPackageManager mContentProtectionPackageManager;
-
-    @Before
-    public void setup() {
-        mContext.setMockPackageManager(mMockPackageManager);
-        mContentProtectionPackageManager = new ContentProtectionPackageManager(mContext);
-    }
-
-    @Test
-    public void getPackageInfo_found() throws Exception {
-        PackageInfo expected = createPackageInfo(/* flags= */ 0);
-        when(mMockPackageManager.getPackageInfo(eq(PACKAGE_NAME), any(PackageInfoFlags.class)))
-                .thenReturn(expected);
-
-        PackageInfo actual = mContentProtectionPackageManager.getPackageInfo(PACKAGE_NAME);
-
-        assertThat(actual).isEqualTo(expected);
-    }
-
-    @Test
-    public void getPackageInfo_notFound() throws Exception {
-        when(mMockPackageManager.getPackageInfo(eq(PACKAGE_NAME), any(PackageInfoFlags.class)))
-                .thenThrow(new NameNotFoundException());
-
-        PackageInfo actual = mContentProtectionPackageManager.getPackageInfo(PACKAGE_NAME);
-
-        assertThat(actual).isNull();
-    }
-
-    @Test
-    public void getPackageInfo_null() {
-        PackageInfo actual = mContentProtectionPackageManager.getPackageInfo(PACKAGE_NAME);
-
-        assertThat(actual).isNull();
-    }
-
-    @Test
-    public void isSystemApp_true() {
-        boolean actual = mContentProtectionPackageManager.isSystemApp(SYSTEM_APP_PACKAGE_INFO);
-
-        assertThat(actual).isTrue();
-    }
-
-    @Test
-    public void isSystemApp_false() {
-        boolean actual =
-                mContentProtectionPackageManager.isSystemApp(UPDATED_SYSTEM_APP_PACKAGE_INFO);
-
-        assertThat(actual).isFalse();
-    }
-
-    @Test
-    public void isSystemApp_noApplicationInfo() {
-        boolean actual = mContentProtectionPackageManager.isSystemApp(EMPTY_PACKAGE_INFO);
-
-        assertThat(actual).isFalse();
-    }
-
-    @Test
-    public void isUpdatedSystemApp_true() {
-        boolean actual =
-                mContentProtectionPackageManager.isUpdatedSystemApp(
-                        UPDATED_SYSTEM_APP_PACKAGE_INFO);
-
-        assertThat(actual).isTrue();
-    }
-
-    @Test
-    public void isUpdatedSystemApp_false() {
-        boolean actual =
-                mContentProtectionPackageManager.isUpdatedSystemApp(SYSTEM_APP_PACKAGE_INFO);
-
-        assertThat(actual).isFalse();
-    }
-
-    @Test
-    public void isUpdatedSystemApp_noApplicationInfo() {
-        boolean actual = mContentProtectionPackageManager.isUpdatedSystemApp(EMPTY_PACKAGE_INFO);
-
-        assertThat(actual).isFalse();
-    }
-
-    @Test
-    public void hasRequestedInternetPermissions_true() {
-        PackageInfo packageInfo = createPackageInfo(new String[] {permission.INTERNET});
-
-        boolean actual =
-                mContentProtectionPackageManager.hasRequestedInternetPermissions(packageInfo);
-
-        assertThat(actual).isTrue();
-    }
-
-    @Test
-    public void hasRequestedInternetPermissions_false() {
-        PackageInfo packageInfo = createPackageInfo(new String[] {permission.ACCESS_FINE_LOCATION});
-
-        boolean actual =
-                mContentProtectionPackageManager.hasRequestedInternetPermissions(packageInfo);
-
-        assertThat(actual).isFalse();
-    }
-
-    @Test
-    public void hasRequestedInternetPermissions_noRequestedPermissions() {
-        boolean actual =
-                mContentProtectionPackageManager.hasRequestedInternetPermissions(
-                        EMPTY_PACKAGE_INFO);
-
-        assertThat(actual).isFalse();
-    }
-
-    private static PackageInfo createSystemAppPackageInfo() {
-        return createPackageInfo(ApplicationInfo.FLAG_SYSTEM);
-    }
-
-    private static PackageInfo createUpdatedSystemAppPackageInfo() {
-        return createPackageInfo(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP);
-    }
-
-    private static PackageInfo createPackageInfo(int flags) {
-        return createPackageInfo(flags, /* requestedPermissions= */ new String[0]);
-    }
-
-    private static PackageInfo createPackageInfo(String[] requestedPermissions) {
-        return createPackageInfo(/* flags= */ 0, requestedPermissions);
-    }
-
-    private static PackageInfo createPackageInfo(int flags, String[] requestedPermissions) {
-        PackageInfo packageInfo = new PackageInfo();
-        packageInfo.packageName = PACKAGE_NAME;
-        packageInfo.applicationInfo = new ApplicationInfo();
-        packageInfo.applicationInfo.packageName = PACKAGE_NAME;
-        packageInfo.applicationInfo.flags = flags;
-        packageInfo.requestedPermissions = requestedPermissions;
-        return packageInfo;
-    }
-}
diff --git a/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java b/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
index 61c4d06131e16bf489dcddce85ac6a8430ccf0d9..270d5df5e702b8df64dce30d6339c52ddb550ede 100644
--- a/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
+++ b/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
@@ -203,5 +203,6 @@ class ShortcutKeyTestBase {
                 mPhoneWindowManager.dispatchUnhandledKey(keyEvent);
             }
         }
+        mPhoneWindowManager.dispatchAllPendingEvents();
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java b/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java
index 8e870681bb83c2f6dd57eeb053b41b573ce604ae..f2721a556454d1fca3031096f579070d18341b07 100644
--- a/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java
@@ -30,6 +30,7 @@ import static org.junit.Assert.assertTrue;
 
 import android.app.Instrumentation;
 import android.content.Context;
+import android.os.Looper;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Process;
@@ -80,7 +81,7 @@ public class SingleKeyGestureTests {
     public void setUp() {
         mInstrumentation.runOnMainSync(
                 () -> {
-                    mDetector = SingleKeyGestureDetector.get(mContext);
+                    mDetector = SingleKeyGestureDetector.get(mContext, Looper.myLooper());
                     initSingleKeyGestureRules();
                 });
 
diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
index 261d3cc3c8d9606ca80161fbad82753964c525de..e26260a6836cceaf1b9e00dc9c170125ce917c57 100644
--- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
+++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
@@ -118,7 +118,6 @@ import org.mockito.quality.Strictness;
 import java.util.function.Supplier;
 
 class TestPhoneWindowManager {
-    private static final long SHORTCUT_KEY_DELAY_MILLIS = 150;
     private static final long TEST_SINGLE_KEY_DELAY_MILLIS
             = SingleKeyGestureDetector.MULTI_PRESS_TIMEOUT + 1000L * HW_TIMEOUT_MULTIPLIER;
 
@@ -188,7 +187,7 @@ class TestPhoneWindowManager {
         MockitoAnnotations.initMocks(this);
         mHandler = new Handler(mTestLooper.getLooper());
         mContext = mockingDetails(context).isSpy() ? context : spy(context);
-        mHandler.post(() -> setUp(supportSettingsUpdate));
+        setUp(supportSettingsUpdate);
         mTestLooper.dispatchAll();
     }
 
@@ -306,6 +305,10 @@ class TestPhoneWindowManager {
         mMockitoSession.finishMocking();
     }
 
+    void dispatchAllPendingEvents() {
+        mTestLooper.dispatchAll();
+    }
+
     // Override accessibility setting and perform function.
     private void overrideLaunchAccessibility() {
         doReturn(true).when(mAccessibilityShortcutController)
@@ -446,6 +449,7 @@ class TestPhoneWindowManager {
         doNothing().when(mPhoneWindowManager).sendCloseSystemWindows();
         doReturn(true).when(mPhoneWindowManager).isUserSetupComplete();
         doReturn(mContext).when(mContext).createContextAsUser(any(), anyInt());
+        doReturn(mSearchManager).when(mContext).getSystemService(eq(SearchManager.class));
     }
 
     void overrideSearchManager(SearchManager searchManager) {
@@ -500,29 +504,24 @@ class TestPhoneWindowManager {
      */
     void assertTakeScreenshotCalled() {
         mTestLooper.dispatchAll();
-        verify(mDisplayPolicy, timeout(SHORTCUT_KEY_DELAY_MILLIS))
-                .takeScreenshot(anyInt(), anyInt());
+        verify(mDisplayPolicy).takeScreenshot(anyInt(), anyInt());
     }
 
     void assertShowGlobalActionsCalled() {
         mTestLooper.dispatchAll();
         verify(mPhoneWindowManager).showGlobalActions();
-        verify(mGlobalActions, timeout(SHORTCUT_KEY_DELAY_MILLIS))
-                .showDialog(anyBoolean(), anyBoolean());
-        verify(mPowerManager, timeout(SHORTCUT_KEY_DELAY_MILLIS))
-                .userActivity(anyLong(), anyBoolean());
+        verify(mGlobalActions).showDialog(anyBoolean(), anyBoolean());
+        verify(mPowerManager).userActivity(anyLong(), anyBoolean());
     }
 
     void assertVolumeMute() {
         mTestLooper.dispatchAll();
-        verify(mAudioManagerInternal, timeout(SHORTCUT_KEY_DELAY_MILLIS))
-                .silenceRingerModeInternal(eq("volume_hush"));
+        verify(mAudioManagerInternal).silenceRingerModeInternal(eq("volume_hush"));
     }
 
     void assertAccessibilityKeychordCalled() {
         mTestLooper.dispatchAll();
-        verify(mAccessibilityShortcutController,
-                timeout(SHORTCUT_KEY_DELAY_MILLIS)).performAccessibilityShortcut();
+        verify(mAccessibilityShortcutController).performAccessibilityShortcut();
     }
 
     void assertDreamRequest() {
@@ -532,14 +531,12 @@ class TestPhoneWindowManager {
 
     void assertPowerSleep() {
         mTestLooper.dispatchAll();
-        verify(mPowerManager,
-                timeout(SHORTCUT_KEY_DELAY_MILLIS)).goToSleep(anyLong(), anyInt(), anyInt());
+        verify(mPowerManager).goToSleep(anyLong(), anyInt(), anyInt());
     }
 
     void assertPowerWakeUp() {
         mTestLooper.dispatchAll();
-        verify(mPowerManager,
-                timeout(SHORTCUT_KEY_DELAY_MILLIS)).wakeUp(anyLong(), anyInt(), anyString());
+        verify(mPowerManager).wakeUp(anyLong(), anyInt(), anyString());
     }
 
     void assertNoPowerSleep() {
@@ -556,7 +553,7 @@ class TestPhoneWindowManager {
 
     void assertSearchManagerLaunchAssist() {
         mTestLooper.dispatchAll();
-        verify(mSearchManager, timeout(SHORTCUT_KEY_DELAY_MILLIS)).launchAssist(any());
+        verify(mSearchManager).launchAssist(any());
     }
 
     void assertLaunchCategory(String category) {
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 40ac7b1ccdca2b143b7fa0927d7df24b134d6b9f..bdbfb7ad80df3c105eaee6fc21cb50fd3200ad2b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -2627,6 +2627,13 @@ public class ActivityRecordTests extends WindowTestsBase {
         // Can specify orientation if the current orientation candidate is orientation behind.
         assertEquals(SCREEN_ORIENTATION_LANDSCAPE,
                 activity.getOrientation(SCREEN_ORIENTATION_BEHIND));
+
+        final ActivityRecord translucentActivity = new ActivityBuilder(mAtm)
+                .setActivityTheme(android.R.style.Theme_Translucent)
+                .setCreateTask(true).build();
+        assertFalse(translucentActivity.providesOrientation());
+        translucentActivity.setOccludesParent(true);
+        assertTrue(translucentActivity.providesOrientation());
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
index 6a738befba9a1cf1da9bca6fd73aa491cfdaba9f..9f584911aed70ca2bb06851d2bdf4f019b498a3b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
@@ -41,7 +41,6 @@ import android.view.SurfaceSession;
 
 import com.android.server.testutils.StubTransaction;
 import com.android.server.wm.utils.MockAnimationAdapter;
-import com.android.window.flags.Flags;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -150,7 +149,7 @@ public class DimmerTests extends WindowTestsBase {
         mHost = new MockSurfaceBuildingContainer(mWm);
         mTransaction = spy(StubTransaction.class);
         mChild = new TestWindowContainer(mWm);
-        if (Flags.dimmerRefactor()) {
+        if (Dimmer.DIMMER_REFACTOR) {
             sTestAnimation = spy(new MockAnimationAdapter());
             mDimmer = new SmoothDimmer(mHost, new MockAnimationAdapterFactory());
         } else {
@@ -177,7 +176,7 @@ public class DimmerTests extends WindowTestsBase {
 
     @Test
     public void testDimBelowWithChildSurfaceCreatesSurfaceBelowChild_Smooth() {
-        assumeTrue(Flags.dimmerRefactor());
+        assumeTrue(Dimmer.DIMMER_REFACTOR);
         final float alpha = 0.7f;
         final int blur = 50;
         mHost.addChild(mChild, 0);
@@ -197,7 +196,7 @@ public class DimmerTests extends WindowTestsBase {
 
     @Test
     public void testDimBelowWithChildSurfaceCreatesSurfaceBelowChild_Legacy() {
-        assumeFalse(Flags.dimmerRefactor());
+        assumeFalse(Dimmer.DIMMER_REFACTOR);
         final float alpha = 0.7f;
         mHost.addChild(mChild, 0);
         mDimmer.adjustAppearance(mChild, alpha, 20);
@@ -212,7 +211,7 @@ public class DimmerTests extends WindowTestsBase {
 
     @Test
     public void testDimBelowWithChildSurfaceDestroyedWhenReset_Smooth() {
-        assumeTrue(Flags.dimmerRefactor());
+        assumeTrue(Dimmer.DIMMER_REFACTOR);
         mHost.addChild(mChild, 0);
 
         final float alpha = 0.8f;
@@ -232,7 +231,7 @@ public class DimmerTests extends WindowTestsBase {
 
     @Test
     public void testDimBelowWithChildSurfaceDestroyedWhenReset_Legacy() {
-        assumeFalse(Flags.dimmerRefactor());
+        assumeFalse(Dimmer.DIMMER_REFACTOR);
         mHost.addChild(mChild, 0);
 
         final float alpha = 0.8f;
@@ -292,7 +291,7 @@ public class DimmerTests extends WindowTestsBase {
 
     @Test
     public void testRemoveDimImmediately_Smooth() {
-        assumeTrue(Flags.dimmerRefactor());
+        assumeTrue(Dimmer.DIMMER_REFACTOR);
         mHost.addChild(mChild, 0);
         mDimmer.adjustAppearance(mChild, 1, 2);
         mDimmer.adjustRelativeLayer(mChild, -1);
@@ -312,7 +311,7 @@ public class DimmerTests extends WindowTestsBase {
 
     @Test
     public void testRemoveDimImmediately_Legacy() {
-        assumeFalse(Flags.dimmerRefactor());
+        assumeFalse(Dimmer.DIMMER_REFACTOR);
         mHost.addChild(mChild, 0);
         mDimmer.adjustAppearance(mChild, 1, 0);
         mDimmer.adjustRelativeLayer(mChild, -1);
@@ -332,7 +331,7 @@ public class DimmerTests extends WindowTestsBase {
 
     @Test
     public void testDimmerWithBlurUpdatesTransaction_Legacy() {
-        assumeFalse(Flags.dimmerRefactor());
+        assumeFalse(Dimmer.DIMMER_REFACTOR);
         mHost.addChild(mChild, 0);
 
         final int blurRadius = 50;
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 5f92fd5f12e73687b20cbadc37b9d1e8ddf63a40..0d4c443ce1b088534e5c5138c5f7cb885cbacbe6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
@@ -676,60 +676,59 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
     @EnableCompatChanges({OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT})
     public void testOverrideOrientationIfNeeded_portraitOverrideEnabled_returnsPortrait()
             throws Exception {
-        assertEquals(mController.overrideOrientationIfNeeded(
-                /* candidate */ SCREEN_ORIENTATION_UNSPECIFIED), SCREEN_ORIENTATION_PORTRAIT);
+        assertEquals(SCREEN_ORIENTATION_PORTRAIT, mController.overrideOrientationIfNeeded(
+                /* candidate */ SCREEN_ORIENTATION_UNSPECIFIED));
     }
 
     @Test
     @EnableCompatChanges({OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR})
     public void testOverrideOrientationIfNeeded_portraitOverrideEnabled_returnsNosensor() {
-        assertEquals(mController.overrideOrientationIfNeeded(
-                /* candidate */ SCREEN_ORIENTATION_UNSPECIFIED), SCREEN_ORIENTATION_NOSENSOR);
+        assertEquals(SCREEN_ORIENTATION_NOSENSOR, mController.overrideOrientationIfNeeded(
+                /* candidate */ SCREEN_ORIENTATION_UNSPECIFIED));
     }
 
     @Test
     @EnableCompatChanges({OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR})
     public void testOverrideOrientationIfNeeded_nosensorOverride_orientationFixed_returnsUnchanged() {
-        assertEquals(mController.overrideOrientationIfNeeded(
-                /* candidate */ SCREEN_ORIENTATION_PORTRAIT), SCREEN_ORIENTATION_PORTRAIT);
+        assertEquals(SCREEN_ORIENTATION_PORTRAIT, mController.overrideOrientationIfNeeded(
+                /* candidate */ SCREEN_ORIENTATION_PORTRAIT));
     }
 
     @Test
     @EnableCompatChanges({OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE})
     public void testOverrideOrientationIfNeeded_reverseLandscapeOverride_orientationPortraitOrUndefined_returnsUnchanged() {
-        assertEquals(mController.overrideOrientationIfNeeded(
-                /* candidate */ SCREEN_ORIENTATION_PORTRAIT), SCREEN_ORIENTATION_PORTRAIT);
-        assertEquals(mController.overrideOrientationIfNeeded(
-                /* candidate */ SCREEN_ORIENTATION_UNSPECIFIED), SCREEN_ORIENTATION_UNSPECIFIED);
+        assertEquals(SCREEN_ORIENTATION_PORTRAIT, mController.overrideOrientationIfNeeded(
+                /* candidate */ SCREEN_ORIENTATION_PORTRAIT));
+        assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, mController.overrideOrientationIfNeeded(
+                /* candidate */ SCREEN_ORIENTATION_UNSPECIFIED));
     }
 
     @Test
     @EnableCompatChanges({OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE})
     public void testOverrideOrientationIfNeeded_reverseLandscapeOverride_orientationLandscape_returnsReverseLandscape() {
-        assertEquals(mController.overrideOrientationIfNeeded(
-                /* candidate */ SCREEN_ORIENTATION_LANDSCAPE),
-                SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
+        assertEquals(SCREEN_ORIENTATION_REVERSE_LANDSCAPE, mController.overrideOrientationIfNeeded(
+                /* candidate */ SCREEN_ORIENTATION_LANDSCAPE));
     }
 
     @Test
     @EnableCompatChanges({OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT})
     public void testOverrideOrientationIfNeeded_portraitOverride_orientationFixed_returnsUnchanged() {
-        assertEquals(mController.overrideOrientationIfNeeded(
-                /* candidate */ SCREEN_ORIENTATION_NOSENSOR), SCREEN_ORIENTATION_NOSENSOR);
+        assertEquals(SCREEN_ORIENTATION_NOSENSOR, mController.overrideOrientationIfNeeded(
+                /* candidate */ SCREEN_ORIENTATION_NOSENSOR));
     }
 
     @Test
     @EnableCompatChanges({OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT, OVERRIDE_ANY_ORIENTATION})
     public void testOverrideOrientationIfNeeded_portraitAndIgnoreFixedOverrides_returnsPortrait() {
-        assertEquals(mController.overrideOrientationIfNeeded(
-                /* candidate */ SCREEN_ORIENTATION_NOSENSOR), SCREEN_ORIENTATION_PORTRAIT);
+        assertEquals(SCREEN_ORIENTATION_PORTRAIT, mController.overrideOrientationIfNeeded(
+                /* candidate */ SCREEN_ORIENTATION_NOSENSOR));
     }
 
     @Test
     @EnableCompatChanges({OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR, OVERRIDE_ANY_ORIENTATION})
     public void testOverrideOrientationIfNeeded_noSensorAndIgnoreFixedOverrides_returnsNosensor() {
-        assertEquals(mController.overrideOrientationIfNeeded(
-                /* candidate */ SCREEN_ORIENTATION_PORTRAIT), SCREEN_ORIENTATION_NOSENSOR);
+        assertEquals(SCREEN_ORIENTATION_NOSENSOR, mController.overrideOrientationIfNeeded(
+                /* candidate */ SCREEN_ORIENTATION_PORTRAIT));
     }
 
     @Test
@@ -740,8 +739,8 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
 
         mController = new LetterboxUiController(mWm, mActivity);
 
-        assertEquals(mController.overrideOrientationIfNeeded(
-                /* candidate */ SCREEN_ORIENTATION_UNSPECIFIED), SCREEN_ORIENTATION_UNSPECIFIED);
+        assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, mController.overrideOrientationIfNeeded(
+                /* candidate */ SCREEN_ORIENTATION_UNSPECIFIED));
     }
 
     @Test
@@ -760,8 +759,8 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
         doReturn(false).when(mDisplayContent.mDisplayRotationCompatPolicy)
                 .isActivityEligibleForOrientationOverride(eq(mActivity));
 
-        assertEquals(mController.overrideOrientationIfNeeded(
-                /* candidate */ SCREEN_ORIENTATION_UNSPECIFIED), SCREEN_ORIENTATION_UNSPECIFIED);
+        assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, mController.overrideOrientationIfNeeded(
+                /* candidate */ SCREEN_ORIENTATION_UNSPECIFIED));
     }
 
     @Test
@@ -780,8 +779,8 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
         doReturn(true).when(mDisplayContent.mDisplayRotationCompatPolicy)
                 .isActivityEligibleForOrientationOverride(eq(mActivity));
 
-        assertEquals(mController.overrideOrientationIfNeeded(
-                /* candidate */ SCREEN_ORIENTATION_UNSPECIFIED), SCREEN_ORIENTATION_PORTRAIT);
+        assertEquals(SCREEN_ORIENTATION_PORTRAIT, mController.overrideOrientationIfNeeded(
+                /* candidate */ SCREEN_ORIENTATION_UNSPECIFIED));
     }
 
     @Test
@@ -789,8 +788,8 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
         spyOn(mController);
         doReturn(true).when(mController).shouldApplyUserFullscreenOverride();
 
-        assertEquals(mController.overrideOrientationIfNeeded(
-                /* candidate */ SCREEN_ORIENTATION_UNSPECIFIED), SCREEN_ORIENTATION_USER);
+        assertEquals(SCREEN_ORIENTATION_USER, mController.overrideOrientationIfNeeded(
+                /* candidate */ SCREEN_ORIENTATION_UNSPECIFIED));
     }
 
     @Test
@@ -799,8 +798,8 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
         spyOn(mController);
         doReturn(true).when(mController).shouldApplyUserFullscreenOverride();
 
-        assertEquals(mController.overrideOrientationIfNeeded(
-                /* candidate */ SCREEN_ORIENTATION_PORTRAIT), SCREEN_ORIENTATION_USER);
+        assertEquals(SCREEN_ORIENTATION_USER, mController.overrideOrientationIfNeeded(
+                /* candidate */ SCREEN_ORIENTATION_PORTRAIT));
     }
 
     @Test
@@ -808,8 +807,8 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
         spyOn(mController);
         doReturn(false).when(mController).shouldApplyUserFullscreenOverride();
 
-        assertEquals(mController.overrideOrientationIfNeeded(
-                /* candidate */ SCREEN_ORIENTATION_PORTRAIT), SCREEN_ORIENTATION_PORTRAIT);
+        assertEquals(SCREEN_ORIENTATION_PORTRAIT, mController.overrideOrientationIfNeeded(
+                /* candidate */ SCREEN_ORIENTATION_PORTRAIT));
     }
 
     @Test
@@ -817,15 +816,15 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
         spyOn(mController);
         doReturn(true).when(mController).shouldApplyUserMinAspectRatioOverride();
 
-        assertEquals(mController.overrideOrientationIfNeeded(
-                /* candidate */ SCREEN_ORIENTATION_UNSPECIFIED), SCREEN_ORIENTATION_PORTRAIT);
+        assertEquals(SCREEN_ORIENTATION_PORTRAIT, mController.overrideOrientationIfNeeded(
+                /* candidate */ SCREEN_ORIENTATION_UNSPECIFIED));
 
-        assertEquals(mController.overrideOrientationIfNeeded(
-                /* candidate */ SCREEN_ORIENTATION_LOCKED), SCREEN_ORIENTATION_PORTRAIT);
+        assertEquals(SCREEN_ORIENTATION_PORTRAIT, mController.overrideOrientationIfNeeded(
+                /* candidate */ SCREEN_ORIENTATION_LOCKED));
 
         // unchanged if orientation is specified
-        assertEquals(mController.overrideOrientationIfNeeded(
-                /* candidate */ SCREEN_ORIENTATION_LANDSCAPE), SCREEN_ORIENTATION_LANDSCAPE);
+        assertEquals(SCREEN_ORIENTATION_LANDSCAPE, mController.overrideOrientationIfNeeded(
+                /* candidate */ SCREEN_ORIENTATION_LANDSCAPE));
     }
 
     @Test
@@ -833,8 +832,8 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
         spyOn(mController);
         doReturn(false).when(mController).shouldApplyUserMinAspectRatioOverride();
 
-        assertEquals(mController.overrideOrientationIfNeeded(
-                /* candidate */ SCREEN_ORIENTATION_UNSPECIFIED), SCREEN_ORIENTATION_UNSPECIFIED);
+        assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, mController.overrideOrientationIfNeeded(
+                /* candidate */ SCREEN_ORIENTATION_UNSPECIFIED));
     }
 
     // shouldApplyUser...Override
@@ -1286,16 +1285,16 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
         mActivity = setUpActivityWithComponent();
         mController = new LetterboxUiController(mWm, mActivity);
 
-        assertEquals(mController.getFixedOrientationLetterboxAspectRatio(
-                mActivity.getParent().getConfiguration()), 1.5f, /* delta */ 0.01);
+        assertEquals(1.5f, mController.getFixedOrientationLetterboxAspectRatio(
+                mActivity.getParent().getConfiguration()), /* delta */ 0.01);
 
         spyOn(mDisplayContent.mDisplayRotationCompatPolicy);
         doReturn(true).when(mDisplayContent.mDisplayRotationCompatPolicy)
                 .isTreatmentEnabledForActivity(eq(mActivity));
 
-        assertEquals(mController.getFixedOrientationLetterboxAspectRatio(
-                mActivity.getParent().getConfiguration()), mController.getSplitScreenAspectRatio(),
-                /* delta */  0.01);
+        assertEquals(mController.getSplitScreenAspectRatio(),
+                mController.getFixedOrientationLetterboxAspectRatio(
+                        mActivity.getParent().getConfiguration()), /* delta */  0.01);
     }
 
     private void mockThatProperty(String propertyName, boolean value) throws Exception {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 9146889e37d9d042b980f39f9342303efec75077..e0ed642d3130bccfec4441d5c229bd10afa76f72 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -1184,6 +1184,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
         private boolean mCreateTask = false;
         private Task mParentTask;
         private int mActivityFlags;
+        private int mActivityTheme;
         private int mLaunchMode;
         private int mResizeMode = RESIZE_MODE_RESIZEABLE;
         private float mMaxAspectRatio;
@@ -1232,6 +1233,14 @@ class WindowTestsBase extends SystemServiceTestsBase {
             return this;
         }
 
+        ActivityBuilder setActivityTheme(int theme) {
+            mActivityTheme = theme;
+            // Use the real package of test so it can get a valid context for theme.
+            mComponent = ComponentName.createRelative(mService.mContext.getPackageName(),
+                    DEFAULT_COMPONENT_CLASS_NAME + sCurrentActivityId++);
+            return this;
+        }
+
         ActivityBuilder setActivityFlags(int flags) {
             mActivityFlags = flags;
             return this;
@@ -1381,6 +1390,9 @@ class WindowTestsBase extends SystemServiceTestsBase {
             if (mTargetActivity != null) {
                 aInfo.targetActivity = mTargetActivity;
             }
+            if (mActivityTheme != 0) {
+                aInfo.theme = mActivityTheme;
+            }
             aInfo.flags |= mActivityFlags;
             aInfo.launchMode = mLaunchMode;
             aInfo.resizeMode = mResizeMode;
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 038b93fc2a43a97a2a1445ae4248288db5a4c735..0b70b40e25567f05d31f37e2dbbe13e18902e661 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -3147,6 +3147,14 @@ public class CarrierConfigManager {
      */
     public static final String KEY_ROAMING_OPERATOR_STRING_ARRAY = "roaming_operator_string_array";
 
+    /**
+     * Config to show the roaming indicator (i.e. the "R" icon) from the status bar when roaming.
+     * The roaming indicator will be shown if this is {@code true} and will not be shown if this is
+     * {@code false}.
+     */
+    @FlaggedApi(Flags.FLAG_HIDE_ROAMING_ICON)
+    public static final String KEY_SHOW_ROAMING_INDICATOR_BOOL = "show_roaming_indicator_bool";
+
     /**
      * URL from which the proto containing the public key of the Carrier used for
      * IMSI encryption will be downloaded.
@@ -3313,11 +3321,11 @@ public class CarrierConfigManager {
      * If {@code false} the SPN display checks if the current MCC/MNC is different from the
      * SIM card's MCC/MNC.
      *
-     * @see KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY
-     * @see KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY
-     * @see KEY_NON_ROAMING_OPERATOR_STRING_ARRAY
-     * @see KEY_ROAMING_OPERATOR_STRING_ARRAY
-     * @see KEY_FORCE_HOME_NETWORK_BOOL
+     * @see #KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY
+     * @see #KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY
+     * @see #KEY_NON_ROAMING_OPERATOR_STRING_ARRAY
+     * @see #KEY_ROAMING_OPERATOR_STRING_ARRAY
+     * @see #KEY_FORCE_HOME_NETWORK_BOOL
      *
      * @hide
      */
@@ -10193,6 +10201,7 @@ public class CarrierConfigManager {
                 false);
         sDefaults.putStringArray(KEY_NON_ROAMING_OPERATOR_STRING_ARRAY, null);
         sDefaults.putStringArray(KEY_ROAMING_OPERATOR_STRING_ARRAY, null);
+        sDefaults.putBoolean(KEY_SHOW_ROAMING_INDICATOR_BOOL, true);
         sDefaults.putBoolean(KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL, false);
         sDefaults.putBoolean(KEY_RTT_SUPPORTED_BOOL, false);
         sDefaults.putBoolean(KEY_TTY_SUPPORTED_BOOL, true);
diff --git a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
index 158e0656b574bc87b257f7cfce596c46f7dce515..dc55dd240be0eb4ecf87c6a78998808d231060e2 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
@@ -236,6 +236,12 @@ public final class SampleDataClass implements Parcelable {
      * Transient fields are completely ignored and can be used for caching.
      */
     private transient LinkAddress[] mLinkAddresses6;
+    /**
+     * For hidden lists, getters, setters and adders will be hidden.
+     * @hide
+     */
+    private @NonNull List<LinkAddress> mLinkAddresses7 = new ArrayList<>();
+
     /**
      * When using transient fields for caching it's often also a good idea to initialize them
      * lazily.
@@ -486,6 +492,8 @@ public final class SampleDataClass implements Parcelable {
      *   Making a field public will suppress getter generation in favor of accessing it directly.
      * @param linkAddresses5
      *   Final fields suppress generating a setter (when setters are requested).
+     * @param linkAddresses7
+     *   For hidden lists, getters, setters and adders will be hidden.
      * @param stringRes
      *   Fields with certain annotations are automatically validated in constructor
      *
@@ -529,9 +537,10 @@ public final class SampleDataClass implements Parcelable {
             @State int state,
             @NonNull CharSequence charSeq,
             @Nullable LinkAddress[] linkAddresses5,
+            @NonNull List<LinkAddress> linkAddresses7,
             @StringRes int stringRes,
             @android.annotation.IntRange(from = 0, to = 6) int dayOfWeek,
-            @Size(2) @NonNull @FloatRange(from = 0f) float[] coords,
+            @Size(2) @NonNull @Each @FloatRange(from = 0f) float[] coords,
             @NonNull IBinder token,
             @Nullable ICompanionDeviceManager iPCInterface) {
         this.mNum = num;
@@ -595,6 +604,9 @@ public final class SampleDataClass implements Parcelable {
         AnnotationValidations.validate(
                 NonNull.class, null, charSeq);
         this.mLinkAddresses5 = linkAddresses5;
+        this.mLinkAddresses7 = linkAddresses7;
+        AnnotationValidations.validate(
+                NonNull.class, null, mLinkAddresses7);
         this.mStringRes = stringRes;
         AnnotationValidations.validate(
                 StringRes.class, null, mStringRes);
@@ -609,13 +621,11 @@ public final class SampleDataClass implements Parcelable {
                 "value", 2);
         AnnotationValidations.validate(
                 NonNull.class, null, mCoords);
-        int coordsSize = mCoords.length;
-        for (int i = 0; i < coordsSize; i++) {
-            AnnotationValidations.validate(
-                    FloatRange.class, null, mCoords[i],
-                    "from", 0f);
-        }
-
+        AnnotationValidations.validate(
+                Each.class, null, mCoords);
+        AnnotationValidations.validate(
+                FloatRange.class, null, mCoords,
+                "from", 0f);
         this.mToken = token;
         AnnotationValidations.validate(
                 NonNull.class, null, mToken);
@@ -776,6 +786,16 @@ public final class SampleDataClass implements Parcelable {
         return mLinkAddresses5;
     }
 
+    /**
+     * For hidden lists, getters, setters and adders will be hidden.
+     *
+     * @hide
+     */
+    @DataClass.Generated.Member
+    public @NonNull List<LinkAddress> getLinkAddresses7() {
+        return mLinkAddresses7;
+    }
+
     /**
      * Fields with certain annotations are automatically validated in constructor
      *
@@ -815,7 +835,7 @@ public final class SampleDataClass implements Parcelable {
      * @see AnnotationValidations#validate(Class, Size, int, String, int)
      */
     @DataClass.Generated.Member
-    public @Size(2) @NonNull @FloatRange(from = 0f) float[] getCoords() {
+    public @Size(2) @NonNull @Each @FloatRange(from = 0f) float[] getCoords() {
         return mCoords;
     }
 
@@ -1064,6 +1084,19 @@ public final class SampleDataClass implements Parcelable {
         return this;
     }
 
+    /**
+     * For hidden lists, getters, setters and adders will be hidden.
+     *
+     * @hide
+     */
+    @DataClass.Generated.Member
+    public @NonNull SampleDataClass setLinkAddresses7(@NonNull List<LinkAddress> value) {
+        mLinkAddresses7 = value;
+        AnnotationValidations.validate(
+                NonNull.class, null, mLinkAddresses7);
+        return this;
+    }
+
     /**
      * Fields with certain annotations are automatically validated in constructor
      *
@@ -1111,20 +1144,18 @@ public final class SampleDataClass implements Parcelable {
      * @see AnnotationValidations#validate(Class, Size, int, String, int)
      */
     @DataClass.Generated.Member
-    public @NonNull SampleDataClass setCoords(@Size(2) @NonNull @FloatRange(from = 0f) float... value) {
+    public @NonNull SampleDataClass setCoords(@Size(2) @NonNull @Each @FloatRange(from = 0f) float... value) {
         mCoords = value;
         AnnotationValidations.validate(
                 Size.class, null, mCoords.length,
                 "value", 2);
         AnnotationValidations.validate(
                 NonNull.class, null, mCoords);
-        int coordsSize = mCoords.length;
-        for (int i = 0; i < coordsSize; i++) {
-            AnnotationValidations.validate(
-                    FloatRange.class, null, mCoords[i],
-                    "from", 0f);
-        }
-
+        AnnotationValidations.validate(
+                Each.class, null, mCoords);
+        AnnotationValidations.validate(
+                FloatRange.class, null, mCoords,
+                "from", 0f);
         return this;
     }
 
@@ -1172,6 +1203,7 @@ public final class SampleDataClass implements Parcelable {
                 "state = " + stateToString(mState) + ", " +
                 "charSeq = " + charSeq + ", " +
                 "linkAddresses5 = " + java.util.Arrays.toString(mLinkAddresses5) + ", " +
+                "linkAddresses7 = " + mLinkAddresses7 + ", " +
                 "stringRes = " + mStringRes + ", " +
                 "dayOfWeek = " + mDayOfWeek + ", " +
                 "coords = " + java.util.Arrays.toString(mCoords) + ", " +
@@ -1210,6 +1242,7 @@ public final class SampleDataClass implements Parcelable {
                 && mState == that.mState
                 && Objects.equals(charSeq, that.charSeq)
                 && java.util.Arrays.equals(mLinkAddresses5, that.mLinkAddresses5)
+                && Objects.equals(mLinkAddresses7, that.mLinkAddresses7)
                 && mStringRes == that.mStringRes
                 && mDayOfWeek == that.mDayOfWeek
                 && java.util.Arrays.equals(mCoords, that.mCoords)
@@ -1241,6 +1274,7 @@ public final class SampleDataClass implements Parcelable {
         _hash = 31 * _hash + mState;
         _hash = 31 * _hash + Objects.hashCode(charSeq);
         _hash = 31 * _hash + java.util.Arrays.hashCode(mLinkAddresses5);
+        _hash = 31 * _hash + Objects.hashCode(mLinkAddresses7);
         _hash = 31 * _hash + mStringRes;
         _hash = 31 * _hash + mDayOfWeek;
         _hash = 31 * _hash + java.util.Arrays.hashCode(mCoords);
@@ -1270,6 +1304,7 @@ public final class SampleDataClass implements Parcelable {
         actionInt.acceptInt(this, "state", mState);
         actionObject.acceptObject(this, "charSeq", charSeq);
         actionObject.acceptObject(this, "linkAddresses5", mLinkAddresses5);
+        actionObject.acceptObject(this, "linkAddresses7", mLinkAddresses7);
         actionInt.acceptInt(this, "stringRes", mStringRes);
         actionInt.acceptInt(this, "dayOfWeek", mDayOfWeek);
         actionObject.acceptObject(this, "coords", mCoords);
@@ -1298,6 +1333,7 @@ public final class SampleDataClass implements Parcelable {
         action.acceptObject(this, "state", mState);
         action.acceptObject(this, "charSeq", charSeq);
         action.acceptObject(this, "linkAddresses5", mLinkAddresses5);
+        action.acceptObject(this, "linkAddresses7", mLinkAddresses7);
         action.acceptObject(this, "stringRes", mStringRes);
         action.acceptObject(this, "dayOfWeek", mDayOfWeek);
         action.acceptObject(this, "coords", mCoords);
@@ -1338,7 +1374,7 @@ public final class SampleDataClass implements Parcelable {
         if (mOtherParcelable != null) flg |= 0x40;
         if (mLinkAddresses4 != null) flg |= 0x800;
         if (mLinkAddresses5 != null) flg |= 0x10000;
-        if (mIPCInterface != null) flg |= 0x200000;
+        if (mIPCInterface != null) flg |= 0x400000;
         dest.writeLong(flg);
         dest.writeInt(mNum);
         dest.writeInt(mNum2);
@@ -1357,6 +1393,7 @@ public final class SampleDataClass implements Parcelable {
         dest.writeInt(mState);
         dest.writeCharSequence(charSeq);
         if (mLinkAddresses5 != null) dest.writeTypedArray(mLinkAddresses5, flags);
+        dest.writeParcelableList(mLinkAddresses7, flags);
         dest.writeInt(mStringRes);
         dest.writeInt(mDayOfWeek);
         dest.writeFloatArray(mCoords);
@@ -1395,11 +1432,13 @@ public final class SampleDataClass implements Parcelable {
         int state = in.readInt();
         CharSequence _charSeq = (CharSequence) in.readCharSequence();
         LinkAddress[] linkAddresses5 = (flg & 0x10000) == 0 ? null : (LinkAddress[]) in.createTypedArray(LinkAddress.CREATOR);
+        List<LinkAddress> linkAddresses7 = new ArrayList<>();
+        in.readParcelableList(linkAddresses7, LinkAddress.class.getClassLoader());
         int stringRes = in.readInt();
         int dayOfWeek = in.readInt();
         float[] coords = in.createFloatArray();
         IBinder token = (IBinder) in.readStrongBinder();
-        ICompanionDeviceManager iPCInterface = (flg & 0x200000) == 0 ? null : ICompanionDeviceManager.Stub.asInterface(in.readStrongBinder());
+        ICompanionDeviceManager iPCInterface = (flg & 0x400000) == 0 ? null : ICompanionDeviceManager.Stub.asInterface(in.readStrongBinder());
 
         this.mNum = num;
         this.mNum2 = num2;
@@ -1462,6 +1501,9 @@ public final class SampleDataClass implements Parcelable {
         AnnotationValidations.validate(
                 NonNull.class, null, charSeq);
         this.mLinkAddresses5 = linkAddresses5;
+        this.mLinkAddresses7 = linkAddresses7;
+        AnnotationValidations.validate(
+                NonNull.class, null, mLinkAddresses7);
         this.mStringRes = stringRes;
         AnnotationValidations.validate(
                 StringRes.class, null, mStringRes);
@@ -1476,13 +1518,11 @@ public final class SampleDataClass implements Parcelable {
                 "value", 2);
         AnnotationValidations.validate(
                 NonNull.class, null, mCoords);
-        int coordsSize = mCoords.length;
-        for (int i = 0; i < coordsSize; i++) {
-            AnnotationValidations.validate(
-                    FloatRange.class, null, mCoords[i],
-                    "from", 0f);
-        }
-
+        AnnotationValidations.validate(
+                Each.class, null, mCoords);
+        AnnotationValidations.validate(
+                FloatRange.class, null, mCoords,
+                "from", 0f);
         this.mToken = token;
         AnnotationValidations.validate(
                 NonNull.class, null, mToken);
@@ -1529,9 +1569,10 @@ public final class SampleDataClass implements Parcelable {
         private @State int mState;
         private @NonNull CharSequence charSeq;
         private @Nullable LinkAddress[] mLinkAddresses5;
+        private @NonNull List<LinkAddress> mLinkAddresses7;
         private @StringRes int mStringRes;
         private @android.annotation.IntRange(from = 0, to = 6) int mDayOfWeek;
-        private @Size(2) @NonNull @FloatRange(from = 0f) float[] mCoords;
+        private @Size(2) @NonNull @Each @FloatRange(from = 0f) float[] mCoords;
         private @NonNull IBinder mToken;
         private @Nullable ICompanionDeviceManager mIPCInterface;
 
@@ -1822,6 +1863,30 @@ public final class SampleDataClass implements Parcelable {
             return this;
         }
 
+        /**
+         * For hidden lists, getters, setters and adders will be hidden.
+         *
+         * @hide
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setLinkAddresses7(@NonNull List<LinkAddress> value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x20000;
+            mLinkAddresses7 = value;
+            return this;
+        }
+
+        /** @see #setLinkAddresses7 @hide */
+        @DataClass.Generated.Member
+        public @NonNull Builder addLinkAddresses7(@NonNull LinkAddress value) {
+            // You can refine this method's name by providing item's singular name, e.g.:
+            // @DataClass.PluralOf("item")) mItems = ...
+
+            if (mLinkAddresses7 == null) setLinkAddresses7(new ArrayList<>());
+            mLinkAddresses7.add(value);
+            return this;
+        }
+
         /**
          * Fields with certain annotations are automatically validated in constructor
          *
@@ -1837,7 +1902,7 @@ public final class SampleDataClass implements Parcelable {
         @DataClass.Generated.Member
         public @NonNull Builder setStringRes(@StringRes int value) {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x20000;
+            mBuilderFieldsSet |= 0x40000;
             mStringRes = value;
             return this;
         }
@@ -1852,7 +1917,7 @@ public final class SampleDataClass implements Parcelable {
         @DataClass.Generated.Member
         public @NonNull Builder setDayOfWeek(@android.annotation.IntRange(from = 0, to = 6) int value) {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x40000;
+            mBuilderFieldsSet |= 0x80000;
             mDayOfWeek = value;
             return this;
         }
@@ -1867,9 +1932,9 @@ public final class SampleDataClass implements Parcelable {
          * @see AnnotationValidations#validate(Class, Size, int, String, int)
          */
         @DataClass.Generated.Member
-        public @NonNull Builder setCoords(@Size(2) @NonNull @FloatRange(from = 0f) float... value) {
+        public @NonNull Builder setCoords(@Size(2) @NonNull @Each @FloatRange(from = 0f) float... value) {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x80000;
+            mBuilderFieldsSet |= 0x100000;
             mCoords = value;
             return this;
         }
@@ -1880,7 +1945,7 @@ public final class SampleDataClass implements Parcelable {
         @DataClass.Generated.Member
         public @NonNull Builder setToken(@NonNull IBinder value) {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x100000;
+            mBuilderFieldsSet |= 0x200000;
             mToken = value;
             return this;
         }
@@ -1891,7 +1956,7 @@ public final class SampleDataClass implements Parcelable {
         @DataClass.Generated.Member
         public @NonNull Builder setIPCInterface(@NonNull ICompanionDeviceManager value) {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x200000;
+            mBuilderFieldsSet |= 0x400000;
             mIPCInterface = value;
             return this;
         }
@@ -1899,7 +1964,7 @@ public final class SampleDataClass implements Parcelable {
         /** Builds the instance. This builder should not be touched after calling this! */
         public @NonNull SampleDataClass build() {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x400000; // Mark builder used
+            mBuilderFieldsSet |= 0x800000; // Mark builder used
 
             if ((mBuilderFieldsSet & 0x10) == 0) {
                 mName2 = "Bob";
@@ -1935,18 +2000,21 @@ public final class SampleDataClass implements Parcelable {
                 charSeq = "";
             }
             if ((mBuilderFieldsSet & 0x20000) == 0) {
-                mStringRes = 0;
+                mLinkAddresses7 = new ArrayList<>();
             }
             if ((mBuilderFieldsSet & 0x40000) == 0) {
-                mDayOfWeek = 3;
+                mStringRes = 0;
             }
             if ((mBuilderFieldsSet & 0x80000) == 0) {
-                mCoords = new float[] { 0f, 0f };
+                mDayOfWeek = 3;
             }
             if ((mBuilderFieldsSet & 0x100000) == 0) {
-                mToken = new Binder();
+                mCoords = new float[] { 0f, 0f };
             }
             if ((mBuilderFieldsSet & 0x200000) == 0) {
+                mToken = new Binder();
+            }
+            if ((mBuilderFieldsSet & 0x400000) == 0) {
                 mIPCInterface = null;
             }
             SampleDataClass o = new SampleDataClass(
@@ -1967,6 +2035,7 @@ public final class SampleDataClass implements Parcelable {
                     mState,
                     charSeq,
                     mLinkAddresses5,
+                    mLinkAddresses7,
                     mStringRes,
                     mDayOfWeek,
                     mCoords,
@@ -1976,7 +2045,7 @@ public final class SampleDataClass implements Parcelable {
         }
 
         private void checkNotUsed() {
-            if ((mBuilderFieldsSet & 0x400000) != 0) {
+            if ((mBuilderFieldsSet & 0x800000) != 0) {
                 throw new IllegalStateException(
                         "This Builder should not be reused. Use a new Builder instance instead");
             }
@@ -1984,10 +2053,10 @@ public final class SampleDataClass implements Parcelable {
     }
 
     @DataClass.Generated(
-            time = 1616541539978L,
+            time = 1697693846352L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java",
-            inputSignatures = "public static final  java.lang.String STATE_NAME_UNDEFINED\npublic static final  java.lang.String STATE_NAME_ON\npublic static final  java.lang.String STATE_NAME_OFF\npublic static final  int STATE_ON\npublic static final  int STATE_OFF\npublic static final  int STATE_UNDEFINED\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_AUGMENTED_REQUEST\nprivate  int mNum\nprivate  int mNum2\nprivate  int mNum4\nprivate @android.annotation.Nullable java.lang.String mName\nprivate @android.annotation.NonNull java.lang.String mName2\nprivate @android.annotation.NonNull java.lang.String mName4\nprivate @android.annotation.Nullable android.view.accessibility.AccessibilityNodeInfo mOtherParcelable\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.codegentest.MyDateParcelling.class) @android.annotation.NonNull java.util.Date mDate\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) @android.annotation.NonNull java.util.regex.Pattern mPattern\nprivate @android.annotation.NonNull java.util.List<android.net.LinkAddress> mLinkAddresses2\nprivate @com.android.internal.util.DataClass.PluralOf(\"linkAddress\") @android.annotation.NonNull java.util.ArrayList<android.net.LinkAddress> mLinkAddresses\nprivate @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses4\nprivate @com.android.codegentest.SampleDataClass.StateName @android.annotation.NonNull java.lang.String mStateName\nprivate @com.android.codegentest.SampleDataClass.RequestFlags int mFlags\nprivate @com.android.codegentest.SampleDataClass.State int mState\npublic @android.annotation.NonNull java.lang.CharSequence charSeq\nprivate final @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses5\nprivate transient  android.net.LinkAddress[] mLinkAddresses6\ntransient  int[] mTmpStorage\nprivate @android.annotation.StringRes int mStringRes\nprivate @android.annotation.IntRange int mDayOfWeek\nprivate @android.annotation.Size @android.annotation.NonNull @com.android.internal.util.DataClass.Each @android.annotation.FloatRange float[] mCoords\nprivate @android.annotation.NonNull android.os.IBinder mToken\nprivate @android.annotation.Nullable android.companion.ICompanionDeviceManager mIPCInterface\nprivate static  java.lang.String defaultName4()\nprivate  int[] lazyInitTmpStorage()\npublic  android.net.LinkAddress[] getLinkAddresses4()\nprivate  boolean patternEquals(java.util.regex.Pattern)\nprivate  int patternHashCode()\nprivate  void onConstructed()\npublic  void dump(java.io.PrintWriter)\nclass SampleDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genConstructor=true, genEqualsHashCode=true, genToString=true, genForEachField=true, genSetters=true)")
+            inputSignatures = "public static final  java.lang.String STATE_NAME_UNDEFINED\npublic static final  java.lang.String STATE_NAME_ON\npublic static final  java.lang.String STATE_NAME_OFF\npublic static final  int STATE_ON\npublic static final  int STATE_OFF\npublic static final  int STATE_UNDEFINED\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_AUGMENTED_REQUEST\nprivate  int mNum\nprivate  int mNum2\nprivate  int mNum4\nprivate @android.annotation.Nullable java.lang.String mName\nprivate @android.annotation.NonNull java.lang.String mName2\nprivate @android.annotation.NonNull java.lang.String mName4\nprivate @android.annotation.Nullable android.view.accessibility.AccessibilityNodeInfo mOtherParcelable\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.codegentest.MyDateParcelling.class) @android.annotation.NonNull java.util.Date mDate\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) @android.annotation.NonNull java.util.regex.Pattern mPattern\nprivate @android.annotation.NonNull java.util.List<android.net.LinkAddress> mLinkAddresses2\nprivate @com.android.internal.util.DataClass.PluralOf(\"linkAddress\") @android.annotation.NonNull java.util.ArrayList<android.net.LinkAddress> mLinkAddresses\nprivate @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses4\nprivate @com.android.codegentest.SampleDataClass.StateName @android.annotation.NonNull java.lang.String mStateName\nprivate @com.android.codegentest.SampleDataClass.RequestFlags int mFlags\nprivate @com.android.codegentest.SampleDataClass.State int mState\npublic @android.annotation.NonNull java.lang.CharSequence charSeq\nprivate final @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses5\nprivate transient  android.net.LinkAddress[] mLinkAddresses6\nprivate @android.annotation.NonNull java.util.List<android.net.LinkAddress> mLinkAddresses7\ntransient  int[] mTmpStorage\nprivate @android.annotation.StringRes int mStringRes\nprivate @android.annotation.IntRange int mDayOfWeek\nprivate @android.annotation.Size @android.annotation.NonNull @com.android.internal.util.DataClass.Each @android.annotation.FloatRange float[] mCoords\nprivate @android.annotation.NonNull android.os.IBinder mToken\nprivate @android.annotation.Nullable android.companion.ICompanionDeviceManager mIPCInterface\nprivate static  java.lang.String defaultName4()\nprivate  int[] lazyInitTmpStorage()\npublic  android.net.LinkAddress[] getLinkAddresses4()\nprivate  boolean patternEquals(java.util.regex.Pattern)\nprivate  int patternHashCode()\nprivate  void onConstructed()\npublic  void dump(java.io.PrintWriter)\nclass SampleDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genConstructor=true, genEqualsHashCode=true, genToString=true, genForEachField=true, genSetters=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/tools/codegen/src/com/android/codegen/Generators.kt b/tools/codegen/src/com/android/codegen/Generators.kt
index 685733386cae99054a982c6c527549fcc32d713d..d3a8b033dfff9dec360a52fe4b1cc573be4378ae 100644
--- a/tools/codegen/src/com/android/codegen/Generators.kt
+++ b/tools/codegen/src/com/android/codegen/Generators.kt
@@ -327,7 +327,8 @@ private fun ClassPrinter.generateBuilderSetters(visibility: String) {
             +"return$maybeCast this;"
         }
 
-        val javadocSeeSetter = "/** @see #$setterName */"
+        val javadocSeeSetter =
+                if (isHidden()) "/** @see #$setterName @hide */" else "/** @see #$setterName */"
         val adderName = "add$SingularName"
 
         val singularNameCustomizationHint = if (SingularNameOrNull == null) {
@@ -750,6 +751,15 @@ fun ClassPrinter.generateGetters() {
     }
 }
 
+fun FieldInfo.isHidden(): Boolean {
+    if (javadocFull != null) {
+        (javadocFull ?: "/**\n */").lines().forEach {
+            if (it.contains("@hide")) return true
+        }
+    }
+    return false
+}
+
 fun FieldInfo.generateFieldJavadoc(forceHide: Boolean = false) = classPrinter {
     if (javadocFull != null || forceHide) {
         var hidden = false