Merge "Prevent adding a user from lockscreen until a user has signed in" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
c0511060f4
@@ -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 {
|
||||||
|
|||||||
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
Reference in New Issue
Block a user