1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 */ 17 18 package com.android.systemui.user.domain.interactor 19 20 import android.app.ActivityManager 21 import android.app.admin.DevicePolicyManager 22 import android.content.Context 23 import android.content.Intent 24 import android.content.pm.UserInfo 25 import android.graphics.Bitmap 26 import android.graphics.drawable.Drawable 27 import android.os.Process 28 import android.os.UserHandle 29 import android.os.UserManager 30 import android.provider.Settings 31 import androidx.test.filters.SmallTest 32 import com.android.internal.logging.UiEventLogger 33 import com.android.keyguard.KeyguardUpdateMonitor 34 import com.android.keyguard.KeyguardUpdateMonitorCallback 35 import com.android.systemui.GuestResetOrExitSessionReceiver 36 import com.android.systemui.GuestResumeSessionReceiver 37 import com.android.systemui.R 38 import com.android.systemui.SysuiTestCase 39 import com.android.systemui.animation.Expandable 40 import com.android.systemui.common.shared.model.Text 41 import com.android.systemui.coroutines.collectLastValue 42 import com.android.systemui.flags.FakeFeatureFlags 43 import com.android.systemui.flags.Flags 44 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository 45 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory 46 import com.android.systemui.plugins.ActivityStarter 47 import com.android.systemui.qs.user.UserSwitchDialogController 48 import com.android.systemui.statusbar.policy.DeviceProvisionedController 49 import com.android.systemui.telephony.data.repository.FakeTelephonyRepository 50 import com.android.systemui.telephony.domain.interactor.TelephonyInteractor 51 import com.android.systemui.user.data.model.UserSwitcherSettingsModel 52 import com.android.systemui.user.data.repository.FakeUserRepository 53 import com.android.systemui.user.data.source.UserRecord 54 import com.android.systemui.user.domain.model.ShowDialogRequestModel 55 import com.android.systemui.user.shared.model.UserActionModel 56 import com.android.systemui.user.shared.model.UserModel 57 import com.android.systemui.user.utils.MultiUserActionsEvent 58 import com.android.systemui.util.mockito.any 59 import com.android.systemui.util.mockito.eq 60 import com.android.systemui.util.mockito.kotlinArgumentCaptor 61 import com.android.systemui.util.mockito.mock 62 import com.android.systemui.util.mockito.whenever 63 import com.google.common.truth.Truth.assertThat 64 import junit.framework.Assert.assertNotNull 65 import kotlinx.coroutines.ExperimentalCoroutinesApi 66 import kotlinx.coroutines.launch 67 import kotlinx.coroutines.runBlocking 68 import kotlinx.coroutines.test.StandardTestDispatcher 69 import kotlinx.coroutines.test.TestDispatcher 70 import kotlinx.coroutines.test.TestScope 71 import kotlinx.coroutines.test.runCurrent 72 import kotlinx.coroutines.test.runTest 73 import org.junit.Before 74 import org.junit.Test 75 import org.junit.runner.RunWith 76 import org.junit.runners.JUnit4 77 import org.mockito.ArgumentCaptor 78 import org.mockito.ArgumentMatchers.anyBoolean 79 import org.mockito.ArgumentMatchers.anyInt 80 import org.mockito.Mock 81 import org.mockito.Mockito.atLeastOnce 82 import org.mockito.Mockito.never 83 import org.mockito.Mockito.spy 84 import org.mockito.Mockito.times 85 import org.mockito.Mockito.verify 86 import org.mockito.MockitoAnnotations 87 88 @OptIn(ExperimentalCoroutinesApi::class) 89 @SmallTest 90 @RunWith(JUnit4::class) 91 class UserInteractorTest : SysuiTestCase() { 92 93 @Mock private lateinit var activityStarter: ActivityStarter 94 @Mock private lateinit var manager: UserManager 95 @Mock private lateinit var headlessSystemUserMode: HeadlessSystemUserMode 96 @Mock private lateinit var activityManager: ActivityManager 97 @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController 98 @Mock private lateinit var devicePolicyManager: DevicePolicyManager 99 @Mock private lateinit var uiEventLogger: UiEventLogger 100 @Mock private lateinit var dialogShower: UserSwitchDialogController.DialogShower 101 @Mock private lateinit var resumeSessionReceiver: GuestResumeSessionReceiver 102 @Mock private lateinit var resetOrExitSessionReceiver: GuestResetOrExitSessionReceiver 103 @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor 104 105 private lateinit var underTest: UserInteractor 106 107 private lateinit var spyContext: Context 108 private lateinit var testScope: TestScope 109 private lateinit var userRepository: FakeUserRepository 110 private lateinit var keyguardReply: KeyguardInteractorFactory.WithDependencies 111 private lateinit var keyguardRepository: FakeKeyguardRepository 112 private lateinit var telephonyRepository: FakeTelephonyRepository 113 private lateinit var testDispatcher: TestDispatcher 114 private lateinit var featureFlags: FakeFeatureFlags 115 private lateinit var refreshUsersScheduler: RefreshUsersScheduler 116 117 @Before 118 fun setUp() { 119 MockitoAnnotations.initMocks(this) 120 whenever(manager.getUserIcon(anyInt())).thenReturn(ICON) 121 whenever(manager.canAddMoreUsers(any())).thenReturn(true) 122 123 overrideResource(R.drawable.ic_account_circle, GUEST_ICON) 124 overrideResource(R.dimen.max_avatar_size, 10) 125 overrideResource( 126 com.android.internal.R.string.config_supervisedUserCreationPackage, 127 SUPERVISED_USER_CREATION_APP_PACKAGE, 128 ) 129 130 featureFlags = 131 FakeFeatureFlags().apply { 132 set(Flags.FULL_SCREEN_USER_SWITCHER, false) 133 set(Flags.FACE_AUTH_REFACTOR, true) 134 } 135 spyContext = spy(context) 136 keyguardReply = KeyguardInteractorFactory.create(featureFlags = featureFlags) 137 keyguardRepository = keyguardReply.repository 138 userRepository = FakeUserRepository() 139 telephonyRepository = FakeTelephonyRepository() 140 testDispatcher = StandardTestDispatcher() 141 testScope = TestScope(testDispatcher) 142 refreshUsersScheduler = 143 RefreshUsersScheduler( 144 applicationScope = testScope.backgroundScope, 145 mainDispatcher = testDispatcher, 146 repository = userRepository, 147 ) 148 } 149 150 @Test 151 fun createUserInteractor_processUser_noSecondaryService() { 152 createUserInteractor() 153 verify(spyContext, never()).startServiceAsUser(any(), any()) 154 } 155 156 @Test 157 fun createUserInteractor_nonProcessUser_startsSecondaryService() { 158 val userId = Process.myUserHandle().identifier + 1 159 whenever(manager.aliveUsers).thenReturn(listOf(createUserInfo(userId, "abc"))) 160 161 createUserInteractor(false /* startAsProcessUser */) 162 verify(spyContext).startServiceAsUser(any(), any()) 163 } 164 165 @Test 166 fun testKeyguardUpdateMonitor_onKeyguardGoingAway() { 167 createUserInteractor() 168 testScope.runTest { 169 val argumentCaptor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java) 170 verify(keyguardUpdateMonitor).registerCallback(argumentCaptor.capture()) 171 172 argumentCaptor.value.onKeyguardGoingAway() 173 174 val lastValue = collectLastValue(underTest.dialogDismissRequests) 175 assertNotNull(lastValue) 176 } 177 } 178 179 @Test 180 fun onRecordSelected_user() { 181 createUserInteractor() 182 testScope.runTest { 183 val userInfos = createUserInfos(count = 3, includeGuest = false) 184 userRepository.setUserInfos(userInfos) 185 userRepository.setSelectedUserInfo(userInfos[0]) 186 userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) 187 188 underTest.onRecordSelected(UserRecord(info = userInfos[1]), dialogShower) 189 190 verify(uiEventLogger, times(1)) 191 .log(MultiUserActionsEvent.SWITCH_TO_USER_FROM_USER_SWITCHER) 192 verify(dialogShower).dismiss() 193 verify(activityManager).switchUser(userInfos[1].id) 194 Unit 195 } 196 } 197 198 @Test 199 fun onRecordSelected_switchToGuestUser() { 200 createUserInteractor() 201 testScope.runTest { 202 val userInfos = createUserInfos(count = 3, includeGuest = true) 203 userRepository.setUserInfos(userInfos) 204 userRepository.setSelectedUserInfo(userInfos[0]) 205 userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) 206 207 underTest.onRecordSelected(UserRecord(info = userInfos.last())) 208 209 verify(uiEventLogger, times(1)) 210 .log(MultiUserActionsEvent.SWITCH_TO_GUEST_FROM_USER_SWITCHER) 211 verify(activityManager).switchUser(userInfos.last().id) 212 Unit 213 } 214 } 215 216 @Test 217 fun onRecordSelected_switchToRestrictedUser() { 218 createUserInteractor() 219 testScope.runTest { 220 var userInfos = createUserInfos(count = 2, includeGuest = false).toMutableList() 221 userInfos.add( 222 UserInfo( 223 60, 224 "Restricted user", 225 /* iconPath= */ "", 226 /* flags= */ UserInfo.FLAG_FULL, 227 UserManager.USER_TYPE_FULL_RESTRICTED, 228 ) 229 ) 230 userRepository.setUserInfos(userInfos) 231 userRepository.setSelectedUserInfo(userInfos[0]) 232 userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) 233 234 underTest.onRecordSelected(UserRecord(info = userInfos.last())) 235 236 verify(uiEventLogger, times(1)) 237 .log(MultiUserActionsEvent.SWITCH_TO_RESTRICTED_USER_FROM_USER_SWITCHER) 238 verify(activityManager).switchUser(userInfos.last().id) 239 Unit 240 } 241 } 242 243 @Test 244 fun onRecordSelected_enterGuestMode() { 245 createUserInteractor() 246 testScope.runTest { 247 val userInfos = createUserInfos(count = 3, includeGuest = false) 248 userRepository.setUserInfos(userInfos) 249 userRepository.setSelectedUserInfo(userInfos[0]) 250 userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) 251 val guestUserInfo = createUserInfo(id = 1337, name = "guest", isGuest = true) 252 whenever(manager.createGuest(any())).thenReturn(guestUserInfo) 253 254 underTest.onRecordSelected(UserRecord(isGuest = true), dialogShower) 255 runCurrent() 256 257 verify(uiEventLogger, times(1)) 258 .log(MultiUserActionsEvent.CREATE_GUEST_FROM_USER_SWITCHER) 259 verify(dialogShower).dismiss() 260 verify(manager).createGuest(any()) 261 Unit 262 } 263 } 264 265 @Test 266 fun onRecordSelected_action() { 267 createUserInteractor() 268 testScope.runTest { 269 val userInfos = createUserInfos(count = 3, includeGuest = true) 270 userRepository.setUserInfos(userInfos) 271 userRepository.setSelectedUserInfo(userInfos[0]) 272 userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) 273 274 underTest.onRecordSelected(UserRecord(isAddSupervisedUser = true), dialogShower) 275 276 verify(uiEventLogger, times(1)) 277 .log(MultiUserActionsEvent.CREATE_RESTRICTED_USER_FROM_USER_SWITCHER) 278 verify(dialogShower, never()).dismiss() 279 verify(activityStarter).startActivity(any(), anyBoolean()) 280 } 281 } 282 283 @Test 284 fun users_switcherEnabled() { 285 createUserInteractor() 286 testScope.runTest { 287 val userInfos = createUserInfos(count = 3, includeGuest = true) 288 userRepository.setUserInfos(userInfos) 289 userRepository.setSelectedUserInfo(userInfos[0]) 290 userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) 291 292 val value = collectLastValue(underTest.users) 293 294 assertUsers(models = value(), count = 3, includeGuest = true) 295 } 296 } 297 298 @Test 299 fun users_switchesToSecondUser() { 300 createUserInteractor() 301 testScope.runTest { 302 val userInfos = createUserInfos(count = 2, includeGuest = false) 303 userRepository.setUserInfos(userInfos) 304 userRepository.setSelectedUserInfo(userInfos[0]) 305 userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) 306 307 val value = collectLastValue(underTest.users) 308 userRepository.setSelectedUserInfo(userInfos[1]) 309 310 assertUsers(models = value(), count = 2, selectedIndex = 1) 311 } 312 } 313 314 @Test 315 fun users_switcherNotEnabled() { 316 createUserInteractor() 317 testScope.runTest { 318 val userInfos = createUserInfos(count = 2, includeGuest = false) 319 userRepository.setUserInfos(userInfos) 320 userRepository.setSelectedUserInfo(userInfos[0]) 321 userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = false)) 322 323 val value = collectLastValue(underTest.users) 324 assertUsers(models = value(), count = 1) 325 } 326 } 327 328 @Test 329 fun selectedUser() { 330 createUserInteractor() 331 testScope.runTest { 332 val userInfos = createUserInfos(count = 2, includeGuest = false) 333 userRepository.setUserInfos(userInfos) 334 userRepository.setSelectedUserInfo(userInfos[0]) 335 userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) 336 337 val value = collectLastValue(underTest.selectedUser) 338 assertUser(value(), id = 0, isSelected = true) 339 340 userRepository.setSelectedUserInfo(userInfos[1]) 341 assertUser(value(), id = 1, isSelected = true) 342 } 343 } 344 345 @Test 346 fun actions_deviceUnlocked() { 347 createUserInteractor() 348 testScope.runTest { 349 val userInfos = createUserInfos(count = 2, includeGuest = false) 350 351 userRepository.setUserInfos(userInfos) 352 userRepository.setSelectedUserInfo(userInfos[0]) 353 userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) 354 keyguardRepository.setKeyguardShowing(false) 355 val value = collectLastValue(underTest.actions) 356 357 runCurrent() 358 359 assertThat(value()) 360 .isEqualTo( 361 listOf( 362 UserActionModel.ENTER_GUEST_MODE, 363 UserActionModel.ADD_USER, 364 UserActionModel.ADD_SUPERVISED_USER, 365 UserActionModel.NAVIGATE_TO_USER_MANAGEMENT, 366 ) 367 ) 368 } 369 } 370 371 @Test 372 fun actions_deviceUnlocked_fullScreen() { 373 createUserInteractor() 374 testScope.runTest { 375 featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true) 376 val userInfos = createUserInfos(count = 2, includeGuest = false) 377 378 userRepository.setUserInfos(userInfos) 379 userRepository.setSelectedUserInfo(userInfos[0]) 380 userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) 381 keyguardRepository.setKeyguardShowing(false) 382 val value = collectLastValue(underTest.actions) 383 384 assertThat(value()) 385 .isEqualTo( 386 listOf( 387 UserActionModel.ADD_USER, 388 UserActionModel.ADD_SUPERVISED_USER, 389 UserActionModel.ENTER_GUEST_MODE, 390 UserActionModel.NAVIGATE_TO_USER_MANAGEMENT, 391 ) 392 ) 393 } 394 } 395 396 @Test 397 fun actions_deviceUnlockedUserNotPrimary_emptyList() { 398 createUserInteractor() 399 testScope.runTest { 400 val userInfos = createUserInfos(count = 2, includeGuest = false) 401 userRepository.setUserInfos(userInfos) 402 userRepository.setSelectedUserInfo(userInfos[1]) 403 userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) 404 keyguardRepository.setKeyguardShowing(false) 405 val value = collectLastValue(underTest.actions) 406 407 assertThat(value()).isEqualTo(emptyList<UserActionModel>()) 408 } 409 } 410 411 @Test 412 fun actions_deviceUnlockedUserIsGuest_emptyList() { 413 createUserInteractor() 414 testScope.runTest { 415 val userInfos = createUserInfos(count = 2, includeGuest = true) 416 assertThat(userInfos[1].isGuest).isTrue() 417 userRepository.setUserInfos(userInfos) 418 userRepository.setSelectedUserInfo(userInfos[1]) 419 userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) 420 keyguardRepository.setKeyguardShowing(false) 421 val value = collectLastValue(underTest.actions) 422 423 assertThat(value()).isEqualTo(emptyList<UserActionModel>()) 424 } 425 } 426 427 @Test 428 fun actions_deviceLockedAddFromLockscreenSet_fullList() { 429 createUserInteractor() 430 testScope.runTest { 431 val userInfos = createUserInfos(count = 2, includeGuest = false) 432 userRepository.setUserInfos(userInfos) 433 userRepository.setSelectedUserInfo(userInfos[0]) 434 userRepository.setSettings( 435 UserSwitcherSettingsModel( 436 isUserSwitcherEnabled = true, 437 isAddUsersFromLockscreen = true, 438 ) 439 ) 440 keyguardRepository.setKeyguardShowing(false) 441 val value = collectLastValue(underTest.actions) 442 443 assertThat(value()) 444 .isEqualTo( 445 listOf( 446 UserActionModel.ENTER_GUEST_MODE, 447 UserActionModel.ADD_USER, 448 UserActionModel.ADD_SUPERVISED_USER, 449 UserActionModel.NAVIGATE_TO_USER_MANAGEMENT, 450 ) 451 ) 452 } 453 } 454 455 @Test 456 fun actions_deviceLockedAddFromLockscreenSet_fullList_fullScreen() { 457 createUserInteractor() 458 testScope.runTest { 459 featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true) 460 val userInfos = createUserInfos(count = 2, includeGuest = false) 461 userRepository.setUserInfos(userInfos) 462 userRepository.setSelectedUserInfo(userInfos[0]) 463 userRepository.setSettings( 464 UserSwitcherSettingsModel( 465 isUserSwitcherEnabled = true, 466 isAddUsersFromLockscreen = true, 467 ) 468 ) 469 keyguardRepository.setKeyguardShowing(false) 470 val value = collectLastValue(underTest.actions) 471 472 assertThat(value()) 473 .isEqualTo( 474 listOf( 475 UserActionModel.ADD_USER, 476 UserActionModel.ADD_SUPERVISED_USER, 477 UserActionModel.ENTER_GUEST_MODE, 478 UserActionModel.NAVIGATE_TO_USER_MANAGEMENT, 479 ) 480 ) 481 } 482 } 483 484 @Test 485 fun actions_deviceLocked_onlymanageUserIsShown() { 486 createUserInteractor() 487 testScope.runTest { 488 val userInfos = createUserInfos(count = 2, includeGuest = false) 489 userRepository.setUserInfos(userInfos) 490 userRepository.setSelectedUserInfo(userInfos[0]) 491 userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) 492 keyguardRepository.setKeyguardShowing(true) 493 val value = collectLastValue(underTest.actions) 494 495 assertThat(value()).isEqualTo(listOf(UserActionModel.NAVIGATE_TO_USER_MANAGEMENT)) 496 } 497 } 498 499 @Test 500 fun executeAction_addUser_dismissesDialogAndStartsActivity() { 501 createUserInteractor() 502 testScope.runTest { 503 val userInfos = createUserInfos(count = 2, includeGuest = false) 504 userRepository.setUserInfos(userInfos) 505 userRepository.setSelectedUserInfo(userInfos[0]) 506 keyguardRepository.setKeyguardShowing(false) 507 508 underTest.executeAction(UserActionModel.ADD_USER) 509 verify(uiEventLogger, times(1)) 510 .log(MultiUserActionsEvent.CREATE_USER_FROM_USER_SWITCHER) 511 underTest.onDialogShown() 512 } 513 } 514 515 @Test 516 fun executeAction_addSupervisedUser_dismissesDialogAndStartsActivity() { 517 createUserInteractor() 518 testScope.runTest { 519 underTest.executeAction(UserActionModel.ADD_SUPERVISED_USER) 520 521 verify(uiEventLogger, times(1)) 522 .log(MultiUserActionsEvent.CREATE_RESTRICTED_USER_FROM_USER_SWITCHER) 523 val intentCaptor = kotlinArgumentCaptor<Intent>() 524 verify(activityStarter).startActivity(intentCaptor.capture(), eq(true)) 525 assertThat(intentCaptor.value.action) 526 .isEqualTo(UserManager.ACTION_CREATE_SUPERVISED_USER) 527 assertThat(intentCaptor.value.`package`).isEqualTo(SUPERVISED_USER_CREATION_APP_PACKAGE) 528 } 529 } 530 531 @Test 532 fun executeAction_navigateToManageUsers() { 533 createUserInteractor() 534 testScope.runTest { 535 underTest.executeAction(UserActionModel.NAVIGATE_TO_USER_MANAGEMENT) 536 537 val intentCaptor = kotlinArgumentCaptor<Intent>() 538 verify(activityStarter).startActivity(intentCaptor.capture(), eq(true)) 539 assertThat(intentCaptor.value.action).isEqualTo(Settings.ACTION_USER_SETTINGS) 540 } 541 } 542 543 @Test 544 fun executeAction_guestMode() { 545 createUserInteractor() 546 testScope.runTest { 547 val userInfos = createUserInfos(count = 2, includeGuest = false) 548 userRepository.setUserInfos(userInfos) 549 userRepository.setSelectedUserInfo(userInfos[0]) 550 userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) 551 val guestUserInfo = createUserInfo(id = 1337, name = "guest", isGuest = true) 552 whenever(manager.createGuest(any())).thenReturn(guestUserInfo) 553 val dialogRequests = mutableListOf<ShowDialogRequestModel?>() 554 backgroundScope.launch { 555 underTest.dialogShowRequests.collect { 556 dialogRequests.add(it) 557 if (it != null) { 558 underTest.onDialogShown() 559 } 560 } 561 } 562 backgroundScope.launch { 563 underTest.dialogDismissRequests.collect { 564 if (it != null) { 565 underTest.onDialogDismissed() 566 } 567 } 568 } 569 570 underTest.executeAction(UserActionModel.ENTER_GUEST_MODE) 571 runCurrent() 572 573 verify(uiEventLogger, times(1)) 574 .log(MultiUserActionsEvent.CREATE_GUEST_FROM_USER_SWITCHER) 575 assertThat(dialogRequests) 576 .contains( 577 ShowDialogRequestModel.ShowUserCreationDialog(isGuest = true), 578 ) 579 verify(activityManager).switchUser(guestUserInfo.id) 580 } 581 } 582 583 @Test 584 fun selectUser_alreadySelectedGuestReSelected_exitGuestDialog() { 585 createUserInteractor() 586 testScope.runTest { 587 val userInfos = createUserInfos(count = 2, includeGuest = true) 588 val guestUserInfo = userInfos[1] 589 assertThat(guestUserInfo.isGuest).isTrue() 590 userRepository.setUserInfos(userInfos) 591 userRepository.setSelectedUserInfo(guestUserInfo) 592 userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) 593 val dialogRequest = collectLastValue(underTest.dialogShowRequests) 594 595 underTest.selectUser( 596 newlySelectedUserId = guestUserInfo.id, 597 dialogShower = dialogShower, 598 ) 599 600 assertThat(dialogRequest()) 601 .isInstanceOf(ShowDialogRequestModel.ShowExitGuestDialog::class.java) 602 verify(dialogShower, never()).dismiss() 603 } 604 } 605 606 @Test 607 fun selectUser_currentlyGuestNonGuestSelected_exitGuestDialog() { 608 createUserInteractor() 609 testScope.runTest { 610 val userInfos = createUserInfos(count = 2, includeGuest = true) 611 val guestUserInfo = userInfos[1] 612 assertThat(guestUserInfo.isGuest).isTrue() 613 userRepository.setUserInfos(userInfos) 614 userRepository.setSelectedUserInfo(guestUserInfo) 615 userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) 616 val dialogRequest = collectLastValue(underTest.dialogShowRequests) 617 618 underTest.selectUser(newlySelectedUserId = userInfos[0].id, dialogShower = dialogShower) 619 620 assertThat(dialogRequest()) 621 .isInstanceOf(ShowDialogRequestModel.ShowExitGuestDialog::class.java) 622 verify(dialogShower, never()).dismiss() 623 } 624 } 625 626 @Test 627 fun selectUser_notCurrentlyGuest_switchesUsers() { 628 createUserInteractor() 629 testScope.runTest { 630 val userInfos = createUserInfos(count = 2, includeGuest = false) 631 userRepository.setUserInfos(userInfos) 632 userRepository.setSelectedUserInfo(userInfos[0]) 633 userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) 634 val dialogRequest = collectLastValue(underTest.dialogShowRequests) 635 636 underTest.selectUser(newlySelectedUserId = userInfos[1].id, dialogShower = dialogShower) 637 638 assertThat(dialogRequest()).isNull() 639 verify(activityManager).switchUser(userInfos[1].id) 640 verify(dialogShower).dismiss() 641 } 642 } 643 644 @Test 645 fun telephonyCallStateChanges_refreshesUsers() { 646 createUserInteractor() 647 testScope.runTest { 648 runCurrent() 649 650 val refreshUsersCallCount = userRepository.refreshUsersCallCount 651 652 telephonyRepository.setCallState(1) 653 runCurrent() 654 655 assertThat(userRepository.refreshUsersCallCount).isEqualTo(refreshUsersCallCount + 1) 656 } 657 } 658 659 @Test 660 fun userSwitchedBroadcast() { 661 testScope.runTest { 662 val userInfos = createUserInfos(count = 2, includeGuest = false) 663 whenever(manager.aliveUsers).thenReturn(userInfos) 664 createUserInteractor() 665 userRepository.setUserInfos(userInfos) 666 userRepository.setSelectedUserInfo(userInfos[0]) 667 userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) 668 val callback1: UserInteractor.UserCallback = mock() 669 val callback2: UserInteractor.UserCallback = mock() 670 underTest.addCallback(callback1) 671 underTest.addCallback(callback2) 672 runCurrent() 673 val refreshUsersCallCount = userRepository.refreshUsersCallCount 674 675 userRepository.setSelectedUserInfo(userInfos[1]) 676 runCurrent() 677 fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly( 678 spyContext, 679 Intent(Intent.ACTION_USER_SWITCHED) 680 .putExtra(Intent.EXTRA_USER_HANDLE, userInfos[1].id), 681 ) 682 runCurrent() 683 684 verify(callback1, atLeastOnce()).onUserStateChanged() 685 verify(callback2, atLeastOnce()).onUserStateChanged() 686 assertThat(userRepository.secondaryUserId).isEqualTo(userInfos[1].id) 687 assertThat(userRepository.refreshUsersCallCount).isEqualTo(refreshUsersCallCount + 1) 688 verify(spyContext).startServiceAsUser(any(), eq(UserHandle.of(userInfos[1].id))) 689 } 690 } 691 692 @Test 693 fun userInfoChangedBroadcast() { 694 createUserInteractor() 695 testScope.runTest { 696 val userInfos = createUserInfos(count = 2, includeGuest = false) 697 userRepository.setUserInfos(userInfos) 698 userRepository.setSelectedUserInfo(userInfos[0]) 699 runCurrent() 700 val refreshUsersCallCount = userRepository.refreshUsersCallCount 701 702 fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly( 703 spyContext, 704 Intent(Intent.ACTION_USER_INFO_CHANGED), 705 ) 706 707 runCurrent() 708 709 assertThat(userRepository.refreshUsersCallCount).isEqualTo(refreshUsersCallCount + 1) 710 } 711 } 712 713 @Test 714 fun systemUserUnlockedBroadcast_refreshUsers() { 715 createUserInteractor() 716 testScope.runTest { 717 val userInfos = createUserInfos(count = 2, includeGuest = false) 718 userRepository.setUserInfos(userInfos) 719 userRepository.setSelectedUserInfo(userInfos[0]) 720 runCurrent() 721 val refreshUsersCallCount = userRepository.refreshUsersCallCount 722 723 fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly( 724 spyContext, 725 Intent(Intent.ACTION_USER_UNLOCKED) 726 .putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_SYSTEM), 727 ) 728 runCurrent() 729 730 assertThat(userRepository.refreshUsersCallCount).isEqualTo(refreshUsersCallCount + 1) 731 } 732 } 733 734 @Test 735 fun nonSystemUserUnlockedBroadcast_doNotRefreshUsers() { 736 createUserInteractor() 737 testScope.runTest { 738 val userInfos = createUserInfos(count = 2, includeGuest = false) 739 userRepository.setUserInfos(userInfos) 740 userRepository.setSelectedUserInfo(userInfos[0]) 741 val refreshUsersCallCount = userRepository.refreshUsersCallCount 742 743 fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly( 744 spyContext, 745 Intent(Intent.ACTION_USER_UNLOCKED).putExtra(Intent.EXTRA_USER_HANDLE, 1337), 746 ) 747 748 assertThat(userRepository.refreshUsersCallCount).isEqualTo(refreshUsersCallCount) 749 } 750 } 751 752 @Test 753 fun userRecords() { 754 createUserInteractor() 755 testScope.runTest { 756 val userInfos = createUserInfos(count = 3, includeGuest = false) 757 userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) 758 userRepository.setUserInfos(userInfos) 759 userRepository.setSelectedUserInfo(userInfos[0]) 760 keyguardRepository.setKeyguardShowing(false) 761 762 runCurrent() 763 764 assertRecords( 765 records = underTest.userRecords.value, 766 userIds = listOf(0, 1, 2), 767 selectedUserIndex = 0, 768 includeGuest = false, 769 expectedActions = 770 listOf( 771 UserActionModel.ENTER_GUEST_MODE, 772 UserActionModel.ADD_USER, 773 UserActionModel.ADD_SUPERVISED_USER, 774 UserActionModel.NAVIGATE_TO_USER_MANAGEMENT, 775 ), 776 ) 777 } 778 } 779 780 @Test 781 fun userRecordsFullScreen() { 782 createUserInteractor() 783 testScope.runTest { 784 featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true) 785 val userInfos = createUserInfos(count = 3, includeGuest = false) 786 userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) 787 userRepository.setUserInfos(userInfos) 788 userRepository.setSelectedUserInfo(userInfos[0]) 789 keyguardRepository.setKeyguardShowing(false) 790 791 runCurrent() 792 793 assertRecords( 794 records = underTest.userRecords.value, 795 userIds = listOf(0, 1, 2), 796 selectedUserIndex = 0, 797 includeGuest = false, 798 expectedActions = 799 listOf( 800 UserActionModel.ADD_USER, 801 UserActionModel.ADD_SUPERVISED_USER, 802 UserActionModel.ENTER_GUEST_MODE, 803 UserActionModel.NAVIGATE_TO_USER_MANAGEMENT, 804 ), 805 ) 806 } 807 } 808 809 @Test 810 fun selectedUserRecord() { 811 createUserInteractor() 812 testScope.runTest { 813 val userInfos = createUserInfos(count = 3, includeGuest = true) 814 userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) 815 userRepository.setUserInfos(userInfos) 816 userRepository.setSelectedUserInfo(userInfos[0]) 817 keyguardRepository.setKeyguardShowing(false) 818 819 assertRecordForUser( 820 record = underTest.selectedUserRecord.value, 821 id = 0, 822 hasPicture = true, 823 isCurrent = true, 824 isSwitchToEnabled = true, 825 ) 826 } 827 } 828 829 @Test 830 fun users_secondaryUser_guestUserCanBeSwitchedTo() { 831 createUserInteractor() 832 testScope.runTest { 833 val userInfos = createUserInfos(count = 3, includeGuest = true) 834 userRepository.setUserInfos(userInfos) 835 userRepository.setSelectedUserInfo(userInfos[1]) 836 userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) 837 838 val res = collectLastValue(underTest.users) 839 assertThat(res()?.size == 3).isTrue() 840 assertThat(res()?.find { it.isGuest }).isNotNull() 841 } 842 } 843 844 @Test 845 fun users_secondaryUser_noGuestAction() { 846 createUserInteractor() 847 testScope.runTest { 848 val userInfos = createUserInfos(count = 3, includeGuest = true) 849 userRepository.setUserInfos(userInfos) 850 userRepository.setSelectedUserInfo(userInfos[1]) 851 userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) 852 853 val res = collectLastValue(underTest.actions) 854 assertThat(res()?.find { it == UserActionModel.ENTER_GUEST_MODE }).isNull() 855 } 856 } 857 858 @Test 859 fun users_secondaryUser_noGuestUserRecord() { 860 createUserInteractor() 861 testScope.runTest { 862 val userInfos = createUserInfos(count = 3, includeGuest = true) 863 userRepository.setUserInfos(userInfos) 864 userRepository.setSelectedUserInfo(userInfos[1]) 865 userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) 866 867 assertThat(underTest.userRecords.value.find { it.isGuest }).isNull() 868 } 869 } 870 871 @Test 872 fun showUserSwitcher_fullScreenDisabled_showsDialogSwitcher() { 873 createUserInteractor() 874 testScope.runTest { 875 val expandable = mock<Expandable>() 876 underTest.showUserSwitcher(expandable) 877 878 val dialogRequest = collectLastValue(underTest.dialogShowRequests) 879 880 // Dialog is shown. 881 assertThat(dialogRequest()) 882 .isEqualTo(ShowDialogRequestModel.ShowUserSwitcherDialog(expandable)) 883 884 underTest.onDialogShown() 885 assertThat(dialogRequest()).isNull() 886 } 887 } 888 889 @Test 890 fun showUserSwitcher_fullScreenEnabled_launchesFullScreenDialog() { 891 createUserInteractor() 892 testScope.runTest { 893 featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true) 894 895 val expandable = mock<Expandable>() 896 underTest.showUserSwitcher(expandable) 897 898 val dialogRequest = collectLastValue(underTest.dialogShowRequests) 899 900 // Dialog is shown. 901 assertThat(dialogRequest()) 902 .isEqualTo(ShowDialogRequestModel.ShowUserSwitcherFullscreenDialog(expandable)) 903 904 underTest.onDialogShown() 905 assertThat(dialogRequest()).isNull() 906 } 907 } 908 909 @Test 910 fun users_secondaryUser_managedProfileIsNotIncluded() { 911 createUserInteractor() 912 testScope.runTest { 913 val userInfos = createUserInfos(count = 3, includeGuest = false).toMutableList() 914 userInfos.add( 915 UserInfo( 916 50, 917 "Work Profile", 918 /* iconPath= */ "", 919 /* flags= */ UserInfo.FLAG_MANAGED_PROFILE 920 ) 921 ) 922 userRepository.setUserInfos(userInfos) 923 userRepository.setSelectedUserInfo(userInfos[1]) 924 userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) 925 926 val res = collectLastValue(underTest.users) 927 assertThat(res()?.size == 3).isTrue() 928 } 929 } 930 931 @Test 932 fun currentUserIsNotPrimaryAndUserSwitcherIsDisabled() { 933 createUserInteractor() 934 testScope.runTest { 935 val userInfos = createUserInfos(count = 2, includeGuest = false) 936 userRepository.setUserInfos(userInfos) 937 userRepository.setSelectedUserInfo(userInfos[1]) 938 userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = false)) 939 val selectedUser = collectLastValue(underTest.selectedUser) 940 assertThat(selectedUser()).isNotNull() 941 } 942 } 943 944 @Test 945 fun userRecords_isActionAndNoUsersUnlocked_actionIsDisabled() { 946 createUserInteractor() 947 testScope.runTest { 948 keyguardRepository.setKeyguardShowing(true) 949 whenever(manager.getUserSwitchability(any())) 950 .thenReturn(UserManager.SWITCHABILITY_STATUS_SYSTEM_USER_LOCKED) 951 val userInfos = createUserInfos(count = 3, includeGuest = false).toMutableList() 952 userRepository.setUserInfos(userInfos) 953 userRepository.setSelectedUserInfo(userInfos[1]) 954 userRepository.setSettings( 955 UserSwitcherSettingsModel( 956 isUserSwitcherEnabled = true, 957 isAddUsersFromLockscreen = true 958 ) 959 ) 960 961 runCurrent() 962 underTest.userRecords.value 963 .filter { it.info == null } 964 .forEach { action -> assertThat(action.isSwitchToEnabled).isFalse() } 965 } 966 } 967 968 @Test 969 fun userRecords_isActionAndNoUsersUnlocked_actionIsDisabled_HeadlessMode() { 970 createUserInteractor() 971 testScope.runTest { 972 keyguardRepository.setKeyguardShowing(true) 973 whenever(headlessSystemUserMode.isHeadlessSystemUserMode()).thenReturn(true) 974 whenever(manager.isUserUnlocked(anyInt())).thenReturn(false) 975 val userInfos = createUserInfos(count = 3, includeGuest = false).toMutableList() 976 userRepository.setUserInfos(userInfos) 977 userRepository.setSelectedUserInfo(userInfos[1]) 978 userRepository.setSettings( 979 UserSwitcherSettingsModel( 980 isUserSwitcherEnabled = true, 981 isAddUsersFromLockscreen = true 982 ) 983 ) 984 985 runCurrent() 986 underTest.userRecords.value 987 .filter { it.info == null } 988 .forEach { action -> assertThat(action.isSwitchToEnabled).isFalse() } 989 } 990 } 991 992 @Test 993 fun initWithNoAliveUsers() { 994 whenever(manager.aliveUsers).thenReturn(listOf()) 995 createUserInteractor() 996 verify(spyContext, never()).startServiceAsUser(any(), any()) 997 } 998 999 private fun assertUsers( 1000 models: List<UserModel>?, 1001 count: Int, 1002 selectedIndex: Int = 0, 1003 includeGuest: Boolean = false, 1004 ) { 1005 checkNotNull(models) 1006 assertThat(models.size).isEqualTo(count) 1007 models.forEachIndexed { index, model -> 1008 assertUser( 1009 model = model, 1010 id = index, 1011 isSelected = index == selectedIndex, 1012 isGuest = includeGuest && index == count - 1 1013 ) 1014 } 1015 } 1016 1017 private fun assertUser( 1018 model: UserModel?, 1019 id: Int, 1020 isSelected: Boolean = false, 1021 isGuest: Boolean = false, 1022 ) { 1023 checkNotNull(model) 1024 assertThat(model.id).isEqualTo(id) 1025 assertThat(model.name).isEqualTo(Text.Loaded(if (isGuest) "guest" else "user_$id")) 1026 assertThat(model.isSelected).isEqualTo(isSelected) 1027 assertThat(model.isSelectable).isTrue() 1028 assertThat(model.isGuest).isEqualTo(isGuest) 1029 } 1030 1031 private fun assertRecords( 1032 records: List<UserRecord>, 1033 userIds: List<Int>, 1034 selectedUserIndex: Int = 0, 1035 includeGuest: Boolean = false, 1036 expectedActions: List<UserActionModel> = emptyList(), 1037 ) { 1038 assertThat(records.size >= userIds.size).isTrue() 1039 userIds.indices.forEach { userIndex -> 1040 val record = records[userIndex] 1041 assertThat(record.info).isNotNull() 1042 val isGuest = includeGuest && userIndex == userIds.size - 1 1043 assertRecordForUser( 1044 record = record, 1045 id = userIds[userIndex], 1046 hasPicture = !isGuest, 1047 isCurrent = userIndex == selectedUserIndex, 1048 isGuest = isGuest, 1049 isSwitchToEnabled = true, 1050 ) 1051 } 1052 1053 assertThat(records.size - userIds.size).isEqualTo(expectedActions.size) 1054 (userIds.size until userIds.size + expectedActions.size).forEach { actionIndex -> 1055 val record = records[actionIndex] 1056 assertThat(record.info).isNull() 1057 assertRecordForAction( 1058 record = record, 1059 type = expectedActions[actionIndex - userIds.size], 1060 ) 1061 } 1062 } 1063 1064 private fun assertRecordForUser( 1065 record: UserRecord?, 1066 id: Int? = null, 1067 hasPicture: Boolean = false, 1068 isCurrent: Boolean = false, 1069 isGuest: Boolean = false, 1070 isSwitchToEnabled: Boolean = false, 1071 ) { 1072 checkNotNull(record) 1073 assertThat(record.info?.id).isEqualTo(id) 1074 assertThat(record.picture != null).isEqualTo(hasPicture) 1075 assertThat(record.isCurrent).isEqualTo(isCurrent) 1076 assertThat(record.isGuest).isEqualTo(isGuest) 1077 assertThat(record.isSwitchToEnabled).isEqualTo(isSwitchToEnabled) 1078 } 1079 1080 private fun assertRecordForAction( 1081 record: UserRecord, 1082 type: UserActionModel, 1083 ) { 1084 assertThat(record.isGuest).isEqualTo(type == UserActionModel.ENTER_GUEST_MODE) 1085 assertThat(record.isAddUser).isEqualTo(type == UserActionModel.ADD_USER) 1086 assertThat(record.isAddSupervisedUser) 1087 .isEqualTo(type == UserActionModel.ADD_SUPERVISED_USER) 1088 } 1089 1090 private fun createUserInteractor(startAsProcessUser: Boolean = true) { 1091 val processUserId = Process.myUserHandle().identifier 1092 val startUserId = if (startAsProcessUser) processUserId else (processUserId + 1) 1093 runBlocking { 1094 val userInfo = 1095 createUserInfo(id = startUserId, name = "user_$startUserId", isPrimary = true) 1096 userRepository.setUserInfos(listOf(userInfo)) 1097 userRepository.setSelectedUserInfo(userInfo) 1098 } 1099 underTest = 1100 UserInteractor( 1101 applicationContext = spyContext, 1102 repository = userRepository, 1103 activityStarter = activityStarter, 1104 keyguardInteractor = keyguardReply.keyguardInteractor, 1105 manager = manager, 1106 headlessSystemUserMode = headlessSystemUserMode, 1107 applicationScope = testScope.backgroundScope, 1108 telephonyInteractor = 1109 TelephonyInteractor( 1110 repository = telephonyRepository, 1111 ), 1112 broadcastDispatcher = fakeBroadcastDispatcher, 1113 keyguardUpdateMonitor = keyguardUpdateMonitor, 1114 backgroundDispatcher = testDispatcher, 1115 activityManager = activityManager, 1116 refreshUsersScheduler = refreshUsersScheduler, 1117 guestUserInteractor = 1118 GuestUserInteractor( 1119 applicationContext = spyContext, 1120 applicationScope = testScope.backgroundScope, 1121 mainDispatcher = testDispatcher, 1122 backgroundDispatcher = testDispatcher, 1123 manager = manager, 1124 repository = userRepository, 1125 deviceProvisionedController = deviceProvisionedController, 1126 devicePolicyManager = devicePolicyManager, 1127 refreshUsersScheduler = refreshUsersScheduler, 1128 uiEventLogger = uiEventLogger, 1129 resumeSessionReceiver = resumeSessionReceiver, 1130 resetOrExitSessionReceiver = resetOrExitSessionReceiver, 1131 ), 1132 uiEventLogger = uiEventLogger, 1133 featureFlags = featureFlags, 1134 ) 1135 } 1136 1137 private fun createUserInfos( 1138 count: Int, 1139 includeGuest: Boolean, 1140 ): List<UserInfo> { 1141 return (0 until count).map { index -> 1142 val isGuest = includeGuest && index == count - 1 1143 createUserInfo( 1144 id = index, 1145 name = 1146 if (isGuest) { 1147 "guest" 1148 } else { 1149 "user_$index" 1150 }, 1151 isPrimary = !isGuest && index == 0, 1152 isGuest = isGuest, 1153 ) 1154 } 1155 } 1156 1157 private fun createUserInfo( 1158 id: Int, 1159 name: String, 1160 isPrimary: Boolean = false, 1161 isGuest: Boolean = false, 1162 ): UserInfo { 1163 return UserInfo( 1164 id, 1165 name, 1166 /* iconPath= */ "", 1167 /* flags= */ if (isPrimary) { 1168 UserInfo.FLAG_PRIMARY or UserInfo.FLAG_ADMIN or UserInfo.FLAG_FULL 1169 } else { 1170 UserInfo.FLAG_FULL 1171 }, 1172 if (isGuest) { 1173 UserManager.USER_TYPE_FULL_GUEST 1174 } else { 1175 UserManager.USER_TYPE_FULL_SYSTEM 1176 }, 1177 ) 1178 } 1179 1180 companion object { 1181 private val ICON = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888) 1182 private val GUEST_ICON: Drawable = mock() 1183 private const val SUPERVISED_USER_CREATION_APP_PACKAGE = "supervisedUserCreation" 1184 } 1185 } 1186