Loading packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt +39 −0 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading Loading @@ -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 Loading Loading @@ -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() }) Loading @@ -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 = Loading @@ -141,6 +155,9 @@ constructor( init { observeSelectedUser() observeUserSettings() if (featureFlags.isEnabled(FACE_AUTH_REFACTOR)) { observeUserSwitching() } } override fun refreshUsers() { Loading @@ -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() { Loading packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt +46 −0 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading Loading @@ -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, Loading Loading @@ -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, Loading @@ -288,6 +332,8 @@ class UserRepositoryImplTest : SysuiTestCase() { backgroundDispatcher = IMMEDIATE, globalSettings = globalSettings, tracker = tracker, activityManager = activityManager, featureFlags = featureFlags, ) } Loading packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt +4 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading
packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt +39 −0 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading Loading @@ -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 Loading Loading @@ -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() }) Loading @@ -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 = Loading @@ -141,6 +155,9 @@ constructor( init { observeSelectedUser() observeUserSettings() if (featureFlags.isEnabled(FACE_AUTH_REFACTOR)) { observeUserSwitching() } } override fun refreshUsers() { Loading @@ -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() { Loading
packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt +46 −0 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading Loading @@ -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, Loading Loading @@ -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, Loading @@ -288,6 +332,8 @@ class UserRepositoryImplTest : SysuiTestCase() { backgroundDispatcher = IMMEDIATE, globalSettings = globalSettings, tracker = tracker, activityManager = activityManager, featureFlags = featureFlags, ) } Loading
packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt +4 −0 Original line number Diff line number Diff line Loading @@ -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 Loading