Merge "[MultiUser] fix async bouncer user" into tm-dev am: ab9ea4a88e am: 20cca28444

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17870576

Change-Id: I6b037b2118574647b59dc7967416f051e58a42b5
Ignore-AOSP-First: this is an automerge
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index f435579..fd7a6e6 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -315,6 +315,7 @@
         Log.i(TAG, "Switching mode from " + modeToString(mCurrentMode) + " to "
                 + modeToString(mode));
         mCurrentMode = mode;
+        mViewMode.onDestroy();
 
         switch (mode) {
             case MODE_ONE_HANDED:
@@ -710,7 +711,6 @@
      * Enscapsulates the differences between bouncer modes for the container.
      */
     interface ViewMode {
-
         default void init(@NonNull ViewGroup v, @NonNull GlobalSettings globalSettings,
                 @NonNull KeyguardSecurityViewFlipper viewFlipper,
                 @NonNull FalsingManager falsingManager,
@@ -738,6 +738,9 @@
         default int getChildWidthMeasureSpec(int parentWidthMeasureSpec) {
             return parentWidthMeasureSpec;
         }
+
+        /** Called when we are setting a new ViewMode */
+        default void onDestroy() {};
     }
 
     /**
@@ -781,6 +784,8 @@
         private UserSwitcherController mUserSwitcherController;
         private KeyguardUserSwitcherPopupMenu mPopup;
         private Resources mResources;
+        private UserSwitcherController.UserSwitchCallback mUserSwitchCallback =
+                this::setupUserSwitcher;
 
         @Override
         public void init(@NonNull ViewGroup v, @NonNull GlobalSettings globalSettings,
@@ -805,6 +810,7 @@
 
             mUserSwitcher = mView.findViewById(R.id.user_switcher_header);
             setupUserSwitcher();
+            mUserSwitcherController.addUserSwitchCallback(mUserSwitchCallback);
         }
 
         @Override
@@ -813,7 +819,11 @@
                 mPopup.dismiss();
                 mPopup = null;
             }
-            setupUserSwitcher();
+        }
+
+        @Override
+        public void onDestroy() {
+            mUserSwitcherController.removeUserSwitchCallback(mUserSwitchCallback);
         }
 
         private Drawable findUserIcon(int userId) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 5eff8cd..6af8e9e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -90,6 +90,7 @@
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -165,6 +166,8 @@
     private View mView;
     private String mCreateSupervisedUserPackage;
     private GlobalSettings mGlobalSettings;
+    private List<UserSwitchCallback> mUserSwitchCallbacks =
+            Collections.synchronizedList(new ArrayList<>());
 
     @Inject
     public UserSwitcherController(Context context,
@@ -230,7 +233,8 @@
         filter.addAction(Intent.ACTION_USER_STOPPED);
         filter.addAction(Intent.ACTION_USER_UNLOCKED);
         mBroadcastDispatcher.registerReceiver(
-                mReceiver, filter, null /* handler */, UserHandle.SYSTEM);
+                mReceiver, filter, null /* executor */,
+                UserHandle.SYSTEM, Context.RECEIVER_EXPORTED, null /* permission */);
 
         mSimpleUserSwitcher = shouldUseSimpleUserSwitcher();
 
@@ -673,6 +677,7 @@
                         i--;
                     }
                 }
+                notifyUserSwitchCallbacks();
                 notifyAdapters();
 
                 // Disconnect from the old secondary user's service
@@ -1134,6 +1139,33 @@
         mActivityStarter.startActivity(intent, true);
     }
 
+    /**
+     *  Add a subscriber to when user switches.
+     */
+    public void addUserSwitchCallback(UserSwitchCallback callback) {
+        mUserSwitchCallbacks.add(callback);
+    }
+
+    /**
+     *  Remove a subscriber to when user switches.
+     */
+    public void removeUserSwitchCallback(UserSwitchCallback callback) {
+        mUserSwitchCallbacks.remove(callback);
+    }
+
+    /**
+     *  Notify user switch callbacks that user has switched.
+     */
+    private void notifyUserSwitchCallbacks() {
+        List<UserSwitchCallback> temp;
+        synchronized (mUserSwitchCallbacks) {
+            temp = new ArrayList<>(mUserSwitchCallbacks);
+        }
+        for (UserSwitchCallback callback : temp) {
+            callback.onUserSwitched();
+        }
+    }
+
     public static final class UserRecord {
         public final UserInfo info;
         public final Bitmap picture;
@@ -1383,4 +1415,14 @@
             }
         }
     }
+
+    /**
+     * Callback to for when this controller receives the intent to switch users.
+     */
+    public interface UserSwitchCallback {
+        /**
+         * Called when user has switched.
+         */
+        void onUserSwitched();
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
index 152815f..e0bf9e7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
@@ -19,6 +19,7 @@
 import android.app.IActivityManager
 import android.app.NotificationManager
 import android.app.admin.DevicePolicyManager
+import android.content.BroadcastReceiver
 import android.content.Context
 import android.content.DialogInterface
 import android.content.Intent
@@ -55,6 +56,10 @@
 import com.android.systemui.statusbar.phone.NotificationShadeWindowView
 import com.android.systemui.telephony.TelephonyListenerManager
 import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.nullable
 import com.android.systemui.util.settings.GlobalSettings
 import com.android.systemui.util.settings.SecureSettings
 import com.android.systemui.util.time.FakeSystemClock
@@ -66,10 +71,8 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.ArgumentMatchers.anyInt
-import org.mockito.ArgumentMatchers.eq
 import org.mockito.Mock
 import org.mockito.Mockito.`when`
-import org.mockito.Mockito.any
 import org.mockito.Mockito.doNothing
 import org.mockito.Mockito.doReturn
 import org.mockito.Mockito.eq
@@ -561,4 +564,20 @@
         setupController()
         assertFalse(userSwitcherController.canCreateSupervisedUser())
     }
+
+    @Test
+    fun addUserSwitchCallback() {
+        val broadcastReceiverCaptor = argumentCaptor<BroadcastReceiver>()
+        verify(broadcastDispatcher).registerReceiver(
+                capture(broadcastReceiverCaptor),
+                any(),
+                nullable(), nullable(), anyInt(), nullable())
+
+        val cb = mock(UserSwitcherController.UserSwitchCallback::class.java)
+        userSwitcherController.addUserSwitchCallback(cb)
+
+        val intent = Intent(Intent.ACTION_USER_SWITCHED).putExtra(Intent.EXTRA_USER_HANDLE, guestId)
+        broadcastReceiverCaptor.value.onReceive(context, intent)
+        verify(cb).onUserSwitched()
+    }
 }