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

Commit 74188925 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Disable QS settings button for headless system user" into main

parents 59e5ecb6 fa3dceee
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