Merge "Add userSwitching state to UserRepository" into tm-qpr-dev am: 07e97aab5c

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20809913

Change-Id: I840e955726e87897fec63b0bcf1489bb18329267
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Chandru S
2023-01-31 20:59:36 +00:00
committed by Automerger Merge Worker
3 changed files with 89 additions and 0 deletions

View File

@@ -17,8 +17,11 @@
package com.android.systemui.user.data.repository package com.android.systemui.user.data.repository
import android.app.IActivityManager
import android.app.UserSwitchObserver
import android.content.Context import android.content.Context
import android.content.pm.UserInfo import android.content.pm.UserInfo
import android.os.IRemoteCallback
import android.os.UserHandle import android.os.UserHandle
import android.os.UserManager import android.os.UserManager
import android.provider.Settings 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.Application
import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main 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.settings.UserTracker
import com.android.systemui.user.data.model.UserSwitcherSettingsModel import com.android.systemui.user.data.model.UserSwitcherSettingsModel
import com.android.systemui.util.settings.GlobalSettings import com.android.systemui.util.settings.GlobalSettings
@@ -68,6 +73,9 @@ interface UserRepository {
/** [UserInfo] of the currently-selected user. */ /** [UserInfo] of the currently-selected user. */
val selectedUserInfo: Flow<UserInfo> val selectedUserInfo: Flow<UserInfo>
/** Whether user switching is currently in progress. */
val userSwitchingInProgress: Flow<Boolean>
/** User ID of the last non-guest selected user. */ /** User ID of the last non-guest selected user. */
val lastSelectedNonGuestUserId: Int val lastSelectedNonGuestUserId: Int
@@ -108,6 +116,8 @@ constructor(
@Background private val backgroundDispatcher: CoroutineDispatcher, @Background private val backgroundDispatcher: CoroutineDispatcher,
private val globalSettings: GlobalSettings, private val globalSettings: GlobalSettings,
private val tracker: UserTracker, private val tracker: UserTracker,
private val activityManager: IActivityManager,
featureFlags: FeatureFlags,
) : UserRepository { ) : UserRepository {
private val _userSwitcherSettings = MutableStateFlow(runBlocking { getSettings() }) private val _userSwitcherSettings = MutableStateFlow(runBlocking { getSettings() })
@@ -129,6 +139,10 @@ constructor(
private var _isGuestUserResetting: Boolean = false private var _isGuestUserResetting: Boolean = false
override var isGuestUserResetting: Boolean = _isGuestUserResetting override var isGuestUserResetting: Boolean = _isGuestUserResetting
private val _isUserSwitchingInProgress = MutableStateFlow(false)
override val userSwitchingInProgress: Flow<Boolean>
get() = _isUserSwitchingInProgress
override val isGuestUserCreationScheduled = AtomicBoolean() override val isGuestUserCreationScheduled = AtomicBoolean()
override val isStatusBarUserChipEnabled: Boolean = override val isStatusBarUserChipEnabled: Boolean =
@@ -141,6 +155,9 @@ constructor(
init { init {
observeSelectedUser() observeSelectedUser()
observeUserSettings() observeUserSettings()
if (featureFlags.isEnabled(FACE_AUTH_REFACTOR)) {
observeUserSwitching()
}
} }
override fun refreshUsers() { override fun refreshUsers() {
@@ -166,6 +183,28 @@ constructor(
return _userSwitcherSettings.value.isSimpleUserSwitcher 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() { private fun observeSelectedUser() {
conflatedCallbackFlow { conflatedCallbackFlow {
fun send() { fun send() {

View File

@@ -17,12 +17,17 @@
package com.android.systemui.user.data.repository package com.android.systemui.user.data.repository
import android.app.IActivityManager
import android.app.UserSwitchObserver
import android.content.pm.UserInfo import android.content.pm.UserInfo
import android.os.IRemoteCallback
import android.os.UserHandle import android.os.UserHandle
import android.os.UserManager import android.os.UserManager
import android.provider.Settings import android.provider.Settings
import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase 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.settings.FakeUserTracker
import com.android.systemui.user.data.model.UserSwitcherSettingsModel import com.android.systemui.user.data.model.UserSwitcherSettingsModel
import com.android.systemui.util.settings.FakeSettings import com.android.systemui.util.settings.FakeSettings
@@ -39,7 +44,14 @@ import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.junit.runners.JUnit4 import org.junit.runners.JUnit4
import org.mockito.ArgumentCaptor
import org.mockito.Captor
import org.mockito.Mock 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.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations import org.mockito.MockitoAnnotations
@@ -48,6 +60,8 @@ import org.mockito.MockitoAnnotations
class UserRepositoryImplTest : SysuiTestCase() { class UserRepositoryImplTest : SysuiTestCase() {
@Mock private lateinit var manager: UserManager @Mock private lateinit var manager: UserManager
@Mock private lateinit var activityManager: IActivityManager
@Captor private lateinit var userSwitchObserver: ArgumentCaptor<UserSwitchObserver>
private lateinit var underTest: UserRepositoryImpl private lateinit var underTest: UserRepositoryImpl
@@ -214,6 +228,34 @@ class UserRepositoryImplTest : SysuiTestCase() {
assertThat(selectedUserInfo?.id).isEqualTo(1) 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( private fun createUserInfo(
id: Int, id: Int,
isGuest: Boolean, isGuest: Boolean,
@@ -280,6 +322,8 @@ class UserRepositoryImplTest : SysuiTestCase() {
} }
private fun create(scope: CoroutineScope = TestCoroutineScope()): UserRepositoryImpl { private fun create(scope: CoroutineScope = TestCoroutineScope()): UserRepositoryImpl {
val featureFlags = FakeFeatureFlags()
featureFlags.set(FACE_AUTH_REFACTOR, true)
return UserRepositoryImpl( return UserRepositoryImpl(
appContext = context, appContext = context,
manager = manager, manager = manager,
@@ -288,6 +332,8 @@ class UserRepositoryImplTest : SysuiTestCase() {
backgroundDispatcher = IMMEDIATE, backgroundDispatcher = IMMEDIATE,
globalSettings = globalSettings, globalSettings = globalSettings,
tracker = tracker, tracker = tracker,
activityManager = activityManager,
featureFlags = featureFlags,
) )
} }

View File

@@ -39,6 +39,10 @@ class FakeUserRepository : UserRepository {
private val _selectedUserInfo = MutableStateFlow<UserInfo?>(null) private val _selectedUserInfo = MutableStateFlow<UserInfo?>(null)
override val selectedUserInfo: Flow<UserInfo> = _selectedUserInfo.filterNotNull() 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 override var lastSelectedNonGuestUserId: Int = UserHandle.USER_SYSTEM
private var _isGuestUserAutoCreated: Boolean = false private var _isGuestUserAutoCreated: Boolean = false