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

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

Merge "[Dual Shade] Separate composables for the toolbar buttons + refactoring." into main

parents caf2c00b bccf745e
Loading
Loading
Loading
Loading
+44 −32
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import androidx.compose.material3.Icon
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 @@ fun FooterActions(
        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 @@ fun FooterActions(
            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 @@ fun FooterActions(
                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 @@ private fun RowScope.ForegroundServicesButton(

/** A button with an icon. */
@Composable
fun IconButton(
private fun IconButton(
    model: () -> FooterActionsButtonViewModel?,
    useModifierBasedExpandable: Boolean,
    modifier: Modifier = Modifier,
@@ -336,21 +339,16 @@ fun IconButton(

/** 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 @@ private fun NumberButton(
    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 @@ private fun NumberButton(
    }
}

@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 @@ private fun TextButton(
    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 numberButtonColors(): TextButtonColors {
private fun buttonColorsForModel(footerAction: FooterActionsButtonViewModel): ButtonColors {
    return if (QsInCompose.isEnabled && notificationShadeBlur()) {
        when (footerAction) {
            is FooterActionsButtonViewModel.PowerActionViewModel -> {
                if (footerAction.isOnDualShade) {
                    FooterActionsDefaults.inactiveButtonColors()
                } else {
            is FooterActionsButtonViewModel.PowerActionViewModel ->
                FooterActionsDefaults.activeButtonColors()
                }
            }
            is FooterActionsButtonViewModel.SettingsActionViewModel ->
                FooterActionsDefaults.inactiveButtonColors()
            is FooterActionsButtonViewModel.UserSwitcherViewModel ->
+1 −7
Original line number Diff line number Diff line
@@ -60,13 +60,7 @@ class FooterActionsInteractorTest : SysuiTestCase() {

    @Before
    fun setUp() {
        utils =
            FooterActionsTestUtils(
                context,
                TestableLooper.get(this),
                testScope.testScheduler,
                testScope.backgroundScope,
            )
        utils = FooterActionsTestUtils(context, TestableLooper.get(this), testScope.testScheduler)
    }

    @Test
+18 −37
Original line number Diff line number Diff line
@@ -48,7 +48,6 @@ import com.android.systemui.qs.tiles.base.shared.model.FakeQSTileConfigProvider
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 @@ class FooterActionsViewModelTest : SysuiTestCase() {

    @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 @@ class FooterActionsViewModelTest : SysuiTestCase() {

    @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 @@ class FooterActionsViewModelTest : SysuiTestCase() {
    @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 @@ class FooterActionsViewModelTest : SysuiTestCase() {
        val underTest =
            utils.footerActionsViewModel(
                showPowerButton = false,
                shadeMode = ShadeMode.Single,
                footerActionsInteractor =
                    utils.footerActionsInteractor(
                        userSwitcherRepository =
@@ -229,13 +217,12 @@ class FooterActionsViewModelTest : SysuiTestCase() {

        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 @@ class FooterActionsViewModelTest : SysuiTestCase() {

        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 @@ class FooterActionsViewModelTest : SysuiTestCase() {

        val underTest =
            utils.footerActionsViewModel(
                shadeMode = ShadeMode.Single,
                footerActionsInteractor =
                    utils.footerActionsInteractor(
                        qsSecurityFooterUtils = qsSecurityFooterUtils,
                        broadcastDispatcher = broadcastDispatcher,
                    ),
                    )
            )

        val job = launch { underTest.observeDeviceMonitoringDialogRequests(mock()) }
@@ -380,7 +365,7 @@ class FooterActionsViewModelTest : SysuiTestCase() {

    @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 @@ class FooterActionsViewModelTest : SysuiTestCase() {

    @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 @@ class FooterActionsViewModelTest : SysuiTestCase() {

    @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 @@ class FooterActionsViewModelTest : SysuiTestCase() {

    @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 @@ class FooterActionsViewModelTest : SysuiTestCase() {
        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 @@ class FooterActionsViewModelTest : SysuiTestCase() {
                        securityRepository = utils.securityRepository(securityController),
                        qsSecurityFooterUtils = qsSecurityFooterUtils,
                    ),
                shadeMode = ShadeMode.Single,
            )

        val textFeedback by collectLastValue(underTest.textFeedback)
+14 −7
Original line number Diff line number Diff line
@@ -18,7 +18,9 @@ package com.android.systemui.qs.footer.ui.viewmodel

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 @@ sealed interface FooterActionsButtonViewModel {

    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 @@ sealed interface FooterActionsButtonViewModel {
                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 @@ sealed interface FooterActionsButtonViewModel {
                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
    }
}
+11 −76
Original line number Diff line number Diff line
@@ -24,7 +24,6 @@ import androidx.lifecycle.Lifecycle
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.TextFeedbackContentViewModel.
import com.android.systemui.qs.panels.ui.viewmodel.TextFeedbackViewModel
import com.android.systemui.res.R
import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.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 @@ class FooterActionsViewModel(
    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 @@ class FooterActionsViewModel(
        @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 @@ class FooterActionsViewModel(
                context,
                footerActionsInteractor,
                textFeedbackInteractor,
                shadeModeInteractor.shadeMode,
                falsingManager,
                globalActionsDialogLite,
                activityStarter,
@@ -181,7 +177,6 @@ class FooterActionsViewModel(
                context,
                footerActionsInteractor,
                textFeedbackInteractor,
                shadeModeInteractor.shadeMode,
                falsingManager,
                globalActionsDialogLite,
                activityStarter,
@@ -195,7 +190,6 @@ fun createFooterActionsViewModel(
    @ShadeDisplayAware appContext: Context,
    footerActionsInteractor: FooterActionsInteractor,
    textFeedbackInteractor: TextFeedbackInteractor,
    shadeMode: StateFlow<ShadeMode>,
    falsingManager: FalsingManager,
    globalActionsDialogLite: GlobalActionsDialogLite,
    activityStarter: ActivityStarter,
@@ -291,13 +285,13 @@ fun createFooterActionsViewModel(
    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 @@ fun createFooterActionsViewModel(
        power = power,
        observeDeviceMonitoringDialogRequests = ::observeDeviceMonitoringDialogRequests,
        textFeedback = textFeedback,
        initialPower =
            if (showPowerButton) {
                { powerButtonViewModel(qsThemedContext, ::onPowerButtonClicked, shadeMode.value) }
            } else {
                { null }
            },
    )
}

@@ -396,65 +384,12 @@ fun userSwitcherButtonViewModel(
    onUserSwitcherClicked: (Expandable) -> Unit,
): FooterActionsButtonViewModel {
    val icon = status.currentUserImage!!
    return UserSwitcherViewModel(
        icon =
            Icon.Loaded(
                icon,
                ContentDescription.Loaded(
                    userSwitcherContentDescription(qsThemedContext, status.currentUserName)
                ),
            ),
        iconTintFallback = null,
        backgroundColorFallback = R.attr.shadeInactive,
        onClick = onUserSwitcherClicked,
    )
}

private fun userSwitcherContentDescription(
    qsThemedContext: Context,
    currentUser: String?,
): String? {
    return currentUser?.let { user ->
    val contentDescription =
        status.currentUserName?.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,
    return UserSwitcherViewModel(
        icon = Icon.Loaded(icon, ContentDescription.Loaded(contentDescription)),
        onClick = onUserSwitcherClicked,
    )
}
Loading