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,
                 )