Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 21ba4f2b authored by Leon Masopust's avatar Leon Masopust Committed by Android (Google) Code Review
Browse files

Merge changes Ie12be493,Ie88daca4 into main

* changes:
  Add sign out option to user switcher
  Setup aconfig for desktop_users_and_accounts
parents 3ea3e955 1b75156d
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
package: "com.android.systemui"
container: "system"

flag {
    name: "user_switcher_add_sign_out_option"
    namespace: "desktop_users_and_accounts"
    description: "Add a sign out option to the user switcher menu if sign out is possible"
    bug: "381478261"
}
 No newline at end of file
+2 −2
Original line number Diff line number Diff line
@@ -507,8 +507,8 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase {
                    0 /* flags */);
            users.add(new UserRecord(info, null, false /* isGuest */, false /* isCurrent */,
                    false /* isAddUser */, false /* isRestricted */, true /* isSwitchToEnabled */,
                    false /* isAddSupervisedUser */, null /* enforcedAdmin */,
                    false /* isManageUsers */));
                    false /* isAddSupervisedUser */, false /* isSignOut */,
                    null /* enforcedAdmin */, false /* isManageUsers */));
        }
        return users;
    }
+68 −18
Original line number Diff line number Diff line
@@ -27,6 +27,8 @@ import android.graphics.drawable.Drawable
import android.os.Process
import android.os.UserHandle
import android.os.UserManager
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.provider.Settings
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -34,6 +36,7 @@ import com.android.internal.logging.UiEventLogger
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.Flags as AConfigFlags
import com.android.systemui.Flags.FLAG_USER_SWITCHER_ADD_SIGN_OUT_OPTION
import com.android.systemui.GuestResetOrExitSessionReceiver
import com.android.systemui.GuestResumeSessionReceiver
import com.android.systemui.SysuiTestCase
@@ -68,6 +71,7 @@ import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import junit.framework.Assert.assertNotNull
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.runCurrent
@@ -101,10 +105,13 @@ class UserSwitcherInteractorTest : SysuiTestCase() {
    @Mock private lateinit var resumeSessionReceiver: GuestResumeSessionReceiver
    @Mock private lateinit var resetOrExitSessionReceiver: GuestResetOrExitSessionReceiver
    @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
    @Mock private lateinit var userLogoutInteractor: UserLogoutInteractor

    private val kosmos = testKosmos()
    private val logoutEnabledStateFlow = MutableStateFlow<Boolean>(false)
    private val testScope = kosmos.testScope
    private lateinit var spyContext: Context

    private lateinit var userRepository: FakeUserRepository
    private lateinit var keyguardReply: KeyguardInteractorFactory.WithDependencies
    private lateinit var keyguardRepository: FakeKeyguardRepository
@@ -118,6 +125,8 @@ class UserSwitcherInteractorTest : SysuiTestCase() {
        whenever(manager.getUserIcon(anyInt())).thenReturn(ICON)
        whenever(manager.canAddMoreUsers(any())).thenReturn(true)

        whenever(userLogoutInteractor.isLogoutEnabled).thenReturn(logoutEnabledStateFlow)

        overrideResource(com.android.settingslib.R.drawable.ic_account_circle, GUEST_ICON)
        overrideResource(R.dimen.max_avatar_size, 10)
        overrideResource(
@@ -492,6 +501,42 @@ class UserSwitcherInteractorTest : SysuiTestCase() {
        }
    }

    @Test
    @DisableFlags(FLAG_USER_SWITCHER_ADD_SIGN_OUT_OPTION)
    fun actions_logoutEnabled_flagDisabled_signOutIsNotShown() {
        createUserInteractor()
        testScope.runTest {
            val userInfos = createUserInfos(count = 1, includeGuest = false)
            userRepository.setUserInfos(userInfos)
            userRepository.setSelectedUserInfo(userInfos[0])
            userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = false))
            keyguardRepository.setKeyguardShowing(true)
            logoutEnabledStateFlow.value = true

            val value = collectLastValue(underTest.actions)

            assertThat(value()).isEqualTo(emptyList<UserActionModel>())
        }
    }

    @Test
    @EnableFlags(FLAG_USER_SWITCHER_ADD_SIGN_OUT_OPTION)
    fun actions_logoutEnabled_flagEnabled_signOutIsShown() {
        createUserInteractor()
        testScope.runTest {
            val userInfos = createUserInfos(count = 1, includeGuest = false)
            userRepository.setUserInfos(userInfos)
            userRepository.setSelectedUserInfo(userInfos[0])
            userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = false))
            keyguardRepository.setKeyguardShowing(true)
            logoutEnabledStateFlow.value = true

            val value = collectLastValue(underTest.actions)

            assertThat(value()).isEqualTo(listOf(UserActionModel.SIGN_OUT))
        }
    }

    @Test
    fun executeAction_addUser_dismissesDialogAndStartsActivity() {
        createUserInteractor()
@@ -569,13 +614,22 @@ class UserSwitcherInteractorTest : SysuiTestCase() {
            verify(uiEventLogger, times(1))
                .log(MultiUserActionsEvent.CREATE_GUEST_FROM_USER_SWITCHER)
            assertThat(dialogRequests)
                .contains(
                    ShowDialogRequestModel.ShowUserCreationDialog(isGuest = true),
                )
                .contains(ShowDialogRequestModel.ShowUserCreationDialog(isGuest = true))
            verify(activityManager).switchUser(guestUserInfo.id)
        }
    }

    @Test
    fun executeAction_signOut() {
        createUserInteractor()
        testScope.runTest {
            underTest.executeAction(UserActionModel.SIGN_OUT)
            runCurrent()

            verify(userLogoutInteractor).logOut()
        }
    }

    @Test
    fun selectUser_alreadySelectedGuestReSelected_exitGuestDialog() {
        createUserInteractor()
@@ -739,7 +793,7 @@ class UserSwitcherInteractorTest : SysuiTestCase() {

            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
                spyContext,
                Intent(Intent.ACTION_LOCALE_CHANGED)
                Intent(Intent.ACTION_LOCALE_CHANGED),
            )
            runCurrent()

@@ -972,7 +1026,7 @@ class UserSwitcherInteractorTest : SysuiTestCase() {
                    50,
                    "Work Profile",
                    /* iconPath= */ "",
                    /* flags= */ UserInfo.FLAG_MANAGED_PROFILE
                    /* flags= */ UserInfo.FLAG_MANAGED_PROFILE,
                )
            )
            userRepository.setUserInfos(userInfos)
@@ -1010,7 +1064,7 @@ class UserSwitcherInteractorTest : SysuiTestCase() {
            userRepository.setSettings(
                UserSwitcherSettingsModel(
                    isUserSwitcherEnabled = true,
                    isAddUsersFromLockscreen = true
                    isAddUsersFromLockscreen = true,
                )
            )

@@ -1034,7 +1088,7 @@ class UserSwitcherInteractorTest : SysuiTestCase() {
            userRepository.setSettings(
                UserSwitcherSettingsModel(
                    isUserSwitcherEnabled = true,
                    isAddUsersFromLockscreen = true
                    isAddUsersFromLockscreen = true,
                )
            )

@@ -1068,7 +1122,7 @@ class UserSwitcherInteractorTest : SysuiTestCase() {
            whenever(
                    manager.hasUserRestrictionForUser(
                        UserManager.DISALLOW_ADD_USER,
                        UserHandle.of(id)
                        UserHandle.of(id),
                    )
                )
                .thenReturn(true)
@@ -1170,7 +1224,7 @@ class UserSwitcherInteractorTest : SysuiTestCase() {
            whenever(
                    manager.hasUserRestrictionForUser(
                        UserManager.DISALLOW_ADD_USER,
                        UserHandle.of(0)
                        UserHandle.of(0),
                    )
                )
                .thenReturn(true)
@@ -1195,7 +1249,7 @@ class UserSwitcherInteractorTest : SysuiTestCase() {
                model = model,
                id = index,
                isSelected = index == selectedIndex,
                isGuest = includeGuest && index == count - 1
                isGuest = includeGuest && index == count - 1,
            )
        }
    }
@@ -1263,14 +1317,12 @@ class UserSwitcherInteractorTest : SysuiTestCase() {
        assertThat(record.isSwitchToEnabled).isEqualTo(isSwitchToEnabled)
    }

    private fun assertRecordForAction(
        record: UserRecord,
        type: UserActionModel,
    ) {
    private fun assertRecordForAction(record: UserRecord, type: UserActionModel) {
        assertThat(record.isGuest).isEqualTo(type == UserActionModel.ENTER_GUEST_MODE)
        assertThat(record.isAddUser).isEqualTo(type == UserActionModel.ADD_USER)
        assertThat(record.isAddSupervisedUser)
            .isEqualTo(type == UserActionModel.ADD_SUPERVISED_USER)
        assertThat(record.isSignOut).isEqualTo(type === UserActionModel.SIGN_OUT)
    }

    private fun createUserInteractor(startAsProcessUser: Boolean = true) {
@@ -1317,13 +1369,11 @@ class UserSwitcherInteractorTest : SysuiTestCase() {
                featureFlags = kosmos.fakeFeatureFlagsClassic,
                userRestrictionChecker = mock(),
                processWrapper = kosmos.processWrapper,
                userLogoutInteractor = userLogoutInteractor,
            )
    }

    private fun createUserInfos(
        count: Int,
        includeGuest: Boolean,
    ): List<UserInfo> {
    private fun createUserInfos(count: Int, includeGuest: Boolean): List<UserInfo> {
        return (0 until count).map { index ->
            val isGuest = includeGuest && index == count - 1
            createUserInfo(
+13 −8
Original line number Diff line number Diff line
@@ -44,9 +44,12 @@ 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.UserLogoutInteractor
import com.android.systemui.user.domain.interactor.UserSwitcherInteractor
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.toList
@@ -78,13 +81,13 @@ class StatusBarUserChipViewModelTest : SysuiTestCase() {
    @Mock private lateinit var resumeSessionReceiver: GuestResumeSessionReceiver
    @Mock private lateinit var resetOrExitSessionReceiver: GuestResetOrExitSessionReceiver
    @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
    @Mock private lateinit var userLogoutInteractor: UserLogoutInteractor

    private lateinit var underTest: StatusBarUserChipViewModel

    private val userRepository = FakeUserRepository()
    private lateinit var guestUserInteractor: GuestUserInteractor
    private lateinit var refreshUsersScheduler: RefreshUsersScheduler

    private val testDispatcher = UnconfinedTestDispatcher()
    private val testScope = TestScope(testDispatcher)

@@ -92,6 +95,9 @@ class StatusBarUserChipViewModelTest : SysuiTestCase() {
    fun setUp() {
        MockitoAnnotations.initMocks(this)

        val logoutEnabledStateFlow = MutableStateFlow<Boolean>(false)
        whenever(userLogoutInteractor.isLogoutEnabled).thenReturn(logoutEnabledStateFlow)

        doAnswer { invocation ->
                val userId = invocation.arguments[0] as Int
                when (userId) {
@@ -251,9 +257,7 @@ class StatusBarUserChipViewModelTest : SysuiTestCase() {
                    headlessSystemUserMode = headlessSystemUserMode,
                    applicationScope = testScope.backgroundScope,
                    telephonyInteractor =
                        TelephonyInteractor(
                            repository = FakeTelephonyRepository(),
                        ),
                        TelephonyInteractor(repository = FakeTelephonyRepository()),
                    broadcastDispatcher = fakeBroadcastDispatcher,
                    keyguardUpdateMonitor = keyguardUpdateMonitor,
                    backgroundDispatcher = testDispatcher,
@@ -263,7 +267,8 @@ class StatusBarUserChipViewModelTest : SysuiTestCase() {
                    guestUserInteractor = guestUserInteractor,
                    uiEventLogger = uiEventLogger,
                    userRestrictionChecker = mock(),
                    processWrapper = ProcessWrapperFake(activityManager)
                    processWrapper = ProcessWrapperFake(activityManager),
                    userLogoutInteractor = userLogoutInteractor,
                )
        )
    }
@@ -293,7 +298,7 @@ class StatusBarUserChipViewModelTest : SysuiTestCase() {
                USER_NAME_0.text!!,
                /* iconPath */ "",
                /* flags */ UserInfo.FLAG_FULL,
                /* userType */ UserManager.USER_TYPE_FULL_SYSTEM
                /* userType */ UserManager.USER_TYPE_FULL_SYSTEM,
            )

        private val USER_1 =
@@ -302,7 +307,7 @@ class StatusBarUserChipViewModelTest : SysuiTestCase() {
                USER_NAME_1.text!!,
                /* iconPath */ "",
                /* flags */ UserInfo.FLAG_FULL,
                /* userType */ UserManager.USER_TYPE_FULL_SYSTEM
                /* userType */ UserManager.USER_TYPE_FULL_SYSTEM,
            )

        private val USER_2 =
@@ -311,7 +316,7 @@ class StatusBarUserChipViewModelTest : SysuiTestCase() {
                USER_NAME_2.text!!,
                /* iconPath */ "",
                /* flags */ UserInfo.FLAG_FULL,
                /* userType */ UserManager.USER_TYPE_FULL_SYSTEM
                /* userType */ UserManager.USER_TYPE_FULL_SYSTEM,
            )
    }
}
+12 −10
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ 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.UserLogoutInteractor
import com.android.systemui.user.domain.interactor.UserSwitcherInteractor
import com.android.systemui.user.legacyhelper.ui.LegacyUserUiHelper
import com.android.systemui.user.shared.model.UserActionModel
@@ -51,6 +52,7 @@ import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
@@ -79,6 +81,7 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
    @Mock private lateinit var resumeSessionReceiver: GuestResumeSessionReceiver
    @Mock private lateinit var resetOrExitSessionReceiver: GuestResetOrExitSessionReceiver
    @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
    @Mock private lateinit var userLogoutInteractor: UserLogoutInteractor

    private lateinit var underTest: UserSwitcherViewModel

@@ -94,6 +97,10 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
        whenever(manager.canAddMoreUsers(any())).thenReturn(true)
        whenever(manager.getUserSwitchability(any()))
            .thenReturn(UserManager.SWITCHABILITY_STATUS_OK)

        val logoutEnabledStateFlow = MutableStateFlow<Boolean>(false)
        whenever(userLogoutInteractor.isLogoutEnabled).thenReturn(logoutEnabledStateFlow)

        overrideResource(
            com.android.internal.R.string.config_supervisedUserCreationPackage,
            SUPERVISED_USER_CREATION_PACKAGE,
@@ -113,15 +120,11 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
                            UserInfo.FLAG_ADMIN or
                            UserInfo.FLAG_FULL,
                        UserManager.USER_TYPE_FULL_SYSTEM,
                    ),
                    )
                )
            userRepository.setUserInfos(userInfos)
            userRepository.setSelectedUserInfo(userInfos[0])
            userRepository.setSettings(
                UserSwitcherSettingsModel(
                    isUserSwitcherEnabled = true,
                )
            )
            userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true))
        }

        val refreshUsersScheduler =
@@ -163,9 +166,7 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
                        headlessSystemUserMode = headlessSystemUserMode,
                        applicationScope = testScope.backgroundScope,
                        telephonyInteractor =
                            TelephonyInteractor(
                                repository = FakeTelephonyRepository(),
                            ),
                            TelephonyInteractor(repository = FakeTelephonyRepository()),
                        broadcastDispatcher = fakeBroadcastDispatcher,
                        keyguardUpdateMonitor = keyguardUpdateMonitor,
                        backgroundDispatcher = testDispatcher,
@@ -175,7 +176,8 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
                        guestUserInteractor = guestUserInteractor,
                        uiEventLogger = uiEventLogger,
                        userRestrictionChecker = mock(),
                        processWrapper = ProcessWrapperFake(activityManager)
                        processWrapper = ProcessWrapperFake(activityManager),
                        userLogoutInteractor = userLogoutInteractor,
                    ),
                guestUserInteractor = guestUserInteractor,
            )
Loading