Merge "Prevent adding a user from lockscreen until a user has signed in" into tm-qpr-dev am: c0511060f4
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/21223582 Change-Id: If14592cb3c2b9897eb11b978182e58dd30346ec9 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -21,6 +21,7 @@ import android.os.UserHandle;
|
||||
|
||||
import com.android.settingslib.users.EditUserInfoController;
|
||||
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 dagger.Binds;
|
||||
@@ -36,6 +37,7 @@ import dagger.multibindings.IntoMap;
|
||||
includes = {
|
||||
UserDialogModule.class,
|
||||
UserRepositoryModule.class,
|
||||
HeadlessSystemUserModeModule.class,
|
||||
}
|
||||
)
|
||||
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 featureFlags: FeatureFlags,
|
||||
private val manager: UserManager,
|
||||
private val headlessSystemUserMode: HeadlessSystemUserMode,
|
||||
@Application private val applicationScope: CoroutineScope,
|
||||
telephonyInteractor: TelephonyInteractor,
|
||||
broadcastDispatcher: BroadcastDispatcher,
|
||||
@@ -560,7 +561,10 @@ constructor(
|
||||
actionType = action,
|
||||
isRestricted = isRestricted,
|
||||
isSwitchToEnabled =
|
||||
canSwitchUsers(selectedUserId) &&
|
||||
canSwitchUsers(
|
||||
selectedUserId = selectedUserId,
|
||||
isAction = true,
|
||||
) &&
|
||||
// If the user is auto-created is must not be currently resetting.
|
||||
!(isGuestUserAutoCreated && isGuestUserResetting),
|
||||
)
|
||||
@@ -712,10 +716,32 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun canSwitchUsers(selectedUserId: Int): Boolean {
|
||||
return withContext(backgroundDispatcher) {
|
||||
manager.getUserSwitchability(UserHandle.of(selectedUserId))
|
||||
} == UserManager.SWITCHABILITY_STATUS_OK
|
||||
private suspend fun canSwitchUsers(
|
||||
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))
|
||||
} == 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")
|
||||
|
||||
@@ -28,7 +28,6 @@ import android.os.UserHandle
|
||||
import android.os.UserManager
|
||||
import android.provider.Settings
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.internal.R.drawable.ic_account_circle
|
||||
import com.android.internal.logging.UiEventLogger
|
||||
import com.android.systemui.GuestResetOrExitSessionReceiver
|
||||
import com.android.systemui.GuestResumeSessionReceiver
|
||||
@@ -87,6 +86,7 @@ class UserInteractorTest : SysuiTestCase() {
|
||||
|
||||
@Mock private lateinit var activityStarter: ActivityStarter
|
||||
@Mock private lateinit var manager: UserManager
|
||||
@Mock private lateinit var headlessSystemUserMode: HeadlessSystemUserMode
|
||||
@Mock private lateinit var activityManager: ActivityManager
|
||||
@Mock private lateinit var deviceProvisionedController: DeviceProvisionedController
|
||||
@Mock private lateinit var devicePolicyManager: DevicePolicyManager
|
||||
@@ -145,6 +145,7 @@ class UserInteractorTest : SysuiTestCase() {
|
||||
featureFlags = featureFlags,
|
||||
),
|
||||
manager = manager,
|
||||
headlessSystemUserMode = headlessSystemUserMode,
|
||||
applicationScope = testScope.backgroundScope,
|
||||
telephonyInteractor =
|
||||
TelephonyInteractor(
|
||||
@@ -848,6 +849,50 @@ class UserInteractorTest : SysuiTestCase() {
|
||||
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(
|
||||
models: List<UserModel>?,
|
||||
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.repository.FakeUserRepository
|
||||
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.UserInteractor
|
||||
import com.android.systemui.util.mockito.mock
|
||||
@@ -71,6 +72,7 @@ class StatusBarUserChipViewModelTest : SysuiTestCase() {
|
||||
@Mock private lateinit var activityStarter: ActivityStarter
|
||||
@Mock private lateinit var activityManager: ActivityManager
|
||||
@Mock private lateinit var manager: UserManager
|
||||
@Mock private lateinit var headlessSystemUserMode: HeadlessSystemUserMode
|
||||
@Mock private lateinit var deviceProvisionedController: DeviceProvisionedController
|
||||
@Mock private lateinit var devicePolicyManager: DevicePolicyManager
|
||||
@Mock private lateinit var uiEventLogger: UiEventLogger
|
||||
@@ -252,6 +254,7 @@ class StatusBarUserChipViewModelTest : SysuiTestCase() {
|
||||
),
|
||||
featureFlags = featureFlags,
|
||||
manager = manager,
|
||||
headlessSystemUserMode = headlessSystemUserMode,
|
||||
applicationScope = testScope.backgroundScope,
|
||||
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.repository.FakeUserRepository
|
||||
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.UserInteractor
|
||||
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 activityManager: ActivityManager
|
||||
@Mock private lateinit var manager: UserManager
|
||||
@Mock private lateinit var headlessSystemUserMode: HeadlessSystemUserMode
|
||||
@Mock private lateinit var deviceProvisionedController: DeviceProvisionedController
|
||||
@Mock private lateinit var devicePolicyManager: DevicePolicyManager
|
||||
@Mock private lateinit var uiEventLogger: UiEventLogger
|
||||
@@ -154,6 +156,7 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
|
||||
),
|
||||
featureFlags = featureFlags,
|
||||
manager = manager,
|
||||
headlessSystemUserMode = headlessSystemUserMode,
|
||||
applicationScope = testScope.backgroundScope,
|
||||
telephonyInteractor =
|
||||
TelephonyInteractor(
|
||||
|
||||
Reference in New Issue
Block a user