summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/user/domain/interactor/UserLogoutInteractorTest.kt55
-rw-r--r--packages/SystemUI/res/values/config.xml5
-rw-r--r--packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt32
-rw-r--r--packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserLogoutInteractor.kt20
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt15
6 files changed, 122 insertions, 9 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt
index 6b371d74eacc..9b47eaddffd6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt
@@ -19,6 +19,7 @@ package com.android.systemui.user.data.repository
import android.app.admin.devicePolicyManager
import android.content.pm.UserInfo
+import android.internal.statusbar.fakeStatusBarService
import android.os.UserHandle
import android.os.UserManager
import android.provider.Settings
@@ -61,6 +62,7 @@ class UserRepositoryImplTest : SysuiTestCase() {
private val globalSettings = kosmos.fakeGlobalSettings
private val broadcastDispatcher = kosmos.broadcastDispatcher
private val devicePolicyManager = kosmos.devicePolicyManager
+ private val statusBarService = kosmos.fakeStatusBarService
@Mock private lateinit var manager: UserManager
@@ -323,6 +325,8 @@ class UserRepositoryImplTest : SysuiTestCase() {
tracker = tracker,
broadcastDispatcher = broadcastDispatcher,
devicePolicyManager = devicePolicyManager,
+ resources = context.resources,
+ statusBarService = statusBarService,
)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/user/domain/interactor/UserLogoutInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/user/domain/interactor/UserLogoutInteractorTest.kt
index 26439df45ba3..f70b42638cda 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/user/domain/interactor/UserLogoutInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/user/domain/interactor/UserLogoutInteractorTest.kt
@@ -49,35 +49,78 @@ class UserLogoutInteractorTest : SysuiTestCase() {
@Before
fun setUp() {
userRepository.setUserInfos(USER_INFOS)
- runBlocking { userRepository.setSelectedUserInfo(USER_INFOS[1]) }
+ runBlocking { userRepository.setSelectedUserInfo(USER_INFOS[2]) }
+ userRepository.setLogoutToSystemUserEnabled(false)
+ userRepository.setSecondaryUserLogoutEnabled(false)
}
@Test
- fun logOut_doesNothing_whenAdminDisabledSecondaryLogout() {
+ fun logOut_doesNothing_whenBothLogoutOptionsAreDisabled() {
testScope.runTest {
val isLogoutEnabled by collectLastValue(underTest.isLogoutEnabled)
- val lastLogoutCount = userRepository.logOutSecondaryUserCallCount
- userRepository.setSecondaryUserLogoutEnabled(false)
+ val secondaryUserLogoutCount = userRepository.logOutSecondaryUserCallCount
+ val logoutToSystemUserCount = userRepository.logOutToSystemUserCallCount
assertThat(isLogoutEnabled).isFalse()
underTest.logOut()
+ assertThat(userRepository.logOutSecondaryUserCallCount)
+ .isEqualTo(secondaryUserLogoutCount)
+ assertThat(userRepository.logOutToSystemUserCallCount)
+ .isEqualTo(logoutToSystemUserCount)
+ }
+ }
+
+ @Test
+ fun logOut_logsOutSecondaryUser_whenAdminEnabledSecondaryLogout() {
+ testScope.runTest {
+ val isLogoutEnabled by collectLastValue(underTest.isLogoutEnabled)
+ val lastLogoutCount = userRepository.logOutSecondaryUserCallCount
+ val logoutToSystemUserCount = userRepository.logOutToSystemUserCallCount
+ userRepository.setSecondaryUserLogoutEnabled(true)
+ assertThat(isLogoutEnabled).isTrue()
+ underTest.logOut()
+ assertThat(userRepository.logOutSecondaryUserCallCount).isEqualTo(lastLogoutCount + 1)
+ assertThat(userRepository.logOutToSystemUserCallCount)
+ .isEqualTo(logoutToSystemUserCount)
+ }
+ }
+
+ @Test
+ fun logOut_logsOutToSystemUser_whenLogoutToSystemUserIsEnabled() {
+ testScope.runTest {
+ val isLogoutEnabled by collectLastValue(underTest.isLogoutEnabled)
+ val lastLogoutCount = userRepository.logOutSecondaryUserCallCount
+ val logoutToSystemUserCount = userRepository.logOutToSystemUserCallCount
+ userRepository.setLogoutToSystemUserEnabled(true)
+ assertThat(isLogoutEnabled).isTrue()
+ underTest.logOut()
assertThat(userRepository.logOutSecondaryUserCallCount).isEqualTo(lastLogoutCount)
+ assertThat(userRepository.logOutToSystemUserCallCount)
+ .isEqualTo(logoutToSystemUserCount + 1)
}
}
@Test
- fun logOut_logsOut_whenAdminEnabledSecondaryLogout() {
+ fun logOut_secondaryUserTakesPrecedence() {
testScope.runTest {
val isLogoutEnabled by collectLastValue(underTest.isLogoutEnabled)
val lastLogoutCount = userRepository.logOutSecondaryUserCallCount
+ val logoutToSystemUserCount = userRepository.logOutToSystemUserCallCount
+ userRepository.setLogoutToSystemUserEnabled(true)
userRepository.setSecondaryUserLogoutEnabled(true)
assertThat(isLogoutEnabled).isTrue()
underTest.logOut()
assertThat(userRepository.logOutSecondaryUserCallCount).isEqualTo(lastLogoutCount + 1)
+ assertThat(userRepository.logOutToSystemUserCallCount)
+ .isEqualTo(logoutToSystemUserCount)
}
}
companion object {
private val USER_INFOS =
- listOf(UserInfo(0, "System user", 0), UserInfo(10, "Regular user", 0))
+ listOf(
+ UserInfo(0, "System user", 0),
+ UserInfo(10, "Regular user", 0),
+ UserInfo(11, "Secondary user", 0),
+ )
}
}
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 82c8c44f1efe..0854eb46ffdd 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -1086,4 +1086,9 @@
enable the desktop specific features.
-->
<bool name="config_enableDesktopFeatureSet">false</bool>
+
+ <!--
+ Whether the user switching can only happen by logging out and going through the system user (login screen).
+ -->
+ <bool name="config_userSwitchingMustGoThroughLoginScreen">false</bool>
</resources>
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 f20ce63467f7..e9a33e062c60 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
@@ -23,11 +23,13 @@ import android.app.admin.DevicePolicyManager
import android.content.Context
import android.content.IntentFilter
import android.content.pm.UserInfo
+import android.content.res.Resources
import android.os.UserHandle
import android.os.UserManager
import android.provider.Settings
import androidx.annotation.VisibleForTesting
import com.android.app.tracing.coroutines.launchTraced as launch
+import com.android.internal.statusbar.IStatusBarService
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
@@ -109,6 +111,9 @@ interface UserRepository {
/** Whether logout for secondary users is enabled by admin device policy. */
val isSecondaryUserLogoutEnabled: StateFlow<Boolean>
+ /** Whether logout into system user is enabled. */
+ val isLogoutToSystemUserEnabled: StateFlow<Boolean>
+
/** Asynchronously refresh the list of users. This will cause [userInfos] to be updated. */
fun refreshUsers()
@@ -121,6 +126,9 @@ interface UserRepository {
/** Performs logout logout for secondary users. */
suspend fun logOutSecondaryUser()
+ /** Performs logout into the system user. */
+ suspend fun logOutToSystemUser()
+
/**
* Returns the user ID of the "main user" of the device. This user may have access to certain
* features which are limited to at most one user. There will never be more than one main user
@@ -143,6 +151,7 @@ class UserRepositoryImpl
@Inject
constructor(
@Application private val appContext: Context,
+ @Main private val resources: Resources,
private val manager: UserManager,
@Application private val applicationScope: CoroutineScope,
@Main private val mainDispatcher: CoroutineDispatcher,
@@ -151,6 +160,7 @@ constructor(
private val tracker: UserTracker,
private val devicePolicyManager: DevicePolicyManager,
private val broadcastDispatcher: BroadcastDispatcher,
+ private val statusBarService: IStatusBarService,
) : UserRepository {
private val _userSwitcherSettings: StateFlow<UserSwitcherSettingsModel> =
@@ -275,12 +285,34 @@ constructor(
.stateIn(applicationScope, SharingStarted.Eagerly, false)
@SuppressLint("MissingPermission")
+ override val isLogoutToSystemUserEnabled: StateFlow<Boolean> =
+ selectedUser
+ .flatMapLatestConflated { selectedUser ->
+ if (selectedUser.isEligibleForLogout()) {
+ flowOf(
+ resources.getBoolean(R.bool.config_userSwitchingMustGoThroughLoginScreen)
+ )
+ } else {
+ flowOf(false)
+ }
+ }
+ .stateIn(applicationScope, SharingStarted.Eagerly, false)
+
+ @SuppressLint("MissingPermission")
override suspend fun logOutSecondaryUser() {
if (isSecondaryUserLogoutEnabled.value) {
withContext(backgroundDispatcher) { devicePolicyManager.logoutUser() }
}
}
+ override suspend fun logOutToSystemUser() {
+ // TODO(b/377493351) : start using proper logout API once it is available.
+ // Using reboot is a temporary solution.
+ if (isLogoutToSystemUserEnabled.value) {
+ withContext(backgroundDispatcher) { statusBarService.reboot(false) }
+ }
+ }
+
@SuppressLint("MissingPermission")
override fun refreshUsers() {
applicationScope.launch {
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserLogoutInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserLogoutInteractor.kt
index 154f1dc3e747..f2dd25fecf08 100644
--- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserLogoutInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserLogoutInteractor.kt
@@ -23,7 +23,10 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.user.data.repository.UserRepository
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.stateIn
/** Encapsulates business logic to for the logout. */
@SysUISingleton
@@ -33,11 +36,22 @@ constructor(
private val userRepository: UserRepository,
@Application private val applicationScope: CoroutineScope,
) {
- val isLogoutEnabled: StateFlow<Boolean> = userRepository.isSecondaryUserLogoutEnabled
+
+ val isLogoutEnabled: StateFlow<Boolean> =
+ combine(
+ userRepository.isSecondaryUserLogoutEnabled,
+ userRepository.isLogoutToSystemUserEnabled,
+ Boolean::or,
+ )
+ .stateIn(applicationScope, SharingStarted.Eagerly, false)
fun logOut() {
- if (userRepository.isSecondaryUserLogoutEnabled.value) {
- applicationScope.launch { userRepository.logOutSecondaryUser() }
+ applicationScope.launch {
+ if (userRepository.isSecondaryUserLogoutEnabled.value) {
+ userRepository.logOutSecondaryUser()
+ } else if (userRepository.isLogoutToSystemUserEnabled.value) {
+ userRepository.logOutToSystemUser()
+ }
}
}
}
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 1808a5f99f4e..85d582a27faf 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
@@ -72,6 +72,10 @@ class FakeUserRepository @Inject constructor() : UserRepository {
override val isSecondaryUserLogoutEnabled: StateFlow<Boolean> =
_isSecondaryUserLogoutEnabled.asStateFlow()
+ private val _isLogoutToSystemUserEnabled = MutableStateFlow<Boolean>(false)
+ override val isLogoutToSystemUserEnabled: StateFlow<Boolean> =
+ _isLogoutToSystemUserEnabled.asStateFlow()
+
override var mainUserId: Int = MAIN_USER_ID
override var lastSelectedNonGuestUserId: Int = mainUserId
@@ -123,6 +127,17 @@ class FakeUserRepository @Inject constructor() : UserRepository {
logOutSecondaryUserCallCount++
}
+ fun setLogoutToSystemUserEnabled(logoutEnabled: Boolean) {
+ _isLogoutToSystemUserEnabled.value = logoutEnabled
+ }
+
+ var logOutToSystemUserCallCount: Int = 0
+ private set
+
+ override suspend fun logOutToSystemUser() {
+ logOutToSystemUserCallCount++
+ }
+
fun setUserInfos(infos: List<UserInfo>) {
_userInfos.value = infos
}