Merge "Prevent adding a user from lockscreen until a user has signed in" into tm-qpr-dev

This commit is contained in:
Tetiana Meronyk
2023-02-13 23:39:52 +00:00
committed by Android (Google) Code Review
7 changed files with 144 additions and 6 deletions

View File

@@ -21,6 +21,7 @@ import android.os.UserHandle;
import com.android.settingslib.users.EditUserInfoController; import com.android.settingslib.users.EditUserInfoController;
import com.android.systemui.user.data.repository.UserRepositoryModule; import com.android.systemui.user.data.repository.UserRepositoryModule;
import com.android.systemui.user.domain.interactor.HeadlessSystemUserModeModule;
import com.android.systemui.user.ui.dialog.UserDialogModule; import com.android.systemui.user.ui.dialog.UserDialogModule;
import dagger.Binds; import dagger.Binds;
@@ -36,6 +37,7 @@ import dagger.multibindings.IntoMap;
includes = { includes = {
UserDialogModule.class, UserDialogModule.class,
UserRepositoryModule.class, UserRepositoryModule.class,
HeadlessSystemUserModeModule.class,
} }
) )
public abstract class UserModule { public abstract class UserModule {

View File

@@ -0,0 +1,33 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.user.domain.interactor
import android.os.UserManager
import com.android.systemui.dagger.SysUISingleton
import javax.inject.Inject
interface HeadlessSystemUserMode {
fun isHeadlessSystemUserMode(): Boolean
}
@SysUISingleton
class HeadlessSystemUserModeImpl @Inject constructor() : HeadlessSystemUserMode {
override fun isHeadlessSystemUserMode(): Boolean {
return UserManager.isHeadlessSystemUserMode()
}
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.user.domain.interactor
import dagger.Binds
@dagger.Module
interface HeadlessSystemUserModeModule {
@Binds
fun bindIsHeadlessSystemUserMode(impl: HeadlessSystemUserModeImpl): HeadlessSystemUserMode
}

View File

@@ -86,6 +86,7 @@ constructor(
private val keyguardInteractor: KeyguardInteractor, private val keyguardInteractor: KeyguardInteractor,
private val featureFlags: FeatureFlags, private val featureFlags: FeatureFlags,
private val manager: UserManager, private val manager: UserManager,
private val headlessSystemUserMode: HeadlessSystemUserMode,
@Application private val applicationScope: CoroutineScope, @Application private val applicationScope: CoroutineScope,
telephonyInteractor: TelephonyInteractor, telephonyInteractor: TelephonyInteractor,
broadcastDispatcher: BroadcastDispatcher, broadcastDispatcher: BroadcastDispatcher,
@@ -560,7 +561,10 @@ constructor(
actionType = action, actionType = action,
isRestricted = isRestricted, isRestricted = isRestricted,
isSwitchToEnabled = isSwitchToEnabled =
canSwitchUsers(selectedUserId) && canSwitchUsers(
selectedUserId = selectedUserId,
isAction = true,
) &&
// If the user is auto-created is must not be currently resetting. // If the user is auto-created is must not be currently resetting.
!(isGuestUserAutoCreated && isGuestUserResetting), !(isGuestUserAutoCreated && isGuestUserResetting),
) )
@@ -712,12 +716,34 @@ constructor(
} }
} }
private suspend fun canSwitchUsers(selectedUserId: Int): Boolean { private suspend fun canSwitchUsers(
return withContext(backgroundDispatcher) { selectedUserId: Int,
isAction: Boolean = false,
): Boolean {
val isHeadlessSystemUserMode =
withContext(backgroundDispatcher) { headlessSystemUserMode.isHeadlessSystemUserMode() }
// Whether menu item should be active. True if item is a user or if any user has
// signed in since reboot or in all cases for non-headless system user mode.
val isItemEnabled = !isAction || !isHeadlessSystemUserMode || isAnyUserUnlocked()
return isItemEnabled &&
withContext(backgroundDispatcher) {
manager.getUserSwitchability(UserHandle.of(selectedUserId)) manager.getUserSwitchability(UserHandle.of(selectedUserId))
} == UserManager.SWITCHABILITY_STATUS_OK } == UserManager.SWITCHABILITY_STATUS_OK
} }
private suspend fun isAnyUserUnlocked(): Boolean {
return manager
.getUsers(
/* excludePartial= */ true,
/* excludeDying= */ true,
/* excludePreCreated= */ true
)
.any { user ->
user.id != UserHandle.USER_SYSTEM &&
withContext(backgroundDispatcher) { manager.isUserUnlocked(user.userHandle) }
}
}
@SuppressLint("UseCompatLoadingForDrawables") @SuppressLint("UseCompatLoadingForDrawables")
private suspend fun getUserImage( private suspend fun getUserImage(
isGuest: Boolean, isGuest: Boolean,

View File

@@ -28,7 +28,6 @@ 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.internal.R.drawable.ic_account_circle
import com.android.internal.logging.UiEventLogger import com.android.internal.logging.UiEventLogger
import com.android.systemui.GuestResetOrExitSessionReceiver import com.android.systemui.GuestResetOrExitSessionReceiver
import com.android.systemui.GuestResumeSessionReceiver import com.android.systemui.GuestResumeSessionReceiver
@@ -87,6 +86,7 @@ class UserInteractorTest : SysuiTestCase() {
@Mock private lateinit var activityStarter: ActivityStarter @Mock private lateinit var activityStarter: ActivityStarter
@Mock private lateinit var manager: UserManager @Mock private lateinit var manager: UserManager
@Mock private lateinit var headlessSystemUserMode: HeadlessSystemUserMode
@Mock private lateinit var activityManager: ActivityManager @Mock private lateinit var activityManager: ActivityManager
@Mock private lateinit var deviceProvisionedController: DeviceProvisionedController @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController
@Mock private lateinit var devicePolicyManager: DevicePolicyManager @Mock private lateinit var devicePolicyManager: DevicePolicyManager
@@ -145,6 +145,7 @@ class UserInteractorTest : SysuiTestCase() {
featureFlags = featureFlags, featureFlags = featureFlags,
), ),
manager = manager, manager = manager,
headlessSystemUserMode = headlessSystemUserMode,
applicationScope = testScope.backgroundScope, applicationScope = testScope.backgroundScope,
telephonyInteractor = telephonyInteractor =
TelephonyInteractor( TelephonyInteractor(
@@ -848,6 +849,50 @@ class UserInteractorTest : SysuiTestCase() {
assertThat(selectedUser()).isNotNull() assertThat(selectedUser()).isNotNull()
} }
@Test
fun userRecords_isActionAndNoUsersUnlocked_actionIsDisabled() =
testScope.runTest {
keyguardRepository.setKeyguardShowing(true)
whenever(manager.getUserSwitchability(any()))
.thenReturn(UserManager.SWITCHABILITY_STATUS_SYSTEM_USER_LOCKED)
val userInfos = createUserInfos(count = 3, includeGuest = false).toMutableList()
userRepository.setUserInfos(userInfos)
userRepository.setSelectedUserInfo(userInfos[1])
userRepository.setSettings(
UserSwitcherSettingsModel(
isUserSwitcherEnabled = true,
isAddUsersFromLockscreen = true
)
)
runCurrent()
underTest.userRecords.value
.filter { it.info == null }
.forEach { action -> assertThat(action.isSwitchToEnabled).isFalse() }
}
@Test
fun userRecords_isActionAndNoUsersUnlocked_actionIsDisabled_HeadlessMode() =
testScope.runTest {
keyguardRepository.setKeyguardShowing(true)
whenever(headlessSystemUserMode.isHeadlessSystemUserMode()).thenReturn(true)
whenever(manager.isUserUnlocked(anyInt())).thenReturn(false)
val userInfos = createUserInfos(count = 3, includeGuest = false).toMutableList()
userRepository.setUserInfos(userInfos)
userRepository.setSelectedUserInfo(userInfos[1])
userRepository.setSettings(
UserSwitcherSettingsModel(
isUserSwitcherEnabled = true,
isAddUsersFromLockscreen = true
)
)
runCurrent()
underTest.userRecords.value
.filter { it.info == null }
.forEach { action -> assertThat(action.isSwitchToEnabled).isFalse() }
}
private fun assertUsers( private fun assertUsers(
models: List<UserModel>?, models: List<UserModel>?,
count: Int, count: Int,

View File

@@ -41,6 +41,7 @@ import com.android.systemui.telephony.domain.interactor.TelephonyInteractor
import com.android.systemui.user.data.model.UserSwitcherSettingsModel import com.android.systemui.user.data.model.UserSwitcherSettingsModel
import com.android.systemui.user.data.repository.FakeUserRepository import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.user.domain.interactor.GuestUserInteractor import com.android.systemui.user.domain.interactor.GuestUserInteractor
import com.android.systemui.user.domain.interactor.HeadlessSystemUserMode
import com.android.systemui.user.domain.interactor.RefreshUsersScheduler import com.android.systemui.user.domain.interactor.RefreshUsersScheduler
import com.android.systemui.user.domain.interactor.UserInteractor import com.android.systemui.user.domain.interactor.UserInteractor
import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.mock
@@ -71,6 +72,7 @@ class StatusBarUserChipViewModelTest : SysuiTestCase() {
@Mock private lateinit var activityStarter: ActivityStarter @Mock private lateinit var activityStarter: ActivityStarter
@Mock private lateinit var activityManager: ActivityManager @Mock private lateinit var activityManager: ActivityManager
@Mock private lateinit var manager: UserManager @Mock private lateinit var manager: UserManager
@Mock private lateinit var headlessSystemUserMode: HeadlessSystemUserMode
@Mock private lateinit var deviceProvisionedController: DeviceProvisionedController @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController
@Mock private lateinit var devicePolicyManager: DevicePolicyManager @Mock private lateinit var devicePolicyManager: DevicePolicyManager
@Mock private lateinit var uiEventLogger: UiEventLogger @Mock private lateinit var uiEventLogger: UiEventLogger
@@ -252,6 +254,7 @@ class StatusBarUserChipViewModelTest : SysuiTestCase() {
), ),
featureFlags = featureFlags, featureFlags = featureFlags,
manager = manager, manager = manager,
headlessSystemUserMode = headlessSystemUserMode,
applicationScope = testScope.backgroundScope, applicationScope = testScope.backgroundScope,
telephonyInteractor = telephonyInteractor =
TelephonyInteractor( TelephonyInteractor(

View File

@@ -41,6 +41,7 @@ import com.android.systemui.telephony.domain.interactor.TelephonyInteractor
import com.android.systemui.user.data.model.UserSwitcherSettingsModel import com.android.systemui.user.data.model.UserSwitcherSettingsModel
import com.android.systemui.user.data.repository.FakeUserRepository import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.user.domain.interactor.GuestUserInteractor import com.android.systemui.user.domain.interactor.GuestUserInteractor
import com.android.systemui.user.domain.interactor.HeadlessSystemUserMode
import com.android.systemui.user.domain.interactor.RefreshUsersScheduler import com.android.systemui.user.domain.interactor.RefreshUsersScheduler
import com.android.systemui.user.domain.interactor.UserInteractor import com.android.systemui.user.domain.interactor.UserInteractor
import com.android.systemui.user.legacyhelper.ui.LegacyUserUiHelper import com.android.systemui.user.legacyhelper.ui.LegacyUserUiHelper
@@ -72,6 +73,7 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
@Mock private lateinit var activityStarter: ActivityStarter @Mock private lateinit var activityStarter: ActivityStarter
@Mock private lateinit var activityManager: ActivityManager @Mock private lateinit var activityManager: ActivityManager
@Mock private lateinit var manager: UserManager @Mock private lateinit var manager: UserManager
@Mock private lateinit var headlessSystemUserMode: HeadlessSystemUserMode
@Mock private lateinit var deviceProvisionedController: DeviceProvisionedController @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController
@Mock private lateinit var devicePolicyManager: DevicePolicyManager @Mock private lateinit var devicePolicyManager: DevicePolicyManager
@Mock private lateinit var uiEventLogger: UiEventLogger @Mock private lateinit var uiEventLogger: UiEventLogger
@@ -154,6 +156,7 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
), ),
featureFlags = featureFlags, featureFlags = featureFlags,
manager = manager, manager = manager,
headlessSystemUserMode = headlessSystemUserMode,
applicationScope = testScope.backgroundScope, applicationScope = testScope.backgroundScope,
telephonyInteractor = telephonyInteractor =
TelephonyInteractor( TelephonyInteractor(