diff options
| author | 2022-12-27 17:00:52 -0800 | |
|---|---|---|
| committer | 2022-12-28 19:51:15 +0000 | |
| commit | 637af6858edaec0787e2a7e446a32413f85c7033 (patch) | |
| tree | 197cb94f88cf3d8182770586ca526e540973c1a7 | |
| parent | b425997d1ffda0dda270c1c46e0a85bbf31d5372 (diff) | |
Fixes user switcher dialog animations.
The user switcher dialog uses a chain of dialogs linked through common
CUJs to morph-animate dialogs into one another as the user goes through
flows that require showing a second dialog after the first.
ag/20259287 was an overzealous fix for b/254704051; a bug where the user
switcher dialog was still visible above the "add supervised user"
activity. The fix addressed the problem but introduced a regression
because it was dismissing the user switcher dialog each time any item
in the dialog was clicked.
This CL basically reverts ag/20259287 and re-does the fix more
surgically in a lower layer. UserInteractor will ask to dismiss the
dialog if it wants to start the activity for the specific action of
adding a supervised user.
Fix: 262743114
Test: modified UserInteractorTest (and also modernized it all)
Test: manually verified that the dialogs morph-animate
Test: manually verified that starting the "add supervised user" activity
causes the user switcher dialog to be dismissed
Test: all tested on handheld device (phone)
Change-Id: Ia33c8644ca891879f36c62c0257ebdc897623c40
6 files changed, 135 insertions, 204 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java index 57a00c9a1620..b6b657ec82f6 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java @@ -204,15 +204,6 @@ public class UserDetailView extends PseudoGridView { Trace.endSection(); } - @Override - public void onUserListItemClicked(@NonNull UserRecord record, - @Nullable UserSwitchDialogController.DialogShower dialogShower) { - if (dialogShower != null) { - mDialogShower.dismiss(); - } - super.onUserListItemClicked(record, dialogShower); - } - public void linkToViewGroup(ViewGroup viewGroup) { PseudoGridView.ViewGroupAdapterBridge.link(viewGroup, this); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt index 68d30d3f3d1e..2b4f51c63043 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt @@ -60,7 +60,7 @@ protected constructor( * animation to and from the parent dialog. */ @JvmOverloads - open fun onUserListItemClicked( + fun onUserListItemClicked( record: UserRecord, dialogShower: DialogShower? = null, ) { diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt index 45cb11e80172..c8f98c35f589 100644 --- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt @@ -455,6 +455,7 @@ constructor( } UserActionModel.ADD_SUPERVISED_USER -> { uiEventLogger.log(MultiUserActionsEvent.CREATE_RESTRICTED_USER_FROM_USER_SWITCHER) + dismissDialog() activityStarter.startActivity( Intent() .setAction(UserManager.ACTION_CREATE_SUPERVISED_USER) diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/dialog/UserSwitcherDialogCoordinator.kt b/packages/SystemUI/src/com/android/systemui/user/ui/dialog/UserSwitcherDialogCoordinator.kt index d4512309f6c6..79721b370c21 100644 --- a/packages/SystemUI/src/com/android/systemui/user/ui/dialog/UserSwitcherDialogCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/user/ui/dialog/UserSwitcherDialogCoordinator.kt @@ -66,12 +66,6 @@ constructor( private fun startHandlingDialogShowRequests() { applicationScope.get().launch { interactor.get().dialogShowRequests.filterNotNull().collect { request -> - currentDialog?.let { - if (it.isShowing) { - it.cancel() - } - } - val (dialog, dialogCuj) = when (request) { is ShowDialogRequestModel.ShowAddUserDialog -> diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt index 08a90b79089e..18e40f633955 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt @@ -30,7 +30,6 @@ import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.classifier.FalsingManagerFake import com.android.systemui.qs.QSUserSwitcherEvent -import com.android.systemui.qs.user.UserSwitchDialogController import com.android.systemui.statusbar.policy.UserSwitcherController import com.android.systemui.user.data.source.UserRecord import org.junit.Assert.assertEquals @@ -42,7 +41,6 @@ import org.mockito.ArgumentMatchers.any import org.mockito.ArgumentMatchers.anyBoolean import org.mockito.ArgumentMatchers.anyInt import org.mockito.Mock -import org.mockito.Mockito.mock import org.mockito.Mockito.verify import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations @@ -152,15 +150,6 @@ class UserDetailViewAdapterTest : SysuiTestCase() { assertNull(adapter.users.find { it.isManageUsers }) } - @Test - fun clickDismissDialog() { - val shower: UserSwitchDialogController.DialogShower = - mock(UserSwitchDialogController.DialogShower::class.java) - adapter.injectDialogShower(shower) - adapter.onUserListItemClicked(createUserRecord(current = true, guest = false), shower) - verify(shower).dismiss() - } - private fun createUserRecord(current: Boolean, guest: Boolean) = UserRecord( UserInfo(0 /* id */, "name", 0 /* flags */), diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt index 95345756f4ae..1a2ee1809dff 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt @@ -36,6 +36,7 @@ import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.animation.Expandable import com.android.systemui.common.shared.model.Text +import com.android.systemui.coroutines.collectLastValue import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository @@ -61,12 +62,12 @@ import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.nullable import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.test.TestCoroutineScope -import kotlinx.coroutines.test.advanceUntilIdle +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.launch +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -74,11 +75,13 @@ import org.junit.runners.JUnit4 import org.mockito.ArgumentMatchers.anyBoolean import org.mockito.ArgumentMatchers.anyInt import org.mockito.Mock +import org.mockito.Mockito.atLeastOnce import org.mockito.Mockito.never import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations +@OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(JUnit4::class) class UserInteractorTest : SysuiTestCase() { @@ -95,7 +98,7 @@ class UserInteractorTest : SysuiTestCase() { private lateinit var underTest: UserInteractor - private lateinit var testCoroutineScope: TestCoroutineScope + private lateinit var testScope: TestScope private lateinit var userRepository: FakeUserRepository private lateinit var keyguardRepository: FakeKeyguardRepository private lateinit var telephonyRepository: FakeTelephonyRepository @@ -119,11 +122,12 @@ class UserInteractorTest : SysuiTestCase() { userRepository = FakeUserRepository() keyguardRepository = FakeKeyguardRepository() telephonyRepository = FakeTelephonyRepository() - testCoroutineScope = TestCoroutineScope() + val testDispatcher = StandardTestDispatcher() + testScope = TestScope(testDispatcher) val refreshUsersScheduler = RefreshUsersScheduler( - applicationScope = testCoroutineScope, - mainDispatcher = IMMEDIATE, + applicationScope = testScope.backgroundScope, + mainDispatcher = testDispatcher, repository = userRepository, ) underTest = @@ -136,21 +140,21 @@ class UserInteractorTest : SysuiTestCase() { repository = keyguardRepository, ), manager = manager, - applicationScope = testCoroutineScope, + applicationScope = testScope.backgroundScope, telephonyInteractor = TelephonyInteractor( repository = telephonyRepository, ), broadcastDispatcher = fakeBroadcastDispatcher, - backgroundDispatcher = IMMEDIATE, + backgroundDispatcher = testDispatcher, activityManager = activityManager, refreshUsersScheduler = refreshUsersScheduler, guestUserInteractor = GuestUserInteractor( applicationContext = context, - applicationScope = testCoroutineScope, - mainDispatcher = IMMEDIATE, - backgroundDispatcher = IMMEDIATE, + applicationScope = testScope.backgroundScope, + mainDispatcher = testDispatcher, + backgroundDispatcher = testDispatcher, manager = manager, repository = userRepository, deviceProvisionedController = deviceProvisionedController, @@ -167,7 +171,7 @@ class UserInteractorTest : SysuiTestCase() { @Test fun `onRecordSelected - user`() = - runBlocking(IMMEDIATE) { + testScope.runTest { val userInfos = createUserInfos(count = 3, includeGuest = false) userRepository.setUserInfos(userInfos) userRepository.setSelectedUserInfo(userInfos[0]) @@ -184,7 +188,7 @@ class UserInteractorTest : SysuiTestCase() { @Test fun `onRecordSelected - switch to guest user`() = - runBlocking(IMMEDIATE) { + testScope.runTest { val userInfos = createUserInfos(count = 3, includeGuest = true) userRepository.setUserInfos(userInfos) userRepository.setSelectedUserInfo(userInfos[0]) @@ -200,7 +204,7 @@ class UserInteractorTest : SysuiTestCase() { @Test fun `onRecordSelected - switch to restricted user`() = - runBlocking(IMMEDIATE) { + testScope.runTest { var userInfos = createUserInfos(count = 2, includeGuest = false).toMutableList() userInfos.add( UserInfo( @@ -225,7 +229,7 @@ class UserInteractorTest : SysuiTestCase() { @Test fun `onRecordSelected - enter guest mode`() = - runBlocking(IMMEDIATE) { + testScope.runTest { val userInfos = createUserInfos(count = 3, includeGuest = false) userRepository.setUserInfos(userInfos) userRepository.setSelectedUserInfo(userInfos[0]) @@ -234,6 +238,7 @@ class UserInteractorTest : SysuiTestCase() { whenever(manager.createGuest(any())).thenReturn(guestUserInfo) underTest.onRecordSelected(UserRecord(isGuest = true), dialogShower) + runCurrent() verify(uiEventLogger, times(1)) .log(MultiUserActionsEvent.CREATE_GUEST_FROM_USER_SWITCHER) @@ -244,7 +249,7 @@ class UserInteractorTest : SysuiTestCase() { @Test fun `onRecordSelected - action`() = - runBlocking(IMMEDIATE) { + testScope.runTest { val userInfos = createUserInfos(count = 3, includeGuest = true) userRepository.setUserInfos(userInfos) userRepository.setSelectedUserInfo(userInfos[0]) @@ -260,81 +265,72 @@ class UserInteractorTest : SysuiTestCase() { @Test fun `users - switcher enabled`() = - runBlocking(IMMEDIATE) { + testScope.runTest { val userInfos = createUserInfos(count = 3, includeGuest = true) userRepository.setUserInfos(userInfos) userRepository.setSelectedUserInfo(userInfos[0]) userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) - var value: List<UserModel>? = null - val job = underTest.users.onEach { value = it }.launchIn(this) - assertUsers(models = value, count = 3, includeGuest = true) + val value = collectLastValue(underTest.users) - job.cancel() + assertUsers(models = value(), count = 3, includeGuest = true) } @Test fun `users - switches to second user`() = - runBlocking(IMMEDIATE) { + testScope.runTest { val userInfos = createUserInfos(count = 2, includeGuest = false) userRepository.setUserInfos(userInfos) userRepository.setSelectedUserInfo(userInfos[0]) userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) - var value: List<UserModel>? = null - val job = underTest.users.onEach { value = it }.launchIn(this) + val value = collectLastValue(underTest.users) userRepository.setSelectedUserInfo(userInfos[1]) - assertUsers(models = value, count = 2, selectedIndex = 1) - job.cancel() + assertUsers(models = value(), count = 2, selectedIndex = 1) } @Test fun `users - switcher not enabled`() = - runBlocking(IMMEDIATE) { + testScope.runTest { val userInfos = createUserInfos(count = 2, includeGuest = false) userRepository.setUserInfos(userInfos) userRepository.setSelectedUserInfo(userInfos[0]) userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = false)) - var value: List<UserModel>? = null - val job = underTest.users.onEach { value = it }.launchIn(this) - assertUsers(models = value, count = 1) - - job.cancel() + val value = collectLastValue(underTest.users) + assertUsers(models = value(), count = 1) } @Test fun selectedUser() = - runBlocking(IMMEDIATE) { + testScope.runTest { val userInfos = createUserInfos(count = 2, includeGuest = false) userRepository.setUserInfos(userInfos) userRepository.setSelectedUserInfo(userInfos[0]) userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) - var value: UserModel? = null - val job = underTest.selectedUser.onEach { value = it }.launchIn(this) - assertUser(value, id = 0, isSelected = true) + val value = collectLastValue(underTest.selectedUser) + assertUser(value(), id = 0, isSelected = true) userRepository.setSelectedUserInfo(userInfos[1]) - assertUser(value, id = 1, isSelected = true) - - job.cancel() + assertUser(value(), id = 1, isSelected = true) } @Test fun `actions - device unlocked`() = - runBlocking(IMMEDIATE) { + testScope.runTest { val userInfos = createUserInfos(count = 2, includeGuest = false) userRepository.setUserInfos(userInfos) userRepository.setSelectedUserInfo(userInfos[0]) userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) keyguardRepository.setKeyguardShowing(false) - var value: List<UserActionModel>? = null - val job = underTest.actions.onEach { value = it }.launchIn(this) + val value = collectLastValue(underTest.actions) + + runCurrent() - assertThat(value) + assertThat(value()) .isEqualTo( listOf( UserActionModel.ENTER_GUEST_MODE, @@ -343,13 +339,11 @@ class UserInteractorTest : SysuiTestCase() { UserActionModel.NAVIGATE_TO_USER_MANAGEMENT, ) ) - - job.cancel() } @Test fun `actions - device unlocked - full screen`() = - runBlocking(IMMEDIATE) { + testScope.runTest { featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true) val userInfos = createUserInfos(count = 2, includeGuest = false) @@ -357,10 +351,9 @@ class UserInteractorTest : SysuiTestCase() { userRepository.setSelectedUserInfo(userInfos[0]) userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) keyguardRepository.setKeyguardShowing(false) - var value: List<UserActionModel>? = null - val job = underTest.actions.onEach { value = it }.launchIn(this) + val value = collectLastValue(underTest.actions) - assertThat(value) + assertThat(value()) .isEqualTo( listOf( UserActionModel.ADD_USER, @@ -369,46 +362,38 @@ class UserInteractorTest : SysuiTestCase() { UserActionModel.NAVIGATE_TO_USER_MANAGEMENT, ) ) - - job.cancel() } @Test fun `actions - device unlocked user not primary - empty list`() = - runBlocking(IMMEDIATE) { + testScope.runTest { val userInfos = createUserInfos(count = 2, includeGuest = false) userRepository.setUserInfos(userInfos) userRepository.setSelectedUserInfo(userInfos[1]) userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) keyguardRepository.setKeyguardShowing(false) - var value: List<UserActionModel>? = null - val job = underTest.actions.onEach { value = it }.launchIn(this) + val value = collectLastValue(underTest.actions) - assertThat(value).isEqualTo(emptyList<UserActionModel>()) - - job.cancel() + assertThat(value()).isEqualTo(emptyList<UserActionModel>()) } @Test fun `actions - device unlocked user is guest - empty list`() = - runBlocking(IMMEDIATE) { + testScope.runTest { val userInfos = createUserInfos(count = 2, includeGuest = true) assertThat(userInfos[1].isGuest).isTrue() userRepository.setUserInfos(userInfos) userRepository.setSelectedUserInfo(userInfos[1]) userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) keyguardRepository.setKeyguardShowing(false) - var value: List<UserActionModel>? = null - val job = underTest.actions.onEach { value = it }.launchIn(this) - - assertThat(value).isEqualTo(emptyList<UserActionModel>()) + val value = collectLastValue(underTest.actions) - job.cancel() + assertThat(value()).isEqualTo(emptyList<UserActionModel>()) } @Test fun `actions - device locked add from lockscreen set - full list`() = - runBlocking(IMMEDIATE) { + testScope.runTest { val userInfos = createUserInfos(count = 2, includeGuest = false) userRepository.setUserInfos(userInfos) userRepository.setSelectedUserInfo(userInfos[0]) @@ -419,10 +404,9 @@ class UserInteractorTest : SysuiTestCase() { ) ) keyguardRepository.setKeyguardShowing(false) - var value: List<UserActionModel>? = null - val job = underTest.actions.onEach { value = it }.launchIn(this) + val value = collectLastValue(underTest.actions) - assertThat(value) + assertThat(value()) .isEqualTo( listOf( UserActionModel.ENTER_GUEST_MODE, @@ -431,13 +415,11 @@ class UserInteractorTest : SysuiTestCase() { UserActionModel.NAVIGATE_TO_USER_MANAGEMENT, ) ) - - job.cancel() } @Test fun `actions - device locked add from lockscreen set - full list - full screen`() = - runBlocking(IMMEDIATE) { + testScope.runTest { featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true) val userInfos = createUserInfos(count = 2, includeGuest = false) userRepository.setUserInfos(userInfos) @@ -449,10 +431,9 @@ class UserInteractorTest : SysuiTestCase() { ) ) keyguardRepository.setKeyguardShowing(false) - var value: List<UserActionModel>? = null - val job = underTest.actions.onEach { value = it }.launchIn(this) + val value = collectLastValue(underTest.actions) - assertThat(value) + assertThat(value()) .isEqualTo( listOf( UserActionModel.ADD_USER, @@ -461,42 +442,35 @@ class UserInteractorTest : SysuiTestCase() { UserActionModel.NAVIGATE_TO_USER_MANAGEMENT, ) ) - - job.cancel() } @Test fun `actions - device locked - only manage user is shown`() = - runBlocking(IMMEDIATE) { + testScope.runTest { val userInfos = createUserInfos(count = 2, includeGuest = false) userRepository.setUserInfos(userInfos) userRepository.setSelectedUserInfo(userInfos[0]) userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) keyguardRepository.setKeyguardShowing(true) - var value: List<UserActionModel>? = null - val job = underTest.actions.onEach { value = it }.launchIn(this) + val value = collectLastValue(underTest.actions) - assertThat(value).isEqualTo(listOf(UserActionModel.NAVIGATE_TO_USER_MANAGEMENT)) - - job.cancel() + assertThat(value()).isEqualTo(listOf(UserActionModel.NAVIGATE_TO_USER_MANAGEMENT)) } @Test fun `executeAction - add user - dialog shown`() = - runBlocking(IMMEDIATE) { + testScope.runTest { val userInfos = createUserInfos(count = 2, includeGuest = false) userRepository.setUserInfos(userInfos) userRepository.setSelectedUserInfo(userInfos[0]) keyguardRepository.setKeyguardShowing(false) - var dialogRequest: ShowDialogRequestModel? = null - val job = underTest.dialogShowRequests.onEach { dialogRequest = it }.launchIn(this) + val dialogRequest = collectLastValue(underTest.dialogShowRequests) val dialogShower: UserSwitchDialogController.DialogShower = mock() underTest.executeAction(UserActionModel.ADD_USER, dialogShower) - verify(uiEventLogger, times(1)) .log(MultiUserActionsEvent.CREATE_USER_FROM_USER_SWITCHER) - assertThat(dialogRequest) + assertThat(dialogRequest()) .isEqualTo( ShowDialogRequestModel.ShowAddUserDialog( userHandle = userInfos[0].userHandle, @@ -507,14 +481,12 @@ class UserInteractorTest : SysuiTestCase() { ) underTest.onDialogShown() - assertThat(dialogRequest).isNull() - - job.cancel() + assertThat(dialogRequest()).isNull() } @Test - fun `executeAction - add supervised user - starts activity`() = - runBlocking(IMMEDIATE) { + fun `executeAction - add supervised user - dismisses dialog and starts activity`() = + testScope.runTest { underTest.executeAction(UserActionModel.ADD_SUPERVISED_USER) verify(uiEventLogger, times(1)) @@ -528,7 +500,7 @@ class UserInteractorTest : SysuiTestCase() { @Test fun `executeAction - navigate to manage users`() = - runBlocking(IMMEDIATE) { + testScope.runTest { underTest.executeAction(UserActionModel.NAVIGATE_TO_USER_MANAGEMENT) val intentCaptor = kotlinArgumentCaptor<Intent>() @@ -538,7 +510,7 @@ class UserInteractorTest : SysuiTestCase() { @Test fun `executeAction - guest mode`() = - runBlocking(IMMEDIATE) { + testScope.runTest { val userInfos = createUserInfos(count = 2, includeGuest = false) userRepository.setUserInfos(userInfos) userRepository.setSelectedUserInfo(userInfos[0]) @@ -546,25 +518,24 @@ class UserInteractorTest : SysuiTestCase() { val guestUserInfo = createUserInfo(id = 1337, name = "guest", isGuest = true) whenever(manager.createGuest(any())).thenReturn(guestUserInfo) val dialogRequests = mutableListOf<ShowDialogRequestModel?>() - val showDialogsJob = - underTest.dialogShowRequests - .onEach { - dialogRequests.add(it) - if (it != null) { - underTest.onDialogShown() - } + backgroundScope.launch { + underTest.dialogShowRequests.collect { + dialogRequests.add(it) + if (it != null) { + underTest.onDialogShown() } - .launchIn(this) - val dismissDialogsJob = - underTest.dialogDismissRequests - .onEach { - if (it != null) { - underTest.onDialogDismissed() - } + } + } + backgroundScope.launch { + underTest.dialogDismissRequests.collect { + if (it != null) { + underTest.onDialogDismissed() } - .launchIn(this) + } + } underTest.executeAction(UserActionModel.ENTER_GUEST_MODE) + runCurrent() verify(uiEventLogger, times(1)) .log(MultiUserActionsEvent.CREATE_GUEST_FROM_USER_SWITCHER) @@ -573,85 +544,79 @@ class UserInteractorTest : SysuiTestCase() { ShowDialogRequestModel.ShowUserCreationDialog(isGuest = true), ) verify(activityManager).switchUser(guestUserInfo.id) - - showDialogsJob.cancel() - dismissDialogsJob.cancel() } @Test fun `selectUser - already selected guest re-selected - exit guest dialog`() = - runBlocking(IMMEDIATE) { + testScope.runTest { val userInfos = createUserInfos(count = 2, includeGuest = true) val guestUserInfo = userInfos[1] assertThat(guestUserInfo.isGuest).isTrue() userRepository.setUserInfos(userInfos) userRepository.setSelectedUserInfo(guestUserInfo) userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) - var dialogRequest: ShowDialogRequestModel? = null - val job = underTest.dialogShowRequests.onEach { dialogRequest = it }.launchIn(this) + val dialogRequest = collectLastValue(underTest.dialogShowRequests) underTest.selectUser( newlySelectedUserId = guestUserInfo.id, dialogShower = dialogShower, ) - assertThat(dialogRequest) + assertThat(dialogRequest()) .isInstanceOf(ShowDialogRequestModel.ShowExitGuestDialog::class.java) verify(dialogShower, never()).dismiss() - job.cancel() } @Test fun `selectUser - currently guest non-guest selected - exit guest dialog`() = - runBlocking(IMMEDIATE) { + testScope.runTest { val userInfos = createUserInfos(count = 2, includeGuest = true) val guestUserInfo = userInfos[1] assertThat(guestUserInfo.isGuest).isTrue() userRepository.setUserInfos(userInfos) userRepository.setSelectedUserInfo(guestUserInfo) userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) - var dialogRequest: ShowDialogRequestModel? = null - val job = underTest.dialogShowRequests.onEach { dialogRequest = it }.launchIn(this) + val dialogRequest = collectLastValue(underTest.dialogShowRequests) underTest.selectUser(newlySelectedUserId = userInfos[0].id, dialogShower = dialogShower) - assertThat(dialogRequest) + assertThat(dialogRequest()) .isInstanceOf(ShowDialogRequestModel.ShowExitGuestDialog::class.java) verify(dialogShower, never()).dismiss() - job.cancel() } @Test fun `selectUser - not currently guest - switches users`() = - runBlocking(IMMEDIATE) { + testScope.runTest { val userInfos = createUserInfos(count = 2, includeGuest = false) userRepository.setUserInfos(userInfos) userRepository.setSelectedUserInfo(userInfos[0]) userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) - var dialogRequest: ShowDialogRequestModel? = null - val job = underTest.dialogShowRequests.onEach { dialogRequest = it }.launchIn(this) + val dialogRequest = collectLastValue(underTest.dialogShowRequests) underTest.selectUser(newlySelectedUserId = userInfos[1].id, dialogShower = dialogShower) - assertThat(dialogRequest).isNull() + assertThat(dialogRequest()).isNull() verify(activityManager).switchUser(userInfos[1].id) verify(dialogShower).dismiss() - job.cancel() } @Test fun `Telephony call state changes - refreshes users`() = - runBlocking(IMMEDIATE) { + testScope.runTest { + runCurrent() + val refreshUsersCallCount = userRepository.refreshUsersCallCount telephonyRepository.setCallState(1) + runCurrent() assertThat(userRepository.refreshUsersCallCount).isEqualTo(refreshUsersCallCount + 1) } @Test fun `User switched broadcast`() = - runBlocking(IMMEDIATE) { + testScope.runTest { val userInfos = createUserInfos(count = 2, includeGuest = false) userRepository.setUserInfos(userInfos) userRepository.setSelectedUserInfo(userInfos[0]) @@ -660,9 +625,11 @@ class UserInteractorTest : SysuiTestCase() { val callback2: UserInteractor.UserCallback = mock() underTest.addCallback(callback1) underTest.addCallback(callback2) + runCurrent() val refreshUsersCallCount = userRepository.refreshUsersCallCount userRepository.setSelectedUserInfo(userInfos[1]) + runCurrent() fakeBroadcastDispatcher.registeredReceivers.forEach { it.onReceive( context, @@ -670,16 +637,17 @@ class UserInteractorTest : SysuiTestCase() { .putExtra(Intent.EXTRA_USER_HANDLE, userInfos[1].id), ) } + runCurrent() - verify(callback1).onUserStateChanged() - verify(callback2).onUserStateChanged() + verify(callback1, atLeastOnce()).onUserStateChanged() + verify(callback2, atLeastOnce()).onUserStateChanged() assertThat(userRepository.secondaryUserId).isEqualTo(userInfos[1].id) assertThat(userRepository.refreshUsersCallCount).isEqualTo(refreshUsersCallCount + 1) } @Test fun `User info changed broadcast`() = - runBlocking(IMMEDIATE) { + testScope.runTest { val userInfos = createUserInfos(count = 2, includeGuest = false) userRepository.setUserInfos(userInfos) userRepository.setSelectedUserInfo(userInfos[0]) @@ -692,12 +660,14 @@ class UserInteractorTest : SysuiTestCase() { ) } + runCurrent() + assertThat(userRepository.refreshUsersCallCount).isEqualTo(refreshUsersCallCount + 1) } @Test fun `System user unlocked broadcast - refresh users`() = - runBlocking(IMMEDIATE) { + testScope.runTest { val userInfos = createUserInfos(count = 2, includeGuest = false) userRepository.setUserInfos(userInfos) userRepository.setSelectedUserInfo(userInfos[0]) @@ -710,13 +680,14 @@ class UserInteractorTest : SysuiTestCase() { .putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_SYSTEM), ) } + runCurrent() assertThat(userRepository.refreshUsersCallCount).isEqualTo(refreshUsersCallCount + 1) } @Test fun `Non-system user unlocked broadcast - do not refresh users`() = - runBlocking(IMMEDIATE) { + testScope.runTest { val userInfos = createUserInfos(count = 2, includeGuest = false) userRepository.setUserInfos(userInfos) userRepository.setSelectedUserInfo(userInfos[0]) @@ -734,14 +705,14 @@ class UserInteractorTest : SysuiTestCase() { @Test fun userRecords() = - runBlocking(IMMEDIATE) { + testScope.runTest { val userInfos = createUserInfos(count = 3, includeGuest = false) userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) userRepository.setUserInfos(userInfos) userRepository.setSelectedUserInfo(userInfos[0]) keyguardRepository.setKeyguardShowing(false) - testCoroutineScope.advanceUntilIdle() + runCurrent() assertRecords( records = underTest.userRecords.value, @@ -760,7 +731,7 @@ class UserInteractorTest : SysuiTestCase() { @Test fun userRecordsFullScreen() = - runBlocking(IMMEDIATE) { + testScope.runTest { featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true) val userInfos = createUserInfos(count = 3, includeGuest = false) userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) @@ -768,7 +739,7 @@ class UserInteractorTest : SysuiTestCase() { userRepository.setSelectedUserInfo(userInfos[0]) keyguardRepository.setKeyguardShowing(false) - testCoroutineScope.advanceUntilIdle() + runCurrent() assertRecords( records = underTest.userRecords.value, @@ -787,7 +758,7 @@ class UserInteractorTest : SysuiTestCase() { @Test fun selectedUserRecord() = - runBlocking(IMMEDIATE) { + testScope.runTest { val userInfos = createUserInfos(count = 3, includeGuest = true) userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) userRepository.setUserInfos(userInfos) @@ -805,64 +776,54 @@ class UserInteractorTest : SysuiTestCase() { @Test fun `users - secondary user - guest user can be switched to`() = - runBlocking(IMMEDIATE) { + testScope.runTest { val userInfos = createUserInfos(count = 3, includeGuest = true) userRepository.setUserInfos(userInfos) userRepository.setSelectedUserInfo(userInfos[1]) userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) - var res: List<UserModel>? = null - val job = underTest.users.onEach { res = it }.launchIn(this) - assertThat(res?.size == 3).isTrue() - assertThat(res?.find { it.isGuest }).isNotNull() - job.cancel() + val res = collectLastValue(underTest.users) + assertThat(res()?.size == 3).isTrue() + assertThat(res()?.find { it.isGuest }).isNotNull() } @Test fun `users - secondary user - no guest action`() = - runBlocking(IMMEDIATE) { + testScope.runTest { val userInfos = createUserInfos(count = 3, includeGuest = true) userRepository.setUserInfos(userInfos) userRepository.setSelectedUserInfo(userInfos[1]) userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) - var res: List<UserActionModel>? = null - val job = underTest.actions.onEach { res = it }.launchIn(this) - assertThat(res?.find { it == UserActionModel.ENTER_GUEST_MODE }).isNull() - job.cancel() + val res = collectLastValue(underTest.actions) + assertThat(res()?.find { it == UserActionModel.ENTER_GUEST_MODE }).isNull() } @Test fun `users - secondary user - no guest user record`() = - runBlocking(IMMEDIATE) { + testScope.runTest { val userInfos = createUserInfos(count = 3, includeGuest = true) userRepository.setUserInfos(userInfos) userRepository.setSelectedUserInfo(userInfos[1]) userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) - var res: List<UserRecord>? = null - val job = underTest.userRecords.onEach { res = it }.launchIn(this) - assertThat(res?.find { it.isGuest }).isNull() - job.cancel() + assertThat(underTest.userRecords.value.find { it.isGuest }).isNull() } @Test fun `show user switcher - full screen disabled - shows dialog switcher`() = - runBlocking(IMMEDIATE) { - var dialogRequest: ShowDialogRequestModel? = null + testScope.runTest { val expandable = mock<Expandable>() underTest.showUserSwitcher(context, expandable) - val job = underTest.dialogShowRequests.onEach { dialogRequest = it }.launchIn(this) + val dialogRequest = collectLastValue(underTest.dialogShowRequests) // Dialog is shown. - assertThat(dialogRequest) + assertThat(dialogRequest()) .isEqualTo(ShowDialogRequestModel.ShowUserSwitcherDialog(expandable)) underTest.onDialogShown() - assertThat(dialogRequest).isNull() - - job.cancel() + assertThat(dialogRequest()).isNull() } @Test @@ -893,8 +854,8 @@ class UserInteractorTest : SysuiTestCase() { @Test fun `users - secondary user - managed profile is not included`() = - runBlocking(IMMEDIATE) { - var userInfos = createUserInfos(count = 3, includeGuest = false).toMutableList() + testScope.runTest { + val userInfos = createUserInfos(count = 3, includeGuest = false).toMutableList() userInfos.add( UserInfo( 50, @@ -907,23 +868,19 @@ class UserInteractorTest : SysuiTestCase() { userRepository.setSelectedUserInfo(userInfos[1]) userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) - var res: List<UserModel>? = null - val job = underTest.users.onEach { res = it }.launchIn(this) - assertThat(res?.size == 3).isTrue() - job.cancel() + val res = collectLastValue(underTest.users) + assertThat(res()?.size == 3).isTrue() } @Test fun `current user is not primary and user switcher is disabled`() = - runBlocking(IMMEDIATE) { + testScope.runTest { val userInfos = createUserInfos(count = 2, includeGuest = false) userRepository.setUserInfos(userInfos) userRepository.setSelectedUserInfo(userInfos[1]) userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = false)) - var selectedUser: UserModel? = null - val job = underTest.selectedUser.onEach { selectedUser = it }.launchIn(this) - assertThat(selectedUser).isNotNull() - job.cancel() + val selectedUser = collectLastValue(underTest.selectedUser) + assertThat(selectedUser()).isNotNull() } private fun assertUsers( @@ -1061,7 +1018,6 @@ class UserInteractorTest : SysuiTestCase() { } companion object { - private val IMMEDIATE = Dispatchers.Main.immediate private val ICON = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888) private val GUEST_ICON: Drawable = mock() private const val SUPERVISED_USER_CREATION_APP_PACKAGE = "supervisedUserCreation" |