[Dual Shade] Separate composables for the toolbar buttons + refactoring.

This removes the background color for the buttons in Dual Shade, to
match the UX spec, and increases the size of the toolbar buttons in Dual
Shade to 24dp.

As a nice side effect, this simplifies the composables and view-models
of both the footer actions (non-Dual Shade) and the toolbar, and
consolidates color determination.

BONUS: Remove FooterActionsViewModel's and ToolbarViewModel's dependency
on the shade mode.

Fix: 415277314
Test: Manually tested by opening the QS shade and observing that the
 toolbar buttons are rendered without a background color.
Flag: com.android.systemui.scene_container
Change-Id: Iac68d38208689e0c3dae25503ff51b08cd6e3d33
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 27f819c..69c66c9 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
@@ -42,6 +42,7 @@
 import androidx.compose.material3.LocalContentColor
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Text
+import androidx.compose.material3.contentColorFor
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.LaunchedEffect
@@ -149,7 +150,6 @@
         mutableStateOf<FooterActionsForegroundServicesButtonViewModel?>(null)
     }
     var userSwitcher by remember { mutableStateOf<FooterActionsButtonViewModel?>(null) }
-    var power by remember { mutableStateOf(viewModel.initialPower()) }
 
     var textFeedback by remember {
         mutableStateOf<TextFeedbackViewModel>(TextFeedbackViewModel.NoFeedback)
@@ -174,7 +174,6 @@
             launch { viewModel.security.collect { security = it } }
             launch { viewModel.foregroundServices.collect { foregroundServices = it } }
             launch { viewModel.userSwitcher.collect { userSwitcher = it } }
-            launch { viewModel.power.collect { power = it } }
             launch { viewModel.textFeedback.collect { textFeedback = it } }
         }
     }
@@ -252,7 +251,11 @@
                 useModifierBasedExpandable,
                 Modifier.sysuiResTag("settings_button_container"),
             )
-            IconButton({ power }, useModifierBasedExpandable, Modifier.sysuiResTag("pm_lite"))
+            IconButton(
+                { viewModel.power },
+                useModifierBasedExpandable,
+                Modifier.sysuiResTag("pm_lite"),
+            )
         }
     }
 }
@@ -325,7 +328,7 @@
 
 /** A button with an icon. */
 @Composable
-fun IconButton(
+private fun IconButton(
     model: () -> FooterActionsButtonViewModel?,
     useModifierBasedExpandable: Boolean,
     modifier: Modifier = Modifier,
@@ -336,21 +339,16 @@
 
 /** A button with an icon. */
 @Composable
-fun IconButton(
+private fun IconButton(
     model: FooterActionsButtonViewModel,
     useModifierBasedExpandable: Boolean,
     modifier: Modifier = Modifier,
 ) {
     val colors = buttonColorsForModel(model)
-    Expandable(
+    CircleExpandable(
         color = colors.background,
-        shape = CircleShape,
         onClick = model.onClick,
-        modifier =
-            modifier.borderOnFocus(
-                color = MaterialTheme.colorScheme.secondary,
-                CornerSize(percent = 50),
-            ),
+        modifier = modifier,
         useModifierBasedImplementation = useModifierBasedExpandable,
     ) {
         FooterIcon(model.icon, Modifier.size(20.dp), colors.icon)
@@ -387,16 +385,11 @@
     val interactionSource = remember { MutableInteractionSource() }
 
     val colors = numberButtonColors()
-    Expandable(
+    CircleExpandable(
         color = colors.background,
-        shape = CircleShape,
         onClick = onClick,
         interactionSource = interactionSource,
-        modifier =
-            modifier.borderOnFocus(
-                color = MaterialTheme.colorScheme.secondary,
-                CornerSize(percent = 50),
-            ),
+        modifier = modifier,
         useModifierBasedImplementation = useModifierBasedExpandable,
     ) {
         Box(Modifier.size(40.dp)) {
@@ -426,6 +419,34 @@
     }
 }
 
+@Composable
+private fun CircleExpandable(
+    color: Color,
+    modifier: Modifier = Modifier,
+    contentColor: Color = contentColorFor(color),
+    borderStroke: BorderStroke? = null,
+    onClick: ((Expandable) -> Unit)? = null,
+    interactionSource: MutableInteractionSource? = null,
+    useModifierBasedImplementation: Boolean,
+    content: @Composable (Expandable) -> Unit,
+) {
+    Expandable(
+        color = color,
+        contentColor = contentColor,
+        borderStroke = borderStroke,
+        shape = CircleShape,
+        onClick = onClick,
+        interactionSource = interactionSource,
+        modifier =
+            modifier.borderOnFocus(
+                color = MaterialTheme.colorScheme.secondary,
+                cornerSize = CornerSize(percent = 50),
+            ),
+        useModifierBasedImplementation = useModifierBasedImplementation,
+        content = content,
+    )
+}
+
 /** A dot that indicates new changes. */
 @Composable
 private fun NewChangesDot(modifier: Modifier = Modifier) {
@@ -448,15 +469,11 @@
     modifier: Modifier = Modifier,
 ) {
     val colors = textButtonColors()
-    Expandable(
-        shape = CircleShape,
+    CircleExpandable(
         color = colors.background,
         contentColor = colors.content,
         borderStroke = colors.border,
-        modifier =
-            modifier
-                .padding(horizontal = 4.dp)
-                .borderOnFocus(color = MaterialTheme.colorScheme.secondary, CornerSize(50)),
+        modifier = modifier.padding(horizontal = 4.dp),
         onClick = onClick,
         useModifierBasedImplementation = useModifierBasedExpandable,
     ) {
@@ -522,13 +539,8 @@
 private fun buttonColorsForModel(footerAction: FooterActionsButtonViewModel): ButtonColors {
     return if (QsInCompose.isEnabled && notificationShadeBlur()) {
         when (footerAction) {
-            is FooterActionsButtonViewModel.PowerActionViewModel -> {
-                if (footerAction.isOnDualShade) {
-                    FooterActionsDefaults.inactiveButtonColors()
-                } else {
-                    FooterActionsDefaults.activeButtonColors()
-                }
-            }
+            is FooterActionsButtonViewModel.PowerActionViewModel ->
+                FooterActionsDefaults.activeButtonColors()
             is FooterActionsButtonViewModel.SettingsActionViewModel ->
                 FooterActionsDefaults.inactiveButtonColors()
             is FooterActionsButtonViewModel.UserSwitcherViewModel ->
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractorTest.kt
index 7cc53a6..4f61090 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractorTest.kt
@@ -60,13 +60,7 @@
 
     @Before
     fun setUp() {
-        utils =
-            FooterActionsTestUtils(
-                context,
-                TestableLooper.get(this),
-                testScope.testScheduler,
-                testScope.backgroundScope,
-            )
+        utils = FooterActionsTestUtils(context, TestableLooper.get(this), testScope.testScheduler)
     }
 
     @Test
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 4146fd2..77cc5b4b 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
@@ -48,7 +48,6 @@
 import com.android.systemui.qs.tiles.base.shared.model.QSTileConfigProvider
 import com.android.systemui.res.R
 import com.android.systemui.security.data.model.SecurityModel
-import com.android.systemui.shade.shared.model.ShadeMode
 import com.android.systemui.statusbar.connectivity.ConnectivityModule
 import com.android.systemui.statusbar.policy.FakeSecurityController
 import com.android.systemui.statusbar.policy.FakeUserInfoController
@@ -85,13 +84,7 @@
 
     @Before
     fun setUp() {
-        utils =
-            FooterActionsTestUtils(
-                context,
-                TestableLooper.get(this),
-                testScope.testScheduler,
-                testScope.backgroundScope,
-            )
+        utils = FooterActionsTestUtils(context, TestableLooper.get(this), testScope.testScheduler)
     }
 
     private fun runTest(block: suspend TestScope.() -> Unit) {
@@ -100,8 +93,7 @@
 
     @Test
     fun settingsButton() = runTest {
-        val underTest =
-            utils.footerActionsViewModel(showPowerButton = false, shadeMode = ShadeMode.Single)
+        val underTest = utils.footerActionsViewModel(showPowerButton = false)
         val settings = underTest.settings
 
         assertThat(settings.icon)
@@ -119,25 +111,22 @@
     @Test
     fun powerButton() = runTest {
         // Without power button.
-        val underTestWithoutPower =
-            utils.footerActionsViewModel(showPowerButton = false, shadeMode = ShadeMode.Single)
-        val withoutPower by collectLastValue(underTestWithoutPower.power)
-        assertThat(withoutPower).isNull()
+        val underTestWithoutPower = utils.footerActionsViewModel(showPowerButton = false)
+        assertThat(underTestWithoutPower.power).isNull()
 
         // With power button.
-        val underTestWithPower =
-            utils.footerActionsViewModel(showPowerButton = true, shadeMode = ShadeMode.Single)
-        val power by collectLastValue(underTestWithPower.power)
-        assertThat(power).isNotNull()
-        assertThat(checkNotNull(power).icon)
+        val underTestWithPower = utils.footerActionsViewModel(showPowerButton = true)
+        assertThat(underTestWithPower.power).isNotNull()
+        assertThat(checkNotNull(underTestWithPower.power).icon)
             .isEqualTo(
                 Icon.Resource(
                     R.drawable.ic_qs_footer_power,
                     ContentDescription.Resource(R.string.accessibility_quick_settings_power_menu),
                 )
             )
-        assertThat(checkNotNull(power).backgroundColorFallback).isEqualTo(R.attr.shadeActive)
-        assertThat(checkNotNull(power).iconTintFallback)
+        assertThat(checkNotNull(underTestWithPower.power).backgroundColorFallback)
+            .isEqualTo(R.attr.shadeActive)
+        assertThat(checkNotNull(underTestWithPower.power).iconTintFallback)
             .isEqualTo(Utils.getColorAttrDefaultColor(themedContext, R.attr.onShadeActive))
     }
 
@@ -159,7 +148,6 @@
         val underTest =
             utils.footerActionsViewModel(
                 showPowerButton = false,
-                shadeMode = ShadeMode.Single,
                 footerActionsInteractor =
                     utils.footerActionsInteractor(
                         userSwitcherRepository =
@@ -229,13 +217,12 @@
 
         val underTest =
             utils.footerActionsViewModel(
-                shadeMode = ShadeMode.Single,
                 footerActionsInteractor =
                     utils.footerActionsInteractor(
                         qsSecurityFooterUtils = qsSecurityFooterUtils,
                         securityRepository =
                             utils.securityRepository(securityController = securityController),
-                    ),
+                    )
             )
 
         // Collect the security model into currentSecurity.
@@ -288,14 +275,13 @@
 
         val underTest =
             utils.footerActionsViewModel(
-                shadeMode = ShadeMode.Single,
                 footerActionsInteractor =
                     utils.footerActionsInteractor(
                         qsSecurityFooterUtils = qsSecurityFooterUtils,
                         securityRepository = utils.securityRepository(securityController),
                         foregroundServicesRepository =
                             utils.foregroundServicesRepository(fgsManagerController),
-                    ),
+                    )
             )
 
         // Collect the security model into currentSecurity.
@@ -362,12 +348,11 @@
 
         val underTest =
             utils.footerActionsViewModel(
-                shadeMode = ShadeMode.Single,
                 footerActionsInteractor =
                     utils.footerActionsInteractor(
                         qsSecurityFooterUtils = qsSecurityFooterUtils,
                         broadcastDispatcher = broadcastDispatcher,
-                    ),
+                    )
             )
 
         val job = launch { underTest.observeDeviceMonitoringDialogRequests(mock()) }
@@ -380,7 +365,7 @@
 
     @Test
     fun alpha_inSplitShade_followsExpansion() {
-        val underTest = utils.footerActionsViewModel(shadeMode = ShadeMode.Split)
+        val underTest = utils.footerActionsViewModel()
 
         underTest.onQuickSettingsExpansionChanged(0f, isInSplitShade = true)
         assertThat(underTest.alpha.value).isEqualTo(0f)
@@ -400,7 +385,7 @@
 
     @Test
     fun backgroundAlpha_inSplitShade_followsExpansion_with_0_15_delay() {
-        val underTest = utils.footerActionsViewModel(shadeMode = ShadeMode.Split)
+        val underTest = utils.footerActionsViewModel()
         val floatTolerance = 0.01f
 
         underTest.onQuickSettingsExpansionChanged(0f, isInSplitShade = true)
@@ -424,7 +409,7 @@
 
     @Test
     fun alpha_inSingleShade_followsExpansion_with_0_9_delay() {
-        val underTest = utils.footerActionsViewModel(shadeMode = ShadeMode.Single)
+        val underTest = utils.footerActionsViewModel()
         val floatTolerance = 0.01f
 
         underTest.onQuickSettingsExpansionChanged(0f, isInSplitShade = false)
@@ -448,7 +433,7 @@
 
     @Test
     fun backgroundAlpha_inSingleShade_always1() {
-        val underTest = utils.footerActionsViewModel(shadeMode = ShadeMode.Single)
+        val underTest = utils.footerActionsViewModel()
 
         underTest.onQuickSettingsExpansionChanged(0f, isInSplitShade = false)
         assertThat(underTest.backgroundAlpha.value).isEqualTo(1f)
@@ -468,10 +453,7 @@
         val textFeedbackInteractor =
             utils.textFeedbackInteractor(qsTileConfigProvider = qsTileConfigProvider)
         val underTest =
-            utils.footerActionsViewModel(
-                textFeedbackInteractor = textFeedbackInteractor,
-                shadeMode = ShadeMode.Single,
-            )
+            utils.footerActionsViewModel(textFeedbackInteractor = textFeedbackInteractor)
 
         val textFeedback by collectLastValue(underTest.textFeedback)
 
@@ -518,7 +500,6 @@
                         securityRepository = utils.securityRepository(securityController),
                         qsSecurityFooterUtils = qsSecurityFooterUtils,
                     ),
-                shadeMode = ShadeMode.Single,
             )
 
         val textFeedback by collectLastValue(underTest.textFeedback)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsButtonViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsButtonViewModel.kt
index f6a6108..120808b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsButtonViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsButtonViewModel.kt
@@ -18,7 +18,9 @@
 
 import android.annotation.AttrRes
 import android.annotation.ColorInt
+import android.content.Context
 import androidx.compose.runtime.Stable
+import com.android.settingslib.Utils
 import com.android.systemui.animation.Expandable
 import com.android.systemui.common.shared.model.ContentDescription
 import com.android.systemui.common.shared.model.Icon
@@ -38,16 +40,15 @@
 
     data class UserSwitcherViewModel(
         override val icon: Icon,
-        @ColorInt override val iconTintFallback: Int?,
-        @AttrRes override val backgroundColorFallback: Int,
         override val onClick: (Expandable) -> Unit,
     ) : FooterActionsButtonViewModel {
         override val id: Int = R.id.multi_user_switch
+        @ColorInt override val iconTintFallback: Int? = null
+        @AttrRes override val backgroundColorFallback: Int = R.attr.shadeInactive
     }
 
     data class SettingsActionViewModel(
-        @ColorInt override val iconTintFallback: Int?,
-        @AttrRes override val backgroundColorFallback: Int,
+        private val context: Context,
         override val onClick: (Expandable) -> Unit,
     ) : FooterActionsButtonViewModel {
         override val id: Int = R.id.settings_button_container
@@ -56,12 +57,14 @@
                 R.drawable.ic_qs_footer_settings,
                 ContentDescription.Resource(R.string.accessibility_quick_settings_settings),
             )
+        @ColorInt
+        override val iconTintFallback: Int =
+            Utils.getColorAttrDefaultColor(context, R.attr.onShadeInactiveVariant)
+        @AttrRes override val backgroundColorFallback: Int = R.attr.shadeInactive
     }
 
     data class PowerActionViewModel(
-        val isOnDualShade: Boolean,
-        @ColorInt override val iconTintFallback: Int?,
-        @AttrRes override val backgroundColorFallback: Int,
+        private val context: Context,
         override val onClick: (Expandable) -> Unit,
     ) : FooterActionsButtonViewModel {
         override val id: Int = R.id.pm_lite
@@ -70,5 +73,9 @@
                 R.drawable.ic_qs_footer_power,
                 ContentDescription.Resource(R.string.accessibility_quick_settings_power_menu),
             )
+        @ColorInt
+        override val iconTintFallback: Int =
+            Utils.getColorAttrDefaultColor(context, R.attr.onShadeActive)
+        @AttrRes override val backgroundColorFallback: Int = R.attr.shadeActive
     }
 }
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 c1f4d56..f819a6d 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,7 +24,6 @@
 import androidx.lifecycle.LifecycleCoroutineScope
 import androidx.lifecycle.LifecycleOwner
 import com.android.app.tracing.coroutines.launchTraced as launch
-import com.android.settingslib.Utils
 import com.android.systemui.animation.Expandable
 import com.android.systemui.common.shared.model.ContentDescription
 import com.android.systemui.common.shared.model.Icon
@@ -46,8 +45,6 @@
 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.shade.domain.interactor.ShadeModeInteractor
-import com.android.systemui.shade.shared.model.ShadeMode
 import com.android.systemui.util.icuMessageFormat
 import javax.inject.Inject
 import javax.inject.Named
@@ -82,8 +79,9 @@
     val settings: FooterActionsButtonViewModel,
 
     /** The model for the power button. */
-    val power: Flow<FooterActionsButtonViewModel?>,
-    val initialPower: () -> FooterActionsButtonViewModel?,
+    val power: FooterActionsButtonViewModel?,
+
+    /** The model for the text feedback. */
     val textFeedback: Flow<TextFeedbackViewModel>,
 
     /**
@@ -127,7 +125,6 @@
         @ShadeDisplayAware private val context: Context,
         private val falsingManager: FalsingManager,
         private val footerActionsInteractor: FooterActionsInteractor,
-        private val shadeModeInteractor: ShadeModeInteractor,
         private val globalActionsDialogLiteProvider: Provider<GlobalActionsDialogLite>,
         private val activityStarter: ActivityStarter,
         private val textFeedbackInteractor: TextFeedbackInteractor,
@@ -155,7 +152,6 @@
                 context,
                 footerActionsInteractor,
                 textFeedbackInteractor,
-                shadeModeInteractor.shadeMode,
                 falsingManager,
                 globalActionsDialogLite,
                 activityStarter,
@@ -181,7 +177,6 @@
                 context,
                 footerActionsInteractor,
                 textFeedbackInteractor,
-                shadeModeInteractor.shadeMode,
                 falsingManager,
                 globalActionsDialogLite,
                 activityStarter,
@@ -195,7 +190,6 @@
     @ShadeDisplayAware appContext: Context,
     footerActionsInteractor: FooterActionsInteractor,
     textFeedbackInteractor: TextFeedbackInteractor,
-    shadeMode: StateFlow<ShadeMode>,
     falsingManager: FalsingManager,
     globalActionsDialogLite: GlobalActionsDialogLite,
     activityStarter: ActivityStarter,
@@ -291,13 +285,13 @@
     val userSwitcher =
         userSwitcherViewModel(qsThemedContext, footerActionsInteractor, ::onUserSwitcherClicked)
 
-    val settings = settingsButtonViewModel(qsThemedContext, ::onSettingsButtonClicked)
+    val settings = SettingsActionViewModel(qsThemedContext, ::onSettingsButtonClicked)
 
     val power =
         if (showPowerButton) {
-            powerButtonViewModel(qsThemedContext, ::onPowerButtonClicked, shadeMode)
+            PowerActionViewModel(qsThemedContext, ::onPowerButtonClicked)
         } else {
-            flowOf(null)
+            null
         }
 
     val textFeedback =
@@ -315,12 +309,6 @@
         power = power,
         observeDeviceMonitoringDialogRequests = ::observeDeviceMonitoringDialogRequests,
         textFeedback = textFeedback,
-        initialPower =
-            if (showPowerButton) {
-                { powerButtonViewModel(qsThemedContext, ::onPowerButtonClicked, shadeMode.value) }
-            } else {
-                { null }
-            },
     )
 }
 
@@ -396,65 +384,12 @@
     onUserSwitcherClicked: (Expandable) -> Unit,
 ): FooterActionsButtonViewModel {
     val icon = status.currentUserImage!!
+    val contentDescription =
+        status.currentUserName?.let { user ->
+            qsThemedContext.getString(R.string.accessibility_quick_settings_user, user)
+        }
     return UserSwitcherViewModel(
-        icon =
-            Icon.Loaded(
-                icon,
-                ContentDescription.Loaded(
-                    userSwitcherContentDescription(qsThemedContext, status.currentUserName)
-                ),
-            ),
-        iconTintFallback = null,
-        backgroundColorFallback = R.attr.shadeInactive,
+        icon = Icon.Loaded(icon, ContentDescription.Loaded(contentDescription)),
         onClick = onUserSwitcherClicked,
     )
 }
-
-private fun userSwitcherContentDescription(
-    qsThemedContext: Context,
-    currentUser: String?,
-): String? {
-    return currentUser?.let { user ->
-        qsThemedContext.getString(R.string.accessibility_quick_settings_user, user)
-    }
-}
-
-fun settingsButtonViewModel(
-    qsThemedContext: Context,
-    onSettingsButtonClicked: (Expandable) -> Unit,
-): FooterActionsButtonViewModel {
-    return SettingsActionViewModel(
-        iconTintFallback =
-            Utils.getColorAttrDefaultColor(qsThemedContext, R.attr.onShadeInactiveVariant),
-        backgroundColorFallback = R.attr.shadeInactive,
-        onClick = onSettingsButtonClicked,
-    )
-}
-
-fun powerButtonViewModel(
-    qsThemedContext: Context,
-    onPowerButtonClicked: (Expandable) -> Unit,
-    shadeMode: Flow<ShadeMode>,
-): Flow<FooterActionsButtonViewModel?> {
-    return shadeMode.map { mode ->
-        powerButtonViewModel(qsThemedContext, onPowerButtonClicked, mode)
-    }
-}
-
-fun powerButtonViewModel(
-    qsThemedContext: Context,
-    onPowerButtonClicked: (Expandable) -> Unit,
-    shadeMode: ShadeMode,
-): FooterActionsButtonViewModel {
-    val isDualShade = shadeMode is ShadeMode.Dual
-    return PowerActionViewModel(
-        isOnDualShade = isDualShade,
-        iconTintFallback =
-            Utils.getColorAttrDefaultColor(
-                qsThemedContext,
-                if (isDualShade) R.attr.onShadeInactiveVariant else R.attr.onShadeActive,
-            ),
-        backgroundColorFallback = if (isDualShade) R.attr.shadeInactive else R.attr.shadeActive,
-        onClick = onPowerButtonClicked,
-    )
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/toolbar/Toolbar.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/toolbar/Toolbar.kt
index b4b4e8a8..ce1d555 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/toolbar/Toolbar.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/toolbar/Toolbar.kt
@@ -24,20 +24,34 @@
 import androidx.compose.animation.SharedTransitionScope
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.foundation.shape.CornerSize
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.minimumInteractiveComponentSize
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.asImageBitmap
 import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.unit.dp
+import androidx.core.graphics.drawable.toBitmap
+import com.android.compose.animation.Expandable
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.common.ui.compose.load
 import com.android.systemui.compose.modifiers.sysuiResTag
 import com.android.systemui.development.ui.compose.BuildNumber
 import com.android.systemui.development.ui.viewmodel.BuildNumberViewModel
 import com.android.systemui.lifecycle.rememberViewModel
-import com.android.systemui.qs.footer.ui.compose.IconButton
+import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsButtonViewModel
 import com.android.systemui.qs.panels.ui.compose.toolbar.Toolbar.TransitionKeys.SecurityInfoKey
 import com.android.systemui.qs.panels.ui.viewmodel.TextFeedbackContentViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.TextFeedbackViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.toolbar.ToolbarViewModel
+import com.android.systemui.qs.ui.compose.borderOnFocus
 
 @OptIn(ExperimentalSharedTransitionApi::class)
 @Composable
@@ -73,8 +87,7 @@
         }
 
         IconButton(
-            { viewModel.powerButtonViewModel },
-            useModifierBasedExpandable = true,
+            viewModel.powerButtonViewModel,
             Modifier.sysuiResTag("pm_lite").minimumInteractiveComponentSize(),
         )
     }
@@ -90,9 +103,9 @@
     Row(modifier) {
         // User switcher button
         IconButton(
-            model = { viewModel.userSwitcherViewModel },
-            useModifierBasedExpandable = true,
+            model = viewModel.userSwitcherViewModel,
             Modifier.sysuiResTag("multi_user_switch").minimumInteractiveComponentSize(),
+            iconColor = Color.Unspecified,
         )
 
         // Edit mode button
@@ -104,7 +117,6 @@
         // Settings button
         IconButton(
             model = viewModel.settingsButtonViewModel,
-            useModifierBasedExpandable = true,
             Modifier.sysuiResTag("settings_button_container").minimumInteractiveComponentSize(),
         )
 
@@ -128,6 +140,39 @@
     }
 }
 
+/** A button with an icon. */
+@Composable
+private fun IconButton(
+    model: FooterActionsButtonViewModel?,
+    modifier: Modifier = Modifier,
+    iconColor: Color = MaterialTheme.colorScheme.onSurface,
+) {
+    if (model == null) {
+        return
+    }
+    Expandable(
+        color = Color.Unspecified,
+        shape = CircleShape,
+        onClick = model.onClick,
+        modifier =
+            modifier.borderOnFocus(MaterialTheme.colorScheme.secondary, CornerSize(percent = 50)),
+        useModifierBasedImplementation = true,
+    ) {
+        ToolbarIcon(icon = model.icon, modifier = Modifier.size(24.dp), tint = iconColor)
+    }
+}
+
+// TODO(b/394738023): Use com.android.systemui.common.ui.compose.Icon instead.
+@Composable
+private fun ToolbarIcon(icon: Icon, modifier: Modifier = Modifier, tint: Color) {
+    val contentDescription = icon.contentDescription?.load()
+    when (icon) {
+        is Icon.Loaded ->
+            Icon(icon.drawable.toBitmap().asImageBitmap(), contentDescription, modifier, tint)
+        is Icon.Resource -> Icon(painterResource(icon.res), contentDescription, modifier, tint)
+    }
+}
+
 @Composable
 private fun ToolbarTextFeedback(
     viewModelFactory: TextFeedbackContentViewModel.Factory,
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 df22d9b..eb6e3e1 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
@@ -30,15 +30,14 @@
 import com.android.systemui.lifecycle.Hydrator
 import com.android.systemui.qs.footer.domain.interactor.FooterActionsInteractor
 import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsButtonViewModel
+import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsButtonViewModel.PowerActionViewModel
+import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsButtonViewModel.SettingsActionViewModel
 import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsSecurityButtonViewModel
-import com.android.systemui.qs.footer.ui.viewmodel.powerButtonViewModel
 import com.android.systemui.qs.footer.ui.viewmodel.securityButtonViewModel
-import com.android.systemui.qs.footer.ui.viewmodel.settingsButtonViewModel
 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.shade.domain.interactor.ShadeModeInteractor
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import javax.inject.Provider
@@ -60,27 +59,17 @@
     private val footerActionsInteractor: FooterActionsInteractor,
     private val globalActionsDialogLiteProvider: Provider<GlobalActionsDialogLite>,
     private val falsingInteractor: FalsingInteractor,
-    shadeModeInteractor: ShadeModeInteractor,
     @ShadeDisplayAware appContext: Context,
 ) : ExclusiveActivatable() {
     private val qsThemedContext =
         ContextThemeWrapper(appContext, R.style.Theme_SystemUI_QuickSettings)
     private val hydrator = Hydrator("ToolbarViewModel.hydrator")
 
-    val powerButtonViewModel: FooterActionsButtonViewModel? by
-        hydrator.hydratedStateOf(
-            traceName = "powerButtonViewModel",
-            initialValue = null,
-            source =
-                powerButtonViewModel(
-                    qsThemedContext,
-                    ::onPowerButtonClicked,
-                    shadeModeInteractor.shadeMode,
-                ),
-        )
+    val powerButtonViewModel: FooterActionsButtonViewModel =
+        PowerActionViewModel(context = qsThemedContext, onClick = ::onPowerButtonClicked)
 
     val settingsButtonViewModel =
-        settingsButtonViewModel(qsThemedContext, ::onSettingsButtonClicked)
+        SettingsActionViewModel(qsThemedContext, ::onSettingsButtonClicked)
 
     val userSwitcherViewModel: FooterActionsButtonViewModel? by
         hydrator.hydratedStateOf(
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 ddb8ae5..697e8d0 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
@@ -43,7 +43,6 @@
 import com.android.systemui.security.data.repository.securityRepository
 import com.android.systemui.settings.userTracker
 import com.android.systemui.shade.data.repository.shadeDialogContextInteractor
-import com.android.systemui.shade.domain.interactor.shadeModeInteractor
 import com.android.systemui.statusbar.policy.deviceProvisionedController
 import com.android.systemui.statusbar.policy.securityController
 import com.android.systemui.user.data.repository.userSwitcherRepository
@@ -103,7 +102,6 @@
         context = applicationContext,
         falsingManager = falsingManager,
         footerActionsInteractor = footerActionsInteractor,
-        shadeModeInteractor = shadeModeInteractor,
         globalActionsDialogLiteProvider = { mock() },
         activityStarter = activityStarter,
         textFeedbackInteractor = textFeedbackInteractor,
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 c90f2df..6284261 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
@@ -50,7 +50,6 @@
 import com.android.systemui.security.data.repository.SecurityRepositoryImpl
 import com.android.systemui.settings.FakeUserTracker
 import com.android.systemui.settings.UserTracker
-import com.android.systemui.shade.shared.model.ShadeMode
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
 import com.android.systemui.statusbar.policy.FakeSecurityController
 import com.android.systemui.statusbar.policy.FakeUserInfoController
@@ -66,8 +65,6 @@
 import com.android.systemui.util.settings.FakeGlobalSettings
 import com.android.systemui.util.settings.GlobalSettings
 import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.test.StandardTestDispatcher
 import kotlinx.coroutines.test.TestCoroutineScheduler
 
@@ -79,7 +76,6 @@
     private val context: Context,
     private val testableLooper: TestableLooper,
     private val scheduler: TestCoroutineScheduler,
-    private val applicationCoroutineScope: CoroutineScope,
 ) {
     private val mockActivityStarter: ActivityStarter = mock<ActivityStarter>()
 
@@ -100,13 +96,11 @@
         falsingManager: FalsingManager = FalsingManagerFake(),
         globalActionsDialogLite: GlobalActionsDialogLite = mock(),
         showPowerButton: Boolean = true,
-        shadeMode: ShadeMode,
     ): FooterActionsViewModel {
         return createFooterActionsViewModel(
             context,
             footerActionsInteractor,
             textFeedbackInteractor,
-            MutableStateFlow(shadeMode),
             falsingManager,
             globalActionsDialogLite,
             mockActivityStarter,
@@ -185,7 +179,7 @@
         )
     }
 
-    fun toggleTextFeedbackRepository(): ToggleTextFeedbackRepository {
+    private fun toggleTextFeedbackRepository(): ToggleTextFeedbackRepository {
         return ToggleTextFeedbackRepository()
     }
 
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 b97e7eb..5120d97 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,7 +23,6 @@
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.qs.footerActionsInteractor
 import com.android.systemui.qs.panels.ui.viewmodel.textFeedbackContentViewModelFactory
-import com.android.systemui.shade.domain.interactor.shadeModeInteractor
 
 val Kosmos.toolbarViewModelFactory by
     Kosmos.Fixture {
@@ -36,7 +35,6 @@
                     footerActionsInteractor,
                     { globalActionsDialogLite },
                     falsingInteractor,
-                    shadeModeInteractor,
                     applicationContext,
                 )
             }