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

Commit fa3dceee authored by Luzanne Batoon's avatar Luzanne Batoon
Browse files

Disable QS settings button for headless system user

Bug: 408067114
Test: atest FooterActionsViewModelTest ToolbarViewModelTest
Flag: com.android.systemui.hsu_qs_changes

Change-Id: Id0807abd72ad137e57755d2f7e0cf3249885ce87
parent f7eb462d
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -156,6 +156,7 @@ fun FooterActions(viewModel: FooterActionsViewModel, modifier: Modifier = Modifi
        mutableStateOf<FooterActionsForegroundServicesButtonViewModel?>(null)
    }
    var userSwitcher by remember { mutableStateOf<FooterActionsButtonViewModel?>(null) }
    var settings by remember { mutableStateOf<FooterActionsButtonViewModel?>(null) }

    var textFeedback by remember {
        mutableStateOf<TextFeedbackViewModel>(TextFeedbackViewModel.NoFeedback)
@@ -174,12 +175,14 @@ fun FooterActions(viewModel: FooterActionsViewModel, modifier: Modifier = Modifi
        viewModel.foregroundServices,
        viewModel.userSwitcher,
        viewModel.textFeedback,
        viewModel.settings,
        minActiveState = Lifecycle.State.RESUMED,
    ) {
        launch { viewModel.security.collect { security = it } }
        launch { viewModel.foregroundServices.collect { foregroundServices = it } }
        launch { viewModel.userSwitcher.collect { userSwitcher = it } }
        launch { viewModel.textFeedback.collect { textFeedback = it } }
        launch { viewModel.settings.collect { settings = it } }
    }

    val backgroundColor =
@@ -253,7 +256,7 @@ fun FooterActions(viewModel: FooterActionsViewModel, modifier: Modifier = Modifi
                Modifier.sysuiResTag("multi_user_switch"),
            )
            IconButton(
                { viewModel.settings },
                { settings },
                useModifierBasedExpandable,
                Modifier.sysuiResTag("settings_button_container"),
            )
+62 −5
Original line number Diff line number Diff line
@@ -17,7 +17,9 @@
package com.android.systemui.qs.footer.ui.viewmodel

import android.app.supervision.flags.Flags
import android.content.pm.UserInfo
import android.graphics.drawable.Drawable
import android.os.UserHandle
import android.os.UserManager
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
@@ -29,6 +31,7 @@ import androidx.test.filters.SmallTest
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.settingslib.Utils
import com.android.settingslib.drawable.UserIconDrawable
import com.android.systemui.Flags as SysUiFlags
import com.android.systemui.InstanceIdSequenceFake
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
@@ -54,6 +57,9 @@ import com.android.systemui.statusbar.policy.FakeSecurityController
import com.android.systemui.statusbar.policy.FakeUserInfoController
import com.android.systemui.statusbar.policy.FakeUserInfoController.FakeInfo
import com.android.systemui.statusbar.policy.MockUserSwitcherControllerWrapper
import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.user.domain.interactor.HeadlessSystemUserModeFake
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.nullable
import com.android.systemui.util.settings.FakeGlobalSettings
@@ -61,6 +67,7 @@ import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.advanceUntilIdle
@@ -80,6 +87,8 @@ import org.mockito.kotlin.eq
class FooterActionsViewModelTest : SysuiTestCase() {
    private val testDispatcher = StandardTestDispatcher()
    private val testScope = TestScope(testDispatcher)
    private val userRepository = FakeUserRepository()
    private val selectedUserInteractor = SelectedUserInteractor(userRepository)
    private lateinit var utils: FooterActionsTestUtils

    private val themedContext = ContextThemeWrapper(context, R.style.Theme_SystemUI_QuickSettings)
@@ -87,6 +96,7 @@ class FooterActionsViewModelTest : SysuiTestCase() {
    @Before
    fun setUp() {
        utils = FooterActionsTestUtils(context, TestableLooper.get(this), testScope.testScheduler)
        userRepository.setUserInfos(USER_INFOS)
    }

    private fun runTest(block: suspend TestScope.() -> Unit) {
@@ -94,22 +104,66 @@ class FooterActionsViewModelTest : SysuiTestCase() {
    }

    @Test
    @DisableFlags(SysUiFlags.FLAG_HSU_QS_CHANGES)
    fun settingsButton() = runTest {
        val underTest = utils.footerActionsViewModel(showPowerButton = false)
        val settings = underTest.settings
        val underTest =
            utils.footerActionsViewModel(
                showPowerButton = false,
                selectedUserInteractor = selectedUserInteractor,
            )
        runBlocking { userRepository.setSelectedUserInfo(USER) }

        val settings by collectLastValue(underTest.settings)

        assertThat(settings.icon)
        assertThat(settings).isNotNull()
        assertThat(settings?.icon)
            .isEqualTo(
                Icon.Resource(
                    R.drawable.ic_qs_footer_settings,
                    ContentDescription.Resource(R.string.accessibility_quick_settings_settings),
                )
            )
        assertThat(settings.backgroundColorFallback).isEqualTo(R.attr.shadeInactive)
        assertThat(settings.iconTintFallback)
        assertThat(settings?.backgroundColorFallback).isEqualTo(R.attr.shadeInactive)
        assertThat(settings?.iconTintFallback)
            .isEqualTo(Utils.getColorAttrDefaultColor(themedContext, R.attr.onShadeInactiveVariant))
    }

    @Test
    @EnableFlags(SysUiFlags.FLAG_HSU_QS_CHANGES)
    fun settingsButton_hideForHeadlessSystemUser() = runTest {
        val fakeHsum = HeadlessSystemUserModeFake()
        fakeHsum.setIsHeadlessSystemUser(true)
        val underTest =
            utils.footerActionsViewModel(
                showPowerButton = false,
                hsum = fakeHsum,
                selectedUserInteractor = selectedUserInteractor,
            )
        runBlocking { userRepository.setSelectedUserInfo(USER) }

        val settings by collectLastValue(underTest.settings)

        assertThat(settings).isNull()
    }

    @Test
    @EnableFlags(SysUiFlags.FLAG_HSU_QS_CHANGES)
    fun settingsButton_showWhenNotHeadlessSystemUser() = runTest {
        val fakeHsum = HeadlessSystemUserModeFake()
        fakeHsum.setIsHeadlessSystemUser(false)
        val underTest =
            utils.footerActionsViewModel(
                showPowerButton = false,
                hsum = fakeHsum,
                selectedUserInteractor = selectedUserInteractor,
            )
        runBlocking { userRepository.setSelectedUserInfo(USER) }

        val settings by collectLastValue(underTest.settings)

        assertThat(settings).isNotNull()
    }

    @Test
    fun powerButton() = runTest {
        // Without power button.
@@ -543,6 +597,9 @@ class FooterActionsViewModelTest : SysuiTestCase() {
    companion object {
        val AIRPLANE_MODE_TILE_SPEC = TileSpec.create(ConnectivityModule.AIRPLANE_MODE_TILE_SPEC)

        private val USER = UserInfo(UserHandle.USER_SYSTEM, "system_user", 0)
        private val USER_INFOS = listOf(USER)

        private fun createAndPopulateQsTileConfigProvider(): QSTileConfigProvider {
            val logger =
                QsEventLoggerFake(UiEventLoggerFake(), InstanceIdSequenceFake(Int.MAX_VALUE))
+55 −0
Original line number Diff line number Diff line
@@ -16,8 +16,13 @@

package com.android.systemui.qs.panels.ui.viewmodel.toolbar

import android.content.pm.UserInfo
import android.os.UserHandle
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.Flags.FLAG_HSU_QS_CHANGES
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.kosmos.Kosmos
@@ -31,6 +36,10 @@ import com.android.systemui.qs.footer.domain.model.SecurityButtonConfig
import com.android.systemui.qs.footerActionsInteractor
import com.android.systemui.res.R
import com.android.systemui.testKosmos
import com.android.systemui.user.data.model.SelectedUserModel
import com.android.systemui.user.data.model.SelectionStatus
import com.android.systemui.user.data.repository.fakeUserRepository
import com.android.systemui.user.domain.interactor.fakeHeadlessSystemUserMode
import com.google.common.truth.Truth.assertThat
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.seconds
@@ -152,11 +161,57 @@ class ToolbarViewModelTest : SysuiTestCase() {
            }
        }

    @Test
    @DisableFlags(FLAG_HSU_QS_CHANGES)
    fun settingsButton_isNotNullWithFlagDisabled() =
        with(kosmos) {
            runTest {
                selectSystemUser()

                assertThat(underTest.settingsButtonViewModel).isNotNull()
            }
        }

    @Test
    @EnableFlags(FLAG_HSU_QS_CHANGES)
    fun settingsButton_hideForHeadlessSystemUser() =
        with(kosmos) {
            runTest {
                fakeHeadlessSystemUserMode.setIsHeadlessSystemUser(true)

                selectSystemUser()

                assertThat(underTest.settingsButtonViewModel).isNull()
            }
        }

    @Test
    @EnableFlags(FLAG_HSU_QS_CHANGES)
    fun settingsButton_showWhenNotHeadlessSystemUser() =
        with(kosmos) {
            runTest {
                fakeHeadlessSystemUserMode.setIsHeadlessSystemUser(false)

                selectSystemUser()

                assertThat(underTest.settingsButtonViewModel).isNotNull()
            }
        }

    private fun Kosmos.setSecurityConfig(config: SecurityButtonConfig?) {
        footerActionsInteractor.fake.setSecurityConfig(config)
        runCurrent()
    }

    private fun Kosmos.selectSystemUser() {
        kosmos.fakeUserRepository.selectedUser.value =
            SelectedUserModel(
                userInfo = UserInfo(UserHandle.USER_SYSTEM, "system_user", 0),
                selectionStatus = SelectionStatus.SELECTION_COMPLETE,
            )
        runCurrent()
    }

    private companion object {
        val MANAGED_CONFIG =
            SecurityButtonConfig(
+20 −2
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleCoroutineScope
import androidx.lifecycle.LifecycleOwner
import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.Flags.hsuQsChanges
import com.android.systemui.animation.Expandable
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
@@ -45,6 +46,8 @@ import com.android.systemui.qs.panels.ui.viewmodel.TextFeedbackContentViewModel.
import com.android.systemui.qs.panels.ui.viewmodel.TextFeedbackViewModel
import com.android.systemui.res.R
import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.user.domain.interactor.HeadlessSystemUserMode
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.icuMessageFormat
import javax.inject.Inject
import javax.inject.Named
@@ -76,7 +79,7 @@ class FooterActionsViewModel(
    val userSwitcher: Flow<FooterActionsButtonViewModel?>,

    /** The model for the settings button. */
    val settings: FooterActionsButtonViewModel,
    val settings: Flow<FooterActionsButtonViewModel?>,

    /** The model for the power button. */
    val power: FooterActionsButtonViewModel?,
@@ -128,6 +131,8 @@ class FooterActionsViewModel(
        private val globalActionsDialogLiteProvider: Provider<GlobalActionsDialogLite>,
        private val activityStarter: ActivityStarter,
        private val textFeedbackInteractor: TextFeedbackInteractor,
        private val selectedUserInteractor: SelectedUserInteractor,
        private val hsum: HeadlessSystemUserMode,
        @Named(PM_LITE_ENABLED) private val showPowerButton: Boolean,
    ) {
        /** Create a [FooterActionsViewModel] bound to the lifecycle of [lifecycleOwner]. */
@@ -156,6 +161,8 @@ class FooterActionsViewModel(
                globalActionsDialogLite,
                activityStarter,
                showPowerButton,
                selectedUserInteractor,
                hsum,
            )
        }

@@ -181,6 +188,8 @@ class FooterActionsViewModel(
                globalActionsDialogLite,
                activityStarter,
                showPowerButton,
                selectedUserInteractor,
                hsum,
            )
        }
    }
@@ -194,6 +203,8 @@ fun createFooterActionsViewModel(
    globalActionsDialogLite: GlobalActionsDialogLite,
    activityStarter: ActivityStarter,
    showPowerButton: Boolean,
    selectedUserInteractor: SelectedUserInteractor,
    hsum: HeadlessSystemUserMode,
): FooterActionsViewModel {
    suspend fun observeDeviceMonitoringDialogRequests(quickSettingsContext: Context) {
        footerActionsInteractor.deviceMonitoringDialogRequests.collect {
@@ -285,7 +296,14 @@ fun createFooterActionsViewModel(
    val userSwitcher =
        userSwitcherViewModel(qsThemedContext, footerActionsInteractor, ::onUserSwitcherClicked)

    val settings = SettingsActionViewModel(qsThemedContext, ::onSettingsButtonClicked)
    val settings =
        selectedUserInteractor.selectedUser
            .map { selectedUserId ->
                SettingsActionViewModel(qsThemedContext, ::onSettingsButtonClicked).takeUnless {
                    hsuQsChanges() && hsum.isHeadlessSystemUser(selectedUserId)
                }
            }
            .distinctUntilChanged()

    val power =
        if (showPowerButton) {
+17 −3
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.view.ContextThemeWrapper
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import com.android.systemui.Flags.hsuQsChanges
import com.android.systemui.animation.Expandable
import com.android.systemui.classifier.domain.interactor.FalsingInteractor
import com.android.systemui.classifier.domain.interactor.runIfNotFalseTap
@@ -38,6 +39,8 @@ import com.android.systemui.qs.footer.ui.viewmodel.userSwitcherViewModel
import com.android.systemui.qs.panels.ui.viewmodel.TextFeedbackContentViewModel
import com.android.systemui.res.R
import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.user.domain.interactor.HeadlessSystemUserMode
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import javax.inject.Provider
@@ -59,6 +62,8 @@ constructor(
    private val footerActionsInteractor: FooterActionsInteractor,
    private val globalActionsDialogLiteProvider: Provider<GlobalActionsDialogLite>,
    private val falsingInteractor: FalsingInteractor,
    private val selectedUserInteractor: SelectedUserInteractor,
    private val hsum: HeadlessSystemUserMode,
    @ShadeDisplayAware appContext: Context,
    @Main private val mainDispatcher: CoroutineDispatcher,
) : ExclusiveActivatable() {
@@ -69,9 +74,6 @@ constructor(
    val powerButtonViewModel: FooterActionsButtonViewModel =
        PowerActionViewModel(context = qsThemedContext, onClick = ::onPowerButtonClicked)

    val settingsButtonViewModel =
        SettingsActionViewModel(qsThemedContext, ::onSettingsButtonClicked)

    val userSwitcherViewModel: FooterActionsButtonViewModel? by
        hydrator.hydratedStateOf(
            traceName = "userSwitcherViewModel",
@@ -84,6 +86,18 @@ constructor(
                ),
        )

    val settingsButtonViewModel: FooterActionsButtonViewModel? by
        hydrator.hydratedStateOf(
            traceName = "settingsButtonViewModel",
            initialValue = null,
            source =
                selectedUserInteractor.selectedUser.map { selectedUserId ->
                    SettingsActionViewModel(qsThemedContext, ::onSettingsButtonClicked).takeUnless {
                        hsuQsChanges() && hsum.isHeadlessSystemUser(selectedUserId)
                    }
                },
        )

    var securityInfoViewModel: FooterActionsSecurityButtonViewModel? by mutableStateOf(null)
        private set

Loading