Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Accessbility and Android APIs

Accessbility and Android APIs

Aung Kyaw Paing

November 19, 2022
Tweet

More Decks by Aung Kyaw Paing

Other Decks in Technology

Transcript

  1. Accessibility and Android APIs Aung Kyaw Paing (Vincent) Senior Consultant

    @ thoughtworks | GDE Thailand aungkyawpaing.dev
  2. Over 1 billion people are estimated to experience disability. This

    corresponds to about 15% of the world's population - World Health Organization (WHO)
  3. Deafness & Hard-of-hearing Motor Impairments Cognitive disabilities Blindness & Visual

    impairment Everyone could experiences one of these in their lives.
  4. - Won “Innovation in Accessibility” award for the first time

    in Game awards - Even people without common disabilities start using these features! The Last of Us
  5. - Integration with braille display - Used together with Talkback

    - Interact using keys on display BrailleBack
  6. Switch Access - Switches instead of taps - Scan items

    and highlight - User can interact with switches
  7. Voice Access - Control hand-free - Show labels and grids

    - Interact device with voice commands
  8. Favorite/Like/Love Search Open Navigation Drawer Label images - Provide a

    screen readable label of your image and actions - Translated for different languages
  9. <ImageView android:id="@+id/event_banner" android:contentDescription="20% discount sale event" /> <menu> <item android:id="@+id/action_settings"

    android:title="@string/action_settings" android:contentDescription="Settings" /> </menu> view.contentDescription = "Describe me!"
  10. Icon( imageVector = Icons.Filled.KeyboardArrowLeft, contentDescription = "Next" ) Image( bitmap

    = ImageBitmap.imageResource(id = R.id.arrow_next), contentDescription = "" )
  11. Icon( imageVector = Icons.Filled.KeyboardArrowLeft, contentDescription = "Next" ) Image( bitmap

    = ImageBitmap.imageResource(id = R.id.arrow_next), contentDescription = "" ) Text( text = "Hello There", modifier = Modifier.semantics { contentDescription = "General Kenobi" } )
  12. <ImageView android:id="@+id/event_banner" android:contentDescription="@null" /> <!-- Only for SDK 16 and

    above --> <ImageView android:id="@+id/event_banner" android:importantForAccessibility="no" />
  13. fun InboxRow() { Row( modifier = Modifier .semantics { onClick(label

    = "Delete") { deleteMail() return@onClick true } } ) { // Render Contents } }
  14. fun InboxRow() { Row( modifier = Modifier .semantics { onClick(label

    = "Delete") { deleteMail() return@onClick true } } ) { // Render Contents } }
  15. fun InboxRow() { Row( modifier = Modifier .semantics { onClick(label

    = "Delete") { deleteMail() return@onClick true } } ) { // Render Contents } }
  16. @Composable fun ClickableRow( text: String, onClick: () -> Unit )

    { Row( modifier = Modifier .clickable() { onClick() } ) { //Render Text and Arrow Right Icon } } “Double tap to click”
  17. @Composable fun ClickableRow( text: String, onClick: () -> Unit )

    { Row( modifier = Modifier .clickable(onClickLabel = "Open $text") { onClick() } ) { //Render Text and Arrow Right Icon } } “Double tap to open $text”
  18. Merge components - Merge views to make screen reader navigate

    with fewer taps - Recommend to use for Lists + “Checkbox Checked” “With Soup” “Checkbox With Soup - Checked”
  19. <ConstraintLayout android:id="@+id/project_container" ... android:screenReaderFocusable="true" android:contentDescription="droiconsg built 3 hours ago"> <TextView

    android:id="@+id/project_title" ... android:focusable="false" android:text="droidconsg" /> <TextView android:id="@+id/build_time" android:focusable="false" android:text="3 Hours Ago" /> </ConstraintLayout>
  20. fun ProjectCard() { Column(modifier = Modifier.Semantic( mergeDescendants = true )

    { //Other accessibility stuffs }) { Text("droidconsg") Text("3 Hours Ago") } }
  21. fun ProjectCard() { Column(modifier = Modifier.Semantic( mergeDescendants = true )

    { onClick(label = "Do Something") { //On Click actions } }) { BookmarkButton() } }
  22. fun ProjectCard() { Column(modifier = Modifier.Semantic( mergeDescendants = true )

    { onClick(label = "Do Something") { //On Click actions } }) { BookmarkButton(modifier = Modifier.clearAndSetSemantics { }) } }
  23. Describe the state - Telling screen reader to alert user

    for state change on interaction Paused Playing Image ref: https://medium.com/google-dev eloper-experts/state-description s-on-android-b2029283871f
  24. Timeout - Do not use constant timeouts - Instead, use

    recommended timeout from Accessibility manager
  25. Anti-patterns - Do not reinvent the wheel - Use material

    or androidx components as much as possible - Do not abuse accessibility announcements val event = AccessibilityEvent(AccessibilityEvent.TYPE_ANNOUNCEMENT) event.text.add("You got a new notification!") accessibilityManager.sendAccessibilityEvent(event)
  26. Anti-patterns - Do not reinvent the wheel - Use material

    or androidx components as much as possible - Do not abuse accessibility announcements val event = AccessibilityEvent(AccessibilityEvent.TYPE_ANNOUNCEMENT) event.text.add("You got a new notification!") accessibilityManager.sendAccessibilityEvent(event)
  27. Check List - Adjust button sizes, text sizes and color

    contrast - Label images - Skip unnecessary elements - Provide accessibility actions - Replace with meaningful actions - Adjust timeout - Merge elements
  28. Automated Testing - Espresso provides a one-line code to test

    accessibility - Runs a list of test every time you interact with the view in a test class EspressoTest { init { AccessibilityChecks.enable() } }
  29. Automated Testing There were 2 accessibility errors: AppCompatImageButton{id=2131165210, ...}: View

    is missing speakable text needed for a screen reader, AppCompatImageButton{id=2131165210,...}: View falls below the minimum recommended size ... ...
  30. Compose UI Test composeTestRule .onNodeWithContentDescription("Content Description") .assertIsDisplayed() val matcher =

    hasStateDescription("state value") composeTestRule.onNode(matcher).assertIsDisplayed()
  31. “Accessibility isn’t something that you check the list and say

    it’s done. It’s an user experience so you have to test it manually by yourself to know it’s a good experience”