Merge "Add userSwitching state to UserRepository" into tm-qpr-dev

This commit is contained in:
Chandru S
2023-01-31 20:04:49 +00:00
committed by Android (Google) Code Review
3 changed files with 89 additions and 0 deletions

View File

@@ -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() {

View File

@@ -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,
)
}

View File

@@ -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