Merge changes from topic "mpietal_users" into main

* changes:
  Fix user switching race condition on boot
  Reset keyguard/bouncer on sim NOT_READY
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 02e8cd6..7974f92 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -1313,6 +1313,16 @@
 }
 
 flag {
+   name: "sim_pin_bouncer_reset"
+   namespace: "systemui"
+   description: "The SIM PIN bouncer does not close after unlocking"
+   bug: "297461589"
+   metadata {
+        purpose: PURPOSE_BUGFIX
+   }
+}
+
+flag {
    name: "use_transitions_for_keyguard_occluded"
    namespace: "systemui"
    description: "Use Keyguard Transitions to set Notification Shade occlusion state"
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardConstants.java b/packages/SystemUI/src/com/android/keyguard/KeyguardConstants.java
index a5b62b6..b16c683 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardConstants.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardConstants.java
@@ -28,5 +28,4 @@
      * be used temporarily for debugging.
      */
     public static final boolean DEBUG = Log.isLoggable("Keyguard", Log.DEBUG);
-    public static final boolean DEBUG_SIM_STATES = true;
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
index 1c1acf8..52c93f7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
@@ -53,7 +53,6 @@
         extends KeyguardPinBasedInputViewController<KeyguardSimPinView> {
     public static final String TAG = "KeyguardSimPinView";
     private static final String LOG_TAG = "KeyguardSimPinView";
-    private static final boolean DEBUG = KeyguardConstants.DEBUG_SIM_STATES;
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     private final TelephonyManager mTelephonyManager;
 
@@ -71,7 +70,7 @@
     KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() {
         @Override
         public void onSimStateChanged(int subId, int slotId, int simState) {
-            if (DEBUG) Log.v(TAG, "onSimStateChanged(subId=" + subId + ",state=" + simState + ")");
+            Log.v(TAG, "onSimStateChanged(subId=" + subId + ",state=" + simState + ")");
             // If subId has gone to PUK required then we need to go to the PUK screen.
             if (subId == mSubId && simState == TelephonyManager.SIM_STATE_PUK_REQUIRED) {
                 getKeyguardSecurityCallback().showCurrentSecurityScreen();
@@ -129,7 +128,7 @@
     @Override
     void resetState() {
         super.resetState();
-        if (DEBUG) Log.v(TAG, "Resetting state");
+        Log.v(TAG, "Resetting state");
         handleSubInfoChangeIfNeeded();
         mMessageAreaController.setMessage("");
         if (mShowDefaultMessage) {
@@ -216,11 +215,9 @@
                                 mMessageAreaController.setMessage(mView.getResources().getString(
                                         R.string.kg_password_pin_failed));
                             }
-                            if (DEBUG) {
-                                Log.d(LOG_TAG, "verifyPasswordAndUnlock "
-                                        + " CheckSimPin.onSimCheckResponse: " + result
-                                        + " attemptsRemaining=" + result.getAttemptsRemaining());
-                            }
+                            Log.d(LOG_TAG, "verifyPasswordAndUnlock "
+                                    + " CheckSimPin.onSimCheckResponse: " + result
+                                    + " attemptsRemaining=" + result.getAttemptsRemaining());
                         }
                         getKeyguardSecurityCallback().userActivity();
                         mCheckSimPinThread = null;
@@ -280,10 +277,8 @@
             displayMessage = mView.getResources()
                     .getString(R.string.kg_sim_lock_esim_instructions, displayMessage);
         }
-        if (DEBUG) {
-            Log.d(LOG_TAG, "getPinPasswordErrorMessage: attemptsRemaining="
-                    + attemptsRemaining + " displayMessage=" + displayMessage);
-        }
+        Log.d(LOG_TAG, "getPinPasswordErrorMessage: attemptsRemaining="
+                + attemptsRemaining + " displayMessage=" + displayMessage);
         return displayMessage;
     }
 
@@ -323,14 +318,10 @@
 
         @Override
         public void run() {
-            if (DEBUG) {
-                Log.v(TAG, "call supplyIccLockPin(subid=" + mSubId + ")");
-            }
+            Log.v(TAG, "call supplyIccLockPin(subid=" + mSubId + ")");
             TelephonyManager telephonyManager = mTelephonyManager.createForSubscriptionId(mSubId);
             final PinResult result = telephonyManager.supplyIccLockPin(mPin);
-            if (DEBUG) {
-                Log.v(TAG, "supplyIccLockPin returned: " + result.toString());
-            }
+            Log.v(TAG, "supplyIccLockPin returned: " + result.toString());
             mView.post(() -> onSimCheckResponse(result));
         }
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index f731186..22130f8 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -43,6 +43,7 @@
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
+import static com.android.systemui.Flags.simPinBouncerReset;
 import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_OPENED;
 
 import android.annotation.AnyThread;
@@ -1703,6 +1704,9 @@
                         intent.getStringExtra(Intent.EXTRA_SIM_STATE),
                         args.slotId,
                         args.subId);
+                if (args.slotId == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+                    return;
+                }
                 mHandler.obtainMessage(MSG_SIM_STATE_CHANGE, args.subId, args.slotId, args.simState)
                         .sendToTarget();
             } else if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action)) {
@@ -1940,7 +1944,13 @@
             }
             int state = TelephonyManager.SIM_STATE_UNKNOWN;
             String stateExtra = intent.getStringExtra(Intent.EXTRA_SIM_STATE);
-            int slotId = intent.getIntExtra(SubscriptionManager.EXTRA_SLOT_INDEX, 0);
+
+            int defaultSlotId = 0;
+            if (simPinBouncerReset()) {
+                defaultSlotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
+            }
+            int slotId = intent.getIntExtra(SubscriptionManager.EXTRA_SLOT_INDEX,
+                    defaultSlotId);
             int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
                     SubscriptionManager.INVALID_SUBSCRIPTION_ID);
             if (Intent.SIM_STATE_ABSENT.equals(stateExtra)) {
@@ -2479,6 +2489,12 @@
                     this::onTransitionStateChanged
             );
         }
+
+        // start() can be invoked in the middle of user switching, so check for this state and issue
+        // the call manually as that important event was missed.
+        if (mUserTracker.isUserSwitching()) {
+            handleUserSwitching(mUserTracker.getUserId(), () -> {});
+        }
     }
 
     @VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt b/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
index 342325f..6df8355 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
@@ -54,29 +54,25 @@
             addURI(
                 Contract.AUTHORITY,
                 Contract.LockScreenQuickAffordances.qualifiedTablePath(
-                    Contract.LockScreenQuickAffordances.SlotTable.TABLE_NAME,
+                    Contract.LockScreenQuickAffordances.SlotTable.TABLE_NAME
                 ),
                 MATCH_CODE_ALL_SLOTS,
             )
             addURI(
                 Contract.AUTHORITY,
                 Contract.LockScreenQuickAffordances.qualifiedTablePath(
-                    Contract.LockScreenQuickAffordances.AffordanceTable.TABLE_NAME,
+                    Contract.LockScreenQuickAffordances.AffordanceTable.TABLE_NAME
                 ),
                 MATCH_CODE_ALL_AFFORDANCES,
             )
             addURI(
                 Contract.AUTHORITY,
                 Contract.LockScreenQuickAffordances.qualifiedTablePath(
-                    Contract.LockScreenQuickAffordances.SelectionTable.TABLE_NAME,
+                    Contract.LockScreenQuickAffordances.SelectionTable.TABLE_NAME
                 ),
                 MATCH_CODE_ALL_SELECTIONS,
             )
-            addURI(
-                Contract.AUTHORITY,
-                Contract.FlagsTable.TABLE_NAME,
-                MATCH_CODE_ALL_FLAGS,
-            )
+            addURI(Contract.AUTHORITY, Contract.FlagsTable.TABLE_NAME, MATCH_CODE_ALL_FLAGS)
         }
 
     override fun onCreate(): Boolean {
@@ -106,15 +102,15 @@
             when (uriMatcher.match(uri)) {
                 MATCH_CODE_ALL_SLOTS ->
                     Contract.LockScreenQuickAffordances.qualifiedTablePath(
-                        Contract.LockScreenQuickAffordances.SlotTable.TABLE_NAME,
+                        Contract.LockScreenQuickAffordances.SlotTable.TABLE_NAME
                     )
                 MATCH_CODE_ALL_AFFORDANCES ->
                     Contract.LockScreenQuickAffordances.qualifiedTablePath(
-                        Contract.LockScreenQuickAffordances.AffordanceTable.TABLE_NAME,
+                        Contract.LockScreenQuickAffordances.AffordanceTable.TABLE_NAME
                     )
                 MATCH_CODE_ALL_SELECTIONS ->
                     Contract.LockScreenQuickAffordances.qualifiedTablePath(
-                        Contract.LockScreenQuickAffordances.SelectionTable.TABLE_NAME,
+                        Contract.LockScreenQuickAffordances.SelectionTable.TABLE_NAME
                     )
                 MATCH_CODE_ALL_FLAGS -> Contract.FlagsTable.TABLE_NAME
                 else -> null
@@ -128,6 +124,7 @@
     }
 
     override fun insert(uri: Uri, values: ContentValues?): Uri? {
+        if (!::mainDispatcher.isInitialized) return null
         if (uriMatcher.match(uri) != MATCH_CODE_ALL_SELECTIONS) {
             throw UnsupportedOperationException()
         }
@@ -142,6 +139,7 @@
         selectionArgs: Array<out String>?,
         sortOrder: String?,
     ): Cursor? {
+        if (!::mainDispatcher.isInitialized) return null
         return runBlocking("$TAG#query", mainDispatcher) {
             when (uriMatcher.match(uri)) {
                 MATCH_CODE_ALL_AFFORDANCES -> queryAffordances()
@@ -163,11 +161,8 @@
         return 0
     }
 
-    override fun delete(
-        uri: Uri,
-        selection: String?,
-        selectionArgs: Array<out String>?,
-    ): Int {
+    override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int {
+        if (!::mainDispatcher.isInitialized) return 0
         if (uriMatcher.match(uri) != MATCH_CODE_ALL_SELECTIONS) {
             throw UnsupportedOperationException()
         }
@@ -232,11 +227,7 @@
             throw IllegalArgumentException("Cannot insert selection, affordance ID was empty!")
         }
 
-        val success =
-            interactor.select(
-                slotId = slotId,
-                affordanceId = affordanceId,
-            )
+        val success = interactor.select(slotId = slotId, affordanceId = affordanceId)
 
         return if (success) {
             Log.d(TAG, "Successfully selected $affordanceId for slot $slotId")
@@ -318,22 +309,14 @@
             )
             .apply {
                 interactor.getSlotPickerRepresentations().forEach { representation ->
-                    addRow(
-                        arrayOf(
-                            representation.id,
-                            representation.maxSelectedAffordances,
-                        )
-                    )
+                    addRow(arrayOf(representation.id, representation.maxSelectedAffordances))
                 }
             }
     }
 
     private suspend fun queryFlags(): Cursor {
         return MatrixCursor(
-                arrayOf(
-                    Contract.FlagsTable.Columns.NAME,
-                    Contract.FlagsTable.Columns.VALUE,
-                )
+                arrayOf(Contract.FlagsTable.Columns.NAME, Contract.FlagsTable.Columns.VALUE)
             )
             .apply {
                 interactor.getPickerFlags().forEach { flag ->
@@ -351,10 +334,7 @@
             }
     }
 
-    private suspend fun deleteSelection(
-        uri: Uri,
-        selectionArgs: Array<out String>?,
-    ): Int {
+    private suspend fun deleteSelection(uri: Uri, selectionArgs: Array<out String>?): Int {
         if (selectionArgs == null) {
             throw IllegalArgumentException(
                 "Cannot delete selection, selection arguments not included!"
@@ -372,11 +352,7 @@
                     )
             }
 
-        val deleted =
-            interactor.unselect(
-                slotId = slotId,
-                affordanceId = affordanceId,
-            )
+        val deleted = interactor.unselect(slotId = slotId, affordanceId = affordanceId)
 
         return if (deleted) {
             Log.d(TAG, "Successfully unselected $affordanceId for slot $slotId")
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 3b1569d..1a0525d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -42,6 +42,7 @@
 import static com.android.systemui.DejankUtils.whitelistIpcs;
 import static com.android.systemui.Flags.notifyPowerManagerUserActivityBackground;
 import static com.android.systemui.Flags.relockWithPowerButtonImmediately;
+import static com.android.systemui.Flags.simPinBouncerReset;
 import static com.android.systemui.Flags.translucentOccludingActivityFix;
 import static com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel.DREAMING_ANIMATION_DURATION_MS;
 
@@ -238,7 +239,6 @@
     private static final long KEYGUARD_DONE_PENDING_TIMEOUT_MS = 3000;
 
     private static final boolean DEBUG = KeyguardConstants.DEBUG;
-    private static final boolean DEBUG_SIM_STATES = KeyguardConstants.DEBUG_SIM_STATES;
 
     private final static String TAG = "KeyguardViewMediator";
 
@@ -649,11 +649,8 @@
 
         @Override
         public void onSimStateChanged(int subId, int slotId, int simState) {
-
-            if (DEBUG_SIM_STATES) {
-                Log.d(TAG, "onSimStateChanged(subId=" + subId + ", slotId=" + slotId
-                        + ",state=" + simState + ")");
-            }
+            Log.d(TAG, "onSimStateChanged(subId=" + subId + ", slotId=" + slotId
+                    + ",state=" +  TelephonyManager.simStateToString(simState) + ")");
 
             int size = mKeyguardStateCallbacks.size();
             boolean simPinSecure = mUpdateMonitor.isSimPinSecure();
@@ -686,7 +683,7 @@
                     synchronized (KeyguardViewMediator.this) {
                         if (shouldWaitForProvisioning()) {
                             if (!mShowing) {
-                                if (DEBUG_SIM_STATES) Log.d(TAG, "ICC_ABSENT isn't showing,"
+                                Log.d(TAG, "ICC_ABSENT isn't showing,"
                                         + " we need to show the keyguard since the "
                                         + "device isn't provisioned yet.");
                                 doKeyguardLocked(null);
@@ -698,11 +695,21 @@
                             // MVNO SIMs can become transiently NOT_READY when switching networks,
                             // so we should only lock when they are ABSENT.
                             if (lastSimStateWasLocked) {
-                                if (DEBUG_SIM_STATES) Log.d(TAG, "SIM moved to ABSENT when the "
+                                Log.d(TAG, "SIM moved to ABSENT when the "
                                         + "previous state was locked. Reset the state.");
                                 resetStateLocked();
                             }
                             mSimWasLocked.append(slotId, false);
+                        } else if (simState == TelephonyManager.SIM_STATE_NOT_READY) {
+                            if (simPinBouncerReset()) {
+                                // Support eSIM disablement, and do not clear `mSimWasLocked`.
+                                // NOT_READY could just be a temporary state
+                                if (lastSimStateWasLocked) {
+                                    Log.d(TAG, "SIM moved to NOT_READY when the "
+                                            + "previous state was locked. Reset the state.");
+                                    resetStateLocked();
+                                }
+                            }
                         }
                     }
                     break;
@@ -712,7 +719,7 @@
                         mSimWasLocked.append(slotId, true);
                         mPendingPinLock = true;
                         if (!mShowing) {
-                            if (DEBUG_SIM_STATES) Log.d(TAG,
+                            Log.d(TAG,
                                     "INTENT_VALUE_ICC_LOCKED and keygaurd isn't "
                                     + "showing; need to show keyguard so user can enter sim pin");
                             doKeyguardLocked(null);
@@ -724,11 +731,11 @@
                 case TelephonyManager.SIM_STATE_PERM_DISABLED:
                     synchronized (KeyguardViewMediator.this) {
                         if (!mShowing) {
-                            if (DEBUG_SIM_STATES) Log.d(TAG, "PERM_DISABLED and "
+                            Log.d(TAG, "PERM_DISABLED and "
                                   + "keygaurd isn't showing.");
                             doKeyguardLocked(null);
                         } else {
-                            if (DEBUG_SIM_STATES) Log.d(TAG, "PERM_DISABLED, resetStateLocked to"
+                            Log.d(TAG, "PERM_DISABLED, resetStateLocked to"
                                   + "show permanently disabled message in lockscreen.");
                             resetStateLocked();
                         }
@@ -736,9 +743,9 @@
                     break;
                 case TelephonyManager.SIM_STATE_READY:
                     synchronized (KeyguardViewMediator.this) {
-                        if (DEBUG_SIM_STATES) Log.d(TAG, "READY, reset state? " + mShowing);
+                        Log.d(TAG, "READY, reset state? " + mShowing);
                         if (mShowing && mSimWasLocked.get(slotId, false)) {
-                            if (DEBUG_SIM_STATES) Log.d(TAG, "SIM moved to READY when the "
+                            Log.d(TAG, "SIM moved to READY when the "
                                     + "previously was locked. Reset the state.");
                             mSimWasLocked.append(slotId, false);
                             resetStateLocked();
@@ -746,7 +753,7 @@
                     }
                     break;
                 default:
-                    if (DEBUG_SIM_STATES) Log.v(TAG, "Unspecific state: " + simState);
+                    Log.v(TAG, "Unspecific state: " + simState);
                     break;
             }
         }
@@ -1682,6 +1689,12 @@
                     });
             mJavaAdapter.alwaysCollectFlow(communalViewModel.getTransitionFromOccludedEnded(),
                     getFinishedCallbackConsumer());
+
+            // System ready can be invoked in the middle of user switching, so check for this state
+            // and issue the call manually as that important event was missed.
+            if (mUserTracker.isUserSwitching()) {
+                mUpdateCallback.onUserSwitching(mUserTracker.getUserId());
+            }
         }
         // Most services aren't available until the system reaches the ready state, so we
         // send it here when the device first boots.
diff --git a/packages/SystemUI/src/com/android/systemui/settings/MultiUserUtilsModule.java b/packages/SystemUI/src/com/android/systemui/settings/MultiUserUtilsModule.java
index b9f9b92..05f19ef 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/MultiUserUtilsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/MultiUserUtilsModule.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.settings;
 
+import android.app.ActivityManager;
 import android.app.IActivityManager;
 import android.content.Context;
 import android.hardware.display.DisplayManager;
@@ -66,7 +67,7 @@
             @Background CoroutineDispatcher backgroundDispatcher,
             @Background Handler handler
     ) {
-        int startingUser = userManager.getBootUser().getIdentifier();
+        int startingUser = ActivityManager.getCurrentUser();
         UserTrackerImpl tracker = new UserTrackerImpl(context, featureFlagsProvider, userManager,
                 iActivityManager, dumpManager, appScope, backgroundDispatcher, handler);
         tracker.initialize(startingUser);
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt
index 1a997a7..e1631cc 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt
@@ -16,11 +16,10 @@
 
 package com.android.systemui.settings
 
-import com.android.systemui.util.annotations.WeaklyReferencedCallback
-
 import android.content.Context
 import android.content.pm.UserInfo
 import android.os.UserHandle
+import com.android.systemui.util.annotations.WeaklyReferencedCallback
 import java.util.concurrent.Executor
 
 /**
@@ -31,19 +30,13 @@
  */
 interface UserTracker : UserContentResolverProvider, UserContextProvider {
 
-    /**
-     * Current user's id.
-     */
+    /** Current user's id. */
     val userId: Int
 
-    /**
-     * [UserHandle] for current user
-     */
+    /** [UserHandle] for current user */
     val userHandle: UserHandle
 
-    /**
-     * [UserInfo] for current user
-     */
+    /** [UserInfo] for current user */
     val userInfo: UserInfo
 
     /**
@@ -56,39 +49,33 @@
      */
     val userProfiles: List<UserInfo>
 
-    /**
-     * Add a [Callback] to be notified of chances, on a particular [Executor]
-     */
+    /** Is the system in the process of switching users? */
+    val isUserSwitching: Boolean
+
+    /** Add a [Callback] to be notified of chances, on a particular [Executor] */
     fun addCallback(callback: Callback, executor: Executor)
 
-    /**
-     * Remove a [Callback] previously added.
-     */
+    /** Remove a [Callback] previously added. */
     fun removeCallback(callback: Callback)
 
-    /**
-     * Callback for notifying of changes.
-     */
+    /** Callback for notifying of changes. */
     @WeaklyReferencedCallback
     interface Callback {
-        /**
-         * Notifies that the current user will be changed.
-         */
+        /** Notifies that the current user will be changed. */
         fun onBeforeUserSwitching(newUser: Int) {}
 
         /**
-         * Same as {@link onUserChanging(Int, Context, Runnable)} but the callback will be
-         * called automatically after the completion of this method.
+         * Same as {@link onUserChanging(Int, Context, Runnable)} but the callback will be called
+         * automatically after the completion of this method.
          */
         fun onUserChanging(newUser: Int, userContext: Context) {}
 
         /**
-         * Notifies that the current user is being changed.
-         * Override this method to run things while the screen is frozen for the user switch.
-         * Please use {@link #onUserChanged} if the task doesn't need to push the unfreezing of the
-         * screen further. Please be aware that code executed in this callback will lengthen the
-         * user switch duration. When overriding this method, resultCallback#run() MUST be called
-         * once the  execution is complete.
+         * Notifies that the current user is being changed. Override this method to run things while
+         * the screen is frozen for the user switch. Please use {@link #onUserChanged} if the task
+         * doesn't need to push the unfreezing of the screen further. Please be aware that code
+         * executed in this callback will lengthen the user switch duration. When overriding this
+         * method, resultCallback#run() MUST be called once the execution is complete.
          */
         fun onUserChanging(newUser: Int, userContext: Context, resultCallback: Runnable) {
             onUserChanging(newUser, userContext)
@@ -96,15 +83,13 @@
         }
 
         /**
-         * Notifies that the current user has changed.
-         * Override this method to run things after the screen is unfrozen for the user switch.
-         * Please see {@link #onUserChanging} if you need to hide jank.
+         * Notifies that the current user has changed. Override this method to run things after the
+         * screen is unfrozen for the user switch. Please see {@link #onUserChanging} if you need to
+         * hide jank.
          */
         fun onUserChanged(newUser: Int, userContext: Context) {}
 
-        /**
-         * Notifies that the current user's profiles have changed.
-         */
+        /** Notifies that the current user's profiles have changed. */
         fun onProfilesChanged(profiles: List<@JvmSuppressWildcards UserInfo>) {}
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
index 553d1f5..1863e12 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
@@ -106,6 +106,9 @@
     override var userInfo: UserInfo by SynchronizedDelegate(UserInfo(context.userId, "", 0))
         protected set
 
+    override var isUserSwitching = false
+        protected set
+
     /**
      * Returns a [List<UserInfo>] of all profiles associated with the current user.
      *
@@ -197,6 +200,7 @@
                 }
 
                 override fun onUserSwitching(newUserId: Int, reply: IRemoteCallback?) {
+                    isUserSwitching = true
                     if (isBackgroundUserSwitchEnabled) {
                         userSwitchingJob?.cancel()
                         userSwitchingJob =
@@ -210,6 +214,7 @@
                 }
 
                 override fun onUserSwitchComplete(newUserId: Int) {
+                    isUserSwitching = false
                     if (isBackgroundUserSwitchEnabled) {
                         afterUserSwitchingJob?.cancel()
                         afterUserSwitchingJob =
@@ -221,7 +226,7 @@
                     }
                 }
             },
-            TAG
+            TAG,
         )
     }
 
@@ -349,7 +354,7 @@
 
 private data class DataItem(
     val callback: WeakReference<UserTracker.Callback>,
-    val executor: Executor
+    val executor: Executor,
 ) {
     fun sameOrEmpty(other: UserTracker.Callback): Boolean {
         return callback.get()?.equals(other) ?: true
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 52fde7e..4005e10 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -494,7 +494,7 @@
 
     @Test
     public void testIgnoresSimStateCallback_rebroadcast() {
-        Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+        Intent intent = defaultSimStateChangedIntent();
 
         mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(), intent);
         mTestableLooper.processAllMessages();
@@ -515,7 +515,8 @@
 
     @Test
     public void testTelephonyCapable_SimState_Absent() {
-        Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+
+        Intent intent = defaultSimStateChangedIntent();
         intent.putExtra(Intent.EXTRA_SIM_STATE,
                 Intent.SIM_STATE_ABSENT);
         mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
@@ -526,7 +527,7 @@
 
     @Test
     public void testTelephonyCapable_SimState_CardIOError() {
-        Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+        Intent intent = defaultSimStateChangedIntent();
         intent.putExtra(Intent.EXTRA_SIM_STATE,
                 Intent.SIM_STATE_CARD_IO_ERROR);
         mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
@@ -593,7 +594,7 @@
         ServiceState state = new ServiceState();
         state.setState(ServiceState.STATE_OUT_OF_SERVICE);
         state.fillInNotifierBundle(data);
-        Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+        Intent intent = defaultSimStateChangedIntent();
         intent.putExtra(Intent.EXTRA_SIM_STATE
                 , Intent.SIM_STATE_NOT_READY);
         mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext()
@@ -608,7 +609,7 @@
         ServiceState state = new ServiceState();
         state.setState(ServiceState.STATE_OUT_OF_SERVICE);
         state.fillInNotifierBundle(data);
-        Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+        Intent intent = defaultSimStateChangedIntent();
         intent.putExtra(Intent.EXTRA_SIM_STATE
                 , Intent.SIM_STATE_READY);
         mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext()
@@ -649,7 +650,7 @@
         ServiceState state = new ServiceState();
         state.setState(ServiceState.STATE_IN_SERVICE);
         state.fillInNotifierBundle(data);
-        Intent intentSimState = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+        Intent intentSimState = defaultSimStateChangedIntent();
         intentSimState.putExtra(Intent.EXTRA_SIM_STATE
                 , Intent.SIM_STATE_LOADED);
         mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext()
@@ -2256,6 +2257,12 @@
         Assert.assertFalse(mKeyguardUpdateMonitor.forceIsDismissibleIsKeepingDeviceUnlocked());
     }
 
+    private Intent defaultSimStateChangedIntent() {
+        Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+        intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, 0);
+        return intent;
+    }
+
     private void verifyFingerprintAuthenticateNeverCalled() {
         verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), any());
         verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 597ffef..9e0d358 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -26,6 +26,7 @@
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
 import static com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR;
+import static com.android.systemui.Flags.FLAG_SIM_PIN_BOUNCER_RESET;
 import static com.android.systemui.keyguard.KeyguardViewMediator.DELAYED_KEYGUARD_ACTION;
 import static com.android.systemui.keyguard.KeyguardViewMediator.KEYGUARD_LOCK_AFTER_DELAY_DEFAULT;
 import static com.android.systemui.keyguard.KeyguardViewMediator.REBOOT_MAINLINE_UPDATE;
@@ -62,6 +63,7 @@
 import android.os.PowerManager;
 import android.os.PowerManager.WakeLock;
 import android.os.RemoteException;
+import android.platform.test.annotations.EnableFlags;
 import android.telephony.TelephonyManager;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -588,6 +590,35 @@
 
     @Test
     @TestableLooper.RunWithLooper(setAsMainLooper = true)
+    @EnableFlags(FLAG_SIM_PIN_BOUNCER_RESET)
+    public void resetStateLocked_whenSimNotReadyAndWasLockedPrior() {
+        // When showing and provisioned
+        mViewMediator.onSystemReady();
+        when(mUpdateMonitor.isDeviceProvisioned()).thenReturn(true);
+        mViewMediator.setShowingLocked(true, "");
+
+        // and a SIM becomes locked and requires a PIN
+        mViewMediator.mUpdateCallback.onSimStateChanged(
+                1 /* subId */,
+                0 /* slotId */,
+                TelephonyManager.SIM_STATE_PIN_REQUIRED);
+        TestableLooper.get(this).processAllMessages();
+
+        reset(mStatusBarKeyguardViewManager);
+
+        // but then disabled by a NOT_READY
+        mViewMediator.mUpdateCallback.onSimStateChanged(
+                1 /* subId */,
+                0 /* slotId */,
+                TelephonyManager.SIM_STATE_NOT_READY);
+        TestableLooper.get(this).processAllMessages();
+
+        // A call to reset the keyguard and bouncer was invoked
+        verify(mStatusBarKeyguardViewManager).reset(true);
+    }
+
+    @Test
+    @TestableLooper.RunWithLooper(setAsMainLooper = true)
     public void restoreBouncerWhenSimLockedAndKeyguardIsGoingAway_initiallyNotShowing() {
         // When showing and provisioned
         mViewMediator.onSystemReady();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt
index 2e2ac3e..a0ecb80 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt
@@ -231,7 +231,7 @@
                         "",
                         "",
                         UserInfo.FLAG_MANAGED_PROFILE,
-                        UserManager.USER_TYPE_PROFILE_MANAGED
+                        UserManager.USER_TYPE_PROFILE_MANAGED,
                     )
                 infoProfile.profileGroupId = id
                 listOf(info, infoProfile)
@@ -261,7 +261,7 @@
                         "",
                         "",
                         UserInfo.FLAG_MANAGED_PROFILE or UserInfo.FLAG_QUIET_MODE,
-                        UserManager.USER_TYPE_PROFILE_MANAGED
+                        UserManager.USER_TYPE_PROFILE_MANAGED,
                     )
                 infoProfile.profileGroupId = id
                 listOf(info, infoProfile)
@@ -291,7 +291,7 @@
                         "",
                         "",
                         UserInfo.FLAG_MANAGED_PROFILE,
-                        UserManager.USER_TYPE_PROFILE_MANAGED
+                        UserManager.USER_TYPE_PROFILE_MANAGED,
                     )
                 infoProfile.profileGroupId = id
                 listOf(info, infoProfile)
@@ -423,7 +423,7 @@
                         "",
                         "",
                         UserInfo.FLAG_MANAGED_PROFILE,
-                        UserManager.USER_TYPE_PROFILE_MANAGED
+                        UserManager.USER_TYPE_PROFILE_MANAGED,
                     )
                 infoProfile.profileGroupId = id
                 listOf(info, infoProfile)
@@ -469,6 +469,24 @@
             assertThat(callback.calledOnProfilesChanged).isEqualTo(0)
         }
 
+    @Test
+    fun testisUserSwitching() =
+        testScope.runTest {
+            tracker.initialize(0)
+            val newID = 5
+            val profileID = newID + 10
+
+            val captor = ArgumentCaptor.forClass(IUserSwitchObserver::class.java)
+            verify(iActivityManager).registerUserSwitchObserver(capture(captor), anyString())
+            assertThat(tracker.isUserSwitching).isFalse()
+
+            captor.value.onUserSwitching(newID, userSwitchingReply)
+            assertThat(tracker.isUserSwitching).isTrue()
+
+            captor.value.onUserSwitchComplete(newID)
+            assertThat(tracker.isUserSwitching).isFalse()
+        }
+
     private class TestCallback : UserTracker.Callback {
         var calledOnUserChanging = 0
         var calledOnUserChanged = 0
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt
index f3d5b7d..cd76a74 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt
@@ -33,6 +33,7 @@
     private var _userHandle: UserHandle = UserHandle.of(_userId),
     private var _userInfo: UserInfo = mock(),
     private var _userProfiles: List<UserInfo> = emptyList(),
+    private var _isUserSwitching: Boolean = false,
     userContentResolverProvider: () -> ContentResolver = { MockContentResolver() },
     userContext: Context = mock(),
     private val onCreateCurrentUserContext: (Context) -> Context = { mock() },
@@ -51,6 +52,9 @@
     override val userProfiles: List<UserInfo>
         get() = _userProfiles
 
+    override val isUserSwitching: Boolean
+        get() = _isUserSwitching
+
     // userContentResolver is lazy because Ravenwood doesn't support MockContentResolver()
     // and we still want to allow people use this class for tests that don't use it.
     override val userContentResolver: ContentResolver by lazy { userContentResolverProvider() }
@@ -86,11 +90,13 @@
     }
 
     fun onUserChanging(userId: Int = _userId) {
+        _isUserSwitching = true
         val copy = callbacks.toList()
         copy.forEach { it.onUserChanging(userId, userContext) {} }
     }
 
     fun onUserChanged(userId: Int = _userId) {
+        _isUserSwitching = false
         val copy = callbacks.toList()
         copy.forEach { it.onUserChanged(userId, userContext) }
     }