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

Commit e7ba2085 authored by Matías Hernández's avatar Matías Hernández Committed by Android (Google) Code Review
Browse files

Merge "Add on/off state description to mode tile toggles." into main

parents 2f426237 43dac35e
Loading
Loading
Loading
Loading
+77 −0
Original line number Diff line number Diff line
@@ -329,6 +329,83 @@ class ModesDialogViewModelTest : SysuiTestCase() {
            assertThat(tiles!![5].subtext).isEqualTo("Set up")
        }

    @Test
    fun tiles_populatesFieldsForAccessibility() =
        testScope.runTest {
            val tiles by collectLastValue(underTest.tiles)

            repository.addModes(
                listOf(
                    TestModeBuilder()
                        .setName("With description, inactive")
                        .setManualInvocationAllowed(true)
                        .setTriggerDescription("When the going gets tough")
                        .setActive(false)
                        .build(),
                    TestModeBuilder()
                        .setName("With description, active")
                        .setManualInvocationAllowed(true)
                        .setTriggerDescription("When in Rome")
                        .setActive(true)
                        .build(),
                    TestModeBuilder()
                        .setName("With description, needs setup")
                        .setManualInvocationAllowed(true)
                        .setTriggerDescription("When you find yourself in a hole")
                        .setEnabled(false, /* byUser= */ false)
                        .build(),
                    TestModeBuilder()
                        .setName("Without description, inactive")
                        .setManualInvocationAllowed(true)
                        .setTriggerDescription(null)
                        .setActive(false)
                        .build(),
                    TestModeBuilder()
                        .setName("Without description, active")
                        .setManualInvocationAllowed(true)
                        .setTriggerDescription(null)
                        .setActive(true)
                        .build(),
                    TestModeBuilder()
                        .setName("Without description, needs setup")
                        .setManualInvocationAllowed(true)
                        .setTriggerDescription(null)
                        .setEnabled(false, /* byUser= */ false)
                        .build(),
                )
            )
            runCurrent()

            assertThat(tiles!!).hasSize(6)
            with(tiles?.elementAt(0)!!) {
                assertThat(this.stateDescription).isEqualTo("Off")
                assertThat(this.subtextDescription).isEqualTo("When the going gets tough")
            }
            with(tiles?.elementAt(1)!!) {
                assertThat(this.stateDescription).isEqualTo("On")
                assertThat(this.subtextDescription).isEqualTo("When in Rome")
            }
            with(tiles?.elementAt(2)!!) {
                assertThat(this.stateDescription).isEqualTo("Off")
                assertThat(this.subtextDescription).isEqualTo("Set up")
            }
            with(tiles?.elementAt(3)!!) {
                assertThat(this.stateDescription).isEqualTo("Off")
                assertThat(this.subtextDescription).isEmpty()
            }
            with(tiles?.elementAt(4)!!) {
                assertThat(this.stateDescription).isEqualTo("On")
                assertThat(this.subtextDescription).isEmpty()
            }
            with(tiles?.elementAt(5)!!) {
                assertThat(this.stateDescription).isEqualTo("Off")
                assertThat(this.subtextDescription).isEqualTo("Set up")
            }

            // All tiles have the same long click info
            tiles!!.forEach { assertThat(it.onLongClickLabel).isEqualTo("Open settings") }
        }

    @Test
    fun onClick_togglesTileState() =
        testScope.runTest {
+12 −3
Original line number Diff line number Diff line
@@ -33,6 +33,10 @@ import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.semantics.clearAndSetSemantics
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.stateDescription
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.android.systemui.common.ui.compose.Icon
@@ -56,9 +60,11 @@ fun ModeTile(viewModel: ModeTileViewModel) {
                modifier =
                    Modifier.combinedClickable(
                            onClick = viewModel.onClick,
                            onLongClick = viewModel.onLongClick
                            onLongClick = viewModel.onLongClick,
                            onLongClickLabel = viewModel.onLongClickLabel
                        )
                        .padding(20.dp),
                        .padding(20.dp)
                        .semantics { stateDescription = viewModel.stateDescription },
                verticalAlignment = Alignment.CenterVertically,
                horizontalArrangement =
                    Arrangement.spacedBy(
@@ -76,7 +82,10 @@ fun ModeTile(viewModel: ModeTileViewModel) {
                    Text(
                        viewModel.subtext,
                        fontWeight = FontWeight.W400,
                        modifier = Modifier.tileMarquee().testTag("state")
                        modifier =
                            Modifier.tileMarquee().testTag("state").clearAndSetSemantics {
                                contentDescription = viewModel.subtextDescription
                            }
                    )
                }
            }
+3 −0
Original line number Diff line number Diff line
@@ -28,7 +28,10 @@ data class ModeTileViewModel(
    val icon: Icon,
    val text: String,
    val subtext: String,
    val subtextDescription: String, // version of subtext without "on"/"off" for screen readers
    val enabled: Boolean,
    val stateDescription: String, // "on"/"off" state of the tile, for screen readers
    val onClick: () -> Unit,
    val onLongClick: () -> Unit,
    val onLongClickLabel: String, // for screen readers
)
+26 −6
Original line number Diff line number Diff line
@@ -92,7 +92,12 @@ constructor(
                        icon = zenModeInteractor.getModeIcon(mode).drawable().asIcon(),
                        text = mode.name,
                        subtext = getTileSubtext(mode),
                        subtextDescription = getModeDescription(mode) ?: "",
                        enabled = mode.isActive,
                        stateDescription =
                            context.getString(
                                if (mode.isActive) R.string.zen_mode_on else R.string.zen_mode_off
                            ),
                        onClick = {
                            if (!mode.rule.isEnabled) {
                                openSettings(mode)
@@ -113,7 +118,9 @@ constructor(
                                }
                            }
                        },
                        onLongClick = { openSettings(mode) }
                        onLongClick = { openSettings(mode) },
                        onLongClickLabel =
                            context.resources.getString(R.string.accessibility_long_click_tile)
                    )
                }
            }
@@ -128,23 +135,36 @@ constructor(
        dialogDelegate.launchFromDialog(intent)
    }

    private fun getTileSubtext(mode: ZenMode): String {
    /**
     * Returns a description of the mode, which is:
     *   * a prompt to set up the mode if it is not enabled
     *   * if it cannot be manually activated, text that says so
     *   * otherwise, the trigger description of the mode if it exists...
     *   * ...or null if it doesn't
     *
     * This description is used directly for the content description of a mode tile for screen
     * readers, and for the tile subtext will be augmented with the current status of the mode.
     */
    private fun getModeDescription(mode: ZenMode): String? {
        if (!mode.rule.isEnabled) {
            return context.resources.getString(R.string.zen_mode_set_up)
        }
        if (!mode.rule.isManualInvocationAllowed && !mode.isActive) {
            return context.resources.getString(R.string.zen_mode_no_manual_invocation)
        }
        return mode.getDynamicDescription(context)
    }

        val modeSubtext = mode.getDynamicDescription(context)
    private fun getTileSubtext(mode: ZenMode): String {
        val modeDescription = getModeDescription(mode)
        return if (mode.isActive) {
            if (modeSubtext != null) {
                context.getString(R.string.zen_mode_on_with_details, modeSubtext)
            if (modeDescription != null) {
                context.getString(R.string.zen_mode_on_with_details, modeDescription)
            } else {
                context.getString(R.string.zen_mode_on)
            }
        } else {
            modeSubtext ?: context.getString(R.string.zen_mode_off)
            modeDescription ?: context.getString(R.string.zen_mode_off)
        }
    }