Skip to content

State descriptions#8

Merged
yamal-alm merged 20 commits intomainfrom
state-descriptions
Mar 10, 2026
Merged

State descriptions#8
yamal-alm merged 20 commits intomainfrom
state-descriptions

Conversation

@yamal-alm
Copy link
Contributor

@yamal-alm yamal-alm commented Feb 20, 2026

Summary

Adds a new State Descriptions section to the accessibility catalog, demonstrating how to use stateDescription to provide dynamic, contextual state information to screen readers for interactive elements.

How

New catalog entry: "State Descriptions" screen registered in AccessibilityCatalogDataSource

  • Description page with
  • Compose implementation: StateDescriptionsCompose
  • Views implementation: StateDescriptionsView
  • Text translated both in English and Spanish

How can I test this

Captura de pantalla 2026-02-27 a las 13 22 03
Grabacion.de.pantalla.2026-02-27.a.las.13.05.22.mov

AccessibilityElement(
id = UUID.randomUUID(),
nameResId = R.string.state_descriptions_title_section,
iconResId = R.drawable.ic_state_descriptions,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i don't really know what icon fits better here... any suggestion?

Image

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that most AI models agree on using a checkmark for the stateDescription icon. Perhaps we could use something like this:

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="24"
    android:viewportHeight="24">

    <path
        android:fillColor="#FF000000"
        android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2z"/>

    <path
        android:fillColor="#FFFFFFFF"
        android:pathData="M10,15.5l-3.5,-3.5L7.91,10.59L10,12.67L16.09,6.58L17.5,8L10,15.5z"/>
</vector>

wdyt?

Image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks! done

@Composable
fun StateDescriptions() {
Column {
ExampleWithThreeStateButton()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is just a three state custom composable that mimics the "sound/vibration/silence" button from Android OS

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a great implementation example, simple and very visual 💯

.size(48.dp)
.semantics {
stateDescription = stateDesc
onClick(label = changeAction, action = null)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I needed to override the default "change" action to a more proper label. "Alternar" in this case

Comment on lines +45 to +62
val stateDesc = when (soundMode) {
SoundMode.SOUND -> stringResource(R.string.state_descriptions_implementation_sound_mode_enabled)
SoundMode.VIBRATION -> stringResource(R.string.state_descriptions_implementation_vibration_mode_enabled)
SoundMode.SILENCE -> stringResource(R.string.state_descriptions_implementation_silence_mode_enabled)
}

val iconRes = when (soundMode) {
SoundMode.SOUND -> R.drawable.ic_volume_active
SoundMode.VIBRATION -> R.drawable.ic_volume_vibrate
SoundMode.SILENCE -> R.drawable.ic_volume_mute
}

val contentDesc =
when (soundMode) {
SoundMode.SOUND -> stringResource(R.string.state_descriptions_implementation_change_to_vibration)
SoundMode.VIBRATION -> stringResource(R.string.state_descriptions_implementation_change_to_silence)
SoundMode.SILENCE -> stringResource(R.string.state_descriptions_implementation_change_to_sound)
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the logic is not complex at all, we just update the contentDescription of the button, its icon and the state description

Comment on lines +59 to +68
soundModeButton.setImageResource(iconRes)
soundModeButton.contentDescription = contentDesc
ViewCompat.setStateDescription(soundModeButton, stateDesc)

ViewCompat.replaceAccessibilityAction(
soundModeButton,
AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CLICK,
context.getString(R.string.state_descriptions_implementation_alternate_action),
null
)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the same logic as in compose: we update the content description, the icon and the state description. The default "change" label has been replaced with "alternar"

@yamal-alm yamal-alm marked this pull request as ready for review March 6, 2026 09:21
Copy link
Contributor

@haynlo haynlo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM Simple and useful.. thanks! 🙌🏼

AccessibilityElement(
id = UUID.randomUUID(),
nameResId = R.string.state_descriptions_title_section,
iconResId = R.drawable.ic_state_descriptions,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that most AI models agree on using a checkmark for the stateDescription icon. Perhaps we could use something like this:

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="24"
    android:viewportHeight="24">

    <path
        android:fillColor="#FF000000"
        android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2z"/>

    <path
        android:fillColor="#FFFFFFFF"
        android:pathData="M10,15.5l-3.5,-3.5L7.91,10.59L10,12.67L16.09,6.58L17.5,8L10,15.5z"/>
</vector>

wdyt?

Image

@Composable
fun StateDescriptions() {
Column {
ExampleWithThreeStateButton()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a great implementation example, simple and very visual 💯

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new “State Descriptions” entry to the Accessibility Catalog to demonstrate using stateDescription for dynamic, contextual announcements in both XML Views and Jetpack Compose.

Changes:

  • Registers a new “State Descriptions” AccessibilityElement in AccessibilityCatalogDataSource.
  • Adds new View and Compose implementations showcasing a 3-state sound mode control with stateDescription.
  • Introduces new strings, URLs, layout, and vector drawables to support the new catalog entry.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
app/src/main/res/values/urls.xml Adds documentation and related links for the new section.
app/src/main/res/values/strings.xml Adds Spanish strings for the new section (title, abstract, requirements, labels).
app/src/main/res/values-en/strings.xml Adds English strings for the new section (title, abstract, requirements, labels).
app/src/main/res/layout/state_descriptions.xml Adds XML layout for the View implementation (title + icon button).
app/src/main/res/drawable/ic_volume_vibrate.xml Adds vibrate icon for the 3-state example.
app/src/main/res/drawable/ic_volume_mute.xml Adds mute icon for the 3-state example.
app/src/main/res/drawable/ic_volume_active.xml Adds sound-on icon for the 3-state example.
app/src/main/res/drawable/ic_state_descriptions.xml Adds catalog icon for the new section.
app/src/main/java/com/telefonica/apps/accessibility_catalog/view/screens/implementations/views/statedescriptions/StateDescriptionsView.kt Implements the XML Views example using ViewCompat.setStateDescription.
app/src/main/java/com/telefonica/apps/accessibility_catalog/view/screens/implementations/views/statedescriptions/README.md Documents the Views approach for state descriptions.
app/src/main/java/com/telefonica/apps/accessibility_catalog/view/screens/implementations/compose/statedescriptions/StateDescriptionsCompose.kt Implements the Compose example using semantics stateDescription.
app/src/main/java/com/telefonica/apps/accessibility_catalog/view/screens/implementations/compose/statedescriptions/README.md Documents the Compose approach for state descriptions.
app/src/main/java/com/telefonica/apps/accessibility_catalog/data/AccessibilityCatalogDataSource.kt Registers the new section, links, and implementations in the catalog.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +75 to +78
.semantics {
stateDescription = stateDesc
onClick(label = changeAction, action = null)
}
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.semantics { onClick(label = ..., action = null) } sets an onClick semantics action with a null handler, which can make the node appear non-clickable to accessibility services (and may override IconButton’s default click semantics). Provide a non-null semantics action (returning true) that triggers the same state change as IconButton(onClick=...), or remove the explicit onClick semantics and only set the stateDescription.

Copilot uses AI. Check for mistakes.
Comment on lines +63 to +68
ViewCompat.replaceAccessibilityAction(
soundModeButton,
AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CLICK,
context.getString(R.string.state_descriptions_implementation_alternate_action),
null
)
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ViewCompat.replaceAccessibilityAction(..., ACTION_CLICK, ..., null) replaces the click accessibility action with a null command. This can result in TalkBack showing the custom label but the action not performing anything (or overriding the default click behavior). Pass a non-null AccessibilityViewCommand that calls soundModeButton.performClick() (or avoid replacing ACTION_CLICK and use another mechanism to customize the label).

Copilot uses AI. Check for mistakes.
@yamal-alm yamal-alm merged commit 6771aa9 into main Mar 10, 2026
@yamal-alm yamal-alm deleted the state-descriptions branch March 10, 2026 16:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants