diff options
3 files changed, 89 insertions, 0 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt index 8cb4deb4882c..e5ab47325229 100644 --- a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt @@ -17,8 +17,11 @@ package com.android.systemui.user.data.repository +import android.app.IActivityManager +import android.app.UserSwitchObserver import android.content.Context import android.content.pm.UserInfo +import android.os.IRemoteCallback import android.os.UserHandle import android.os.UserManager import android.provider.Settings @@ -30,6 +33,8 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.flags.FeatureFlags +import com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR import com.android.systemui.settings.UserTracker import com.android.systemui.user.data.model.UserSwitcherSettingsModel import com.android.systemui.util.settings.GlobalSettings @@ -68,6 +73,9 @@ interface UserRepository { /** [UserInfo] of the currently-selected user. */ val selectedUserInfo: Flow<UserInfo> + /** Whether user switching is currently in progress. */ + val userSwitchingInProgress: Flow<Boolean> + /** User ID of the last non-guest selected user. */ val lastSelectedNonGuestUserId: Int @@ -108,6 +116,8 @@ constructor( @Background private val backgroundDispatcher: CoroutineDispatcher, private val globalSettings: GlobalSettings, private val tracker: UserTracker, + private val activityManager: IActivityManager, + featureFlags: FeatureFlags, ) : UserRepository { private val _userSwitcherSettings = MutableStateFlow(runBlocking { getSettings() }) @@ -129,6 +139,10 @@ constructor( private var _isGuestUserResetting: Boolean = false override var isGuestUserResetting: Boolean = _isGuestUserResetting + private val _isUserSwitchingInProgress = MutableStateFlow(false) + override val userSwitchingInProgress: Flow<Boolean> + get() = _isUserSwitchingInProgress + override val isGuestUserCreationScheduled = AtomicBoolean() override val isStatusBarUserChipEnabled: Boolean = @@ -141,6 +155,9 @@ constructor( init { observeSelectedUser() observeUserSettings() + if (featureFlags.isEnabled(FACE_AUTH_REFACTOR)) { + observeUserSwitching() + } } override fun refreshUsers() { @@ -166,6 +183,28 @@ constructor( return _userSwitcherSettings.value.isSimpleUserSwitcher } + private fun observeUserSwitching() { + conflatedCallbackFlow { + val callback = + object : UserSwitchObserver() { + override fun onUserSwitching(newUserId: Int, reply: IRemoteCallback) { + trySendWithFailureLogging(true, TAG, "userSwitching started") + } + + override fun onUserSwitchComplete(newUserId: Int) { + trySendWithFailureLogging(false, TAG, "userSwitching completed") + } + } + activityManager.registerUserSwitchObserver(callback, TAG) + trySendWithFailureLogging(false, TAG, "initial value defaulting to false") + awaitClose { activityManager.unregisterUserSwitchObserver(callback) } + } + .onEach { _isUserSwitchingInProgress.value = it } + // TODO (b/262838215), Make this stateIn and initialize directly in field declaration + // once the flag is launched + .launchIn(applicationScope) + } + private fun observeSelectedUser() { conflatedCallbackFlow { fun send() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt index 034c618e55d4..ccf378a71abd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt @@ -17,12 +17,17 @@ package com.android.systemui.user.data.repository +import android.app.IActivityManager +import android.app.UserSwitchObserver import android.content.pm.UserInfo +import android.os.IRemoteCallback import android.os.UserHandle import android.os.UserManager import android.provider.Settings import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.flags.FakeFeatureFlags +import com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR import com.android.systemui.settings.FakeUserTracker import com.android.systemui.user.data.model.UserSwitcherSettingsModel import com.android.systemui.util.settings.FakeSettings @@ -39,7 +44,14 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 +import org.mockito.ArgumentCaptor +import org.mockito.Captor import org.mockito.Mock +import org.mockito.Mockito.any +import org.mockito.Mockito.anyString +import org.mockito.Mockito.mock +import org.mockito.Mockito.times +import org.mockito.Mockito.verify import org.mockito.Mockito.`when` as whenever import org.mockito.MockitoAnnotations @@ -48,6 +60,8 @@ import org.mockito.MockitoAnnotations class UserRepositoryImplTest : SysuiTestCase() { @Mock private lateinit var manager: UserManager + @Mock private lateinit var activityManager: IActivityManager + @Captor private lateinit var userSwitchObserver: ArgumentCaptor<UserSwitchObserver> private lateinit var underTest: UserRepositoryImpl @@ -214,6 +228,34 @@ class UserRepositoryImplTest : SysuiTestCase() { assertThat(selectedUserInfo?.id).isEqualTo(1) } + @Test + fun userSwitchingInProgress_registersOnlyOneUserSwitchObserver() = runSelfCancelingTest { + underTest = create(this) + + underTest.userSwitchingInProgress.launchIn(this) + underTest.userSwitchingInProgress.launchIn(this) + underTest.userSwitchingInProgress.launchIn(this) + + verify(activityManager, times(1)).registerUserSwitchObserver(any(), anyString()) + } + + @Test + fun userSwitchingInProgress_propagatesStateFromActivityManager() = runSelfCancelingTest { + underTest = create(this) + verify(activityManager) + .registerUserSwitchObserver(userSwitchObserver.capture(), anyString()) + + userSwitchObserver.value.onUserSwitching(0, mock(IRemoteCallback::class.java)) + + var mostRecentSwitchingValue = false + underTest.userSwitchingInProgress.onEach { mostRecentSwitchingValue = it }.launchIn(this) + + assertThat(mostRecentSwitchingValue).isTrue() + + userSwitchObserver.value.onUserSwitchComplete(0) + assertThat(mostRecentSwitchingValue).isFalse() + } + private fun createUserInfo( id: Int, isGuest: Boolean, @@ -280,6 +322,8 @@ class UserRepositoryImplTest : SysuiTestCase() { } private fun create(scope: CoroutineScope = TestCoroutineScope()): UserRepositoryImpl { + val featureFlags = FakeFeatureFlags() + featureFlags.set(FACE_AUTH_REFACTOR, true) return UserRepositoryImpl( appContext = context, manager = manager, @@ -288,6 +332,8 @@ class UserRepositoryImplTest : SysuiTestCase() { backgroundDispatcher = IMMEDIATE, globalSettings = globalSettings, tracker = tracker, + activityManager = activityManager, + featureFlags = featureFlags, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt index ea5a302ce05a..1a8e244bf54f 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt @@ -39,6 +39,10 @@ class FakeUserRepository : UserRepository { private val _selectedUserInfo = MutableStateFlow<UserInfo?>(null) override val selectedUserInfo: Flow<UserInfo> = _selectedUserInfo.filterNotNull() + private val _userSwitchingInProgress = MutableStateFlow(false) + override val userSwitchingInProgress: Flow<Boolean> + get() = _userSwitchingInProgress + override var lastSelectedNonGuestUserId: Int = UserHandle.USER_SYSTEM private var _isGuestUserAutoCreated: Boolean = false |