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