diff options
| author | 2023-02-13 23:39:52 +0000 | |
|---|---|---|
| committer | 2023-02-13 23:39:52 +0000 | |
| commit | c0511060f42e4530d82747afa5d0cd9a34e0fd43 (patch) | |
| tree | 5de1a3f6f2c9a2a9e8da21d1b143aabe600c5541 | |
| parent | 090f8dca9cdfe21e64aa3f0b2e92680da6fb899f (diff) | |
| parent | f4f93d0ea95fd0f1052a8cd96ba9c53644120576 (diff) | |
Merge "Prevent adding a user from lockscreen until a user has signed in" into tm-qpr-dev
7 files changed, 144 insertions, 6 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/user/UserModule.java b/packages/SystemUI/src/com/android/systemui/user/UserModule.java index 2b29885db682..f7c8bac1b478 100644 --- a/packages/SystemUI/src/com/android/systemui/user/UserModule.java +++ b/packages/SystemUI/src/com/android/systemui/user/UserModule.java @@ -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 { diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/HeadlessSystemUserMode.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/HeadlessSystemUserMode.kt new file mode 100644 index 000000000000..756e6a1a5b15 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/HeadlessSystemUserMode.kt @@ -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() + } +} diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/HeadlessSystemUserModeModule.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/HeadlessSystemUserModeModule.kt new file mode 100644 index 000000000000..0efa2d8b6a36 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/HeadlessSystemUserModeModule.kt @@ -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 +} diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt index c0ba3cc352b0..3f895ad0b5b4 100644 --- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt @@ -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") diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt index 8660d097c0df..0257ebd5c6d4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt @@ -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, diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt index 8a35cb05038a..2fedb875b3e3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt @@ -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( diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt index 1337d1bdb7ca..166b90943847 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt @@ -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( |