diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index f4355798a381f..fd7a6e624e2db 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -315,6 +315,7 @@ public class KeyguardSecurityContainer extends FrameLayout { 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 @@ public class KeyguardSecurityContainer extends FrameLayout { * 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 @@ public class KeyguardSecurityContainer extends FrameLayout { default int getChildWidthMeasureSpec(int parentWidthMeasureSpec) { return parentWidthMeasureSpec; } + + /** Called when we are setting a new ViewMode */ + default void onDestroy() {}; } /** @@ -781,6 +784,8 @@ public class KeyguardSecurityContainer extends FrameLayout { 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 @@ public class KeyguardSecurityContainer extends FrameLayout { mUserSwitcher = mView.findViewById(R.id.user_switcher_header); setupUserSwitcher(); + mUserSwitcherController.addUserSwitchCallback(mUserSwitchCallback); } @Override @@ -813,7 +819,11 @@ public class KeyguardSecurityContainer extends FrameLayout { 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 28938d19c3b53..f151d291cda38 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 com.android.systemui.util.settings.SecureSettings; 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 @@ public class UserSwitcherController implements Dumpable { private View mView; private String mCreateSupervisedUserPackage; private GlobalSettings mGlobalSettings; + private List mUserSwitchCallbacks = + Collections.synchronizedList(new ArrayList<>()); @Inject public UserSwitcherController(Context context, @@ -230,7 +233,8 @@ public class UserSwitcherController implements Dumpable { 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 @@ public class UserSwitcherController implements Dumpable { i--; } } + notifyUserSwitchCallbacks(); notifyAdapters(); // Disconnect from the old secondary user's service @@ -1134,6 +1139,33 @@ public class UserSwitcherController implements Dumpable { 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 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 @@ public class UserSwitcherController implements Dumpable { } } } + + /** + * 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 152815f2d47e2..e0bf9e7b00819 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 @@ package com.android.systemui.statusbar.policy 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.settings.UserTracker 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.Before 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 @@ class UserSwitcherControllerTest : SysuiTestCase() { setupController() assertFalse(userSwitcherController.canCreateSupervisedUser()) } + + @Test + fun addUserSwitchCallback() { + val broadcastReceiverCaptor = argumentCaptor() + 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() + } }