Disable QS settings button for headless system user
Bug: 408067114
Test: atest FooterActionsViewModelTest ToolbarViewModelTest
Flag: com.android.systemui.hsu_qs_changes
Change-Id: Id0807abd72ad137e57755d2f7e0cf3249885ce87
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt
index 7b03c98..cba11c8 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt
@@ -156,6 +156,7 @@
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 @@
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 @@
Modifier.sysuiResTag("multi_user_switch"),
)
IconButton(
- { viewModel.settings },
+ { settings },
useModifierBasedExpandable,
Modifier.sysuiResTag("settings_button_container"),
)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
index 001ba98..0ea8633 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
@@ -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 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.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 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 @@
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 @@
@Before
fun setUp() {
utils = FooterActionsTestUtils(context, TestableLooper.get(this), testScope.testScheduler)
+ userRepository.setUserInfos(USER_INFOS)
}
private fun runTest(block: suspend TestScope.() -> Unit) {
@@ -94,23 +104,67 @@
}
@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) }
- assertThat(settings.icon)
+ val settings by collectLastValue(underTest.settings)
+
+ 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.
val underTestWithoutPower = utils.footerActionsViewModel(showPowerButton = false)
@@ -543,6 +597,9 @@
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))
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModelTest.kt
index b009294..b0fcaab 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModelTest.kt
@@ -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.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 @@
}
}
+ @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(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
index 5881aa4..53a865e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
@@ -24,6 +24,7 @@
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.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 @@
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 @@
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 @@
globalActionsDialogLite,
activityStarter,
showPowerButton,
+ selectedUserInteractor,
+ hsum,
)
}
@@ -181,6 +188,8 @@
globalActionsDialogLite,
activityStarter,
showPowerButton,
+ selectedUserInteractor,
+ hsum,
)
}
}
@@ -194,6 +203,8 @@
globalActionsDialogLite: GlobalActionsDialogLite,
activityStarter: ActivityStarter,
showPowerButton: Boolean,
+ selectedUserInteractor: SelectedUserInteractor,
+ hsum: HeadlessSystemUserMode,
): FooterActionsViewModel {
suspend fun observeDeviceMonitoringDialogRequests(quickSettingsContext: Context) {
footerActionsInteractor.deviceMonitoringDialogRequests.collect {
@@ -285,7 +296,14 @@
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) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModel.kt
index 1729734..1ebd4fb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModel.kt
@@ -21,6 +21,7 @@
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.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 @@
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 @@
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 @@
),
)
+ 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
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/QuickSettingsKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/QuickSettingsKosmos.kt
index 1a33566..b022534 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/QuickSettingsKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/QuickSettingsKosmos.kt
@@ -47,6 +47,8 @@
import com.android.systemui.statusbar.policy.securityController
import com.android.systemui.supervision.data.repository.supervisionRepository
import com.android.systemui.user.data.repository.userSwitcherRepository
+import com.android.systemui.user.domain.interactor.headlessSystemUserMode
+import com.android.systemui.user.domain.interactor.selectedUserInteractor
import com.android.systemui.user.domain.interactor.userSwitcherInteractor
import com.android.systemui.util.mockito.mock
@@ -108,6 +110,8 @@
activityStarter = activityStarter,
textFeedbackInteractor = textFeedbackInteractor,
showPowerButton = true,
+ selectedUserInteractor = selectedUserInteractor,
+ hsum = headlessSystemUserMode,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/footer/FooterActionsTestUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/footer/FooterActionsTestUtils.kt
index d8c6a07..b67f447 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/footer/FooterActionsTestUtils.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/footer/FooterActionsTestUtils.kt
@@ -65,6 +65,8 @@
import com.android.systemui.user.data.repository.UserRepository
import com.android.systemui.user.data.repository.UserSwitcherRepository
import com.android.systemui.user.data.repository.UserSwitcherRepositoryImpl
+import com.android.systemui.user.domain.interactor.HeadlessSystemUserMode
+import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.user.domain.interactor.UserSwitcherInteractor
import com.android.systemui.util.settings.FakeGlobalSettings
import com.android.systemui.util.settings.GlobalSettings
@@ -101,6 +103,8 @@
falsingManager: FalsingManager = FalsingManagerFake(),
globalActionsDialogLite: GlobalActionsDialogLite = mock(),
showPowerButton: Boolean = true,
+ selectedUserInteractor: SelectedUserInteractor = mock(),
+ hsum: HeadlessSystemUserMode = mock(),
): FooterActionsViewModel {
return createFooterActionsViewModel(
context,
@@ -110,6 +114,8 @@
globalActionsDialogLite,
mockActivityStarter,
showPowerButton,
+ selectedUserInteractor,
+ hsum,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModelKosmos.kt
index c4d51da..4602320 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModelKosmos.kt
@@ -23,6 +23,8 @@
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.qs.footerActionsInteractor
import com.android.systemui.qs.panels.ui.viewmodel.textFeedbackContentViewModelFactory
+import com.android.systemui.user.domain.interactor.fakeHeadlessSystemUserMode
+import com.android.systemui.user.domain.interactor.selectedUserInteractor
val Kosmos.toolbarViewModelFactory by
Kosmos.Fixture {
@@ -34,6 +36,8 @@
footerActionsInteractor,
{ globalActionsDialogLite },
falsingInteractor,
+ selectedUserInteractor,
+ fakeHeadlessSystemUserMode,
applicationContext,
testDispatcher,
)