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:
Tetiana Meronyk
2023-02-14 00:07:53 +00:00
committed by Automerger Merge Worker
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.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 {

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 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")

View File

@@ -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,

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.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(

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.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(