# Accessibility in Android: STRV Common Topics Pt. 2

[Michal Urbanek](https://www.strv.com/blog/authors/michal-urbanek) Android Engineer

---

## Introduction

As promised, we’re back with more digital accessibility (a11y) content. For those catching up, we recommend checking out our [Intro to Digital Accessibility](https://www.strv.com/blog/what-is-accessibility-why-its-a-must-have-at-strv-product?ref=strv.ghost.io) and its importance for STRV, [the Basics & Tools of Accessibility in Android Apps](https://www.strv.com/blog/accessibility-at-strv-android-basics-best-tools-engineering?ref=strv.ghost.io), and [Android Common Topics, Pt. 1](https://www.strv.com/blog/accessibility-at-strv-android-common-topics-pt-1-engineering?ref=strv.ghost.io).

We’ve gone over a lot of issues that can be revealed mainly by Android Scanner or by using a keyboard for navigation. Now, with this article (the third of our four-part Android series), we’d like to continue with a11y issues that can be recognized by a screen reader — in our case, TalkBack.

---

## State Announcement

Basically, you can (and should) announce everything that happens on the screen. Here are some things that should be announced by TalkBack:

### Entering a Screen

This is something taken from a Google Play app where they announce that the detail of an app was opened. The easiest way would be to announce the Toolbar title since it would be sufficient information in most cases. You may sometimes need more information, e.g., when you open Profile Detail; you can then add a user name and make the announcement dynamic.

**Example with SettingsFragment.kt:**

```kotlin
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
	super.onViewCreated(view, savedInstanceState)
	requireView().announceForAccessibility("Settings")
}
```

### Progress States

There may be cases where you show a progress bar while sending an event to the server and waiting for a response. This is pretty straightforward for users who can see what is happening on the screen, but users using TalkBack would not have any idea about the current state.

Display and announce the loading state while fetching records from the server:

```kotlin
buttonApply.setOnClickListener {
	progressView.visibility = View.VISIBLE
	progressView.announceForAccessibility("Loading more records")
	// ...
	progressView.visibility = View.GONE
	progressView.announceForAccessibility("More records loaded")
}
```

### Error States

The best practice would be to not use any custom errors but rather errors that are a part of the TextInputLayout view or similar. But in real-world scenarios, sometimes custom errors are necessary. When doing this, ensure to announce this error to users via TalkBack.

A common mistake is using Toast or Snackbar views for errors, which breaks WCAG requirements that users should have enough time to read the content. Such self-dismissable views are not compliant for conveying error information.

**Example of a custom Button view displaying an error:**

You can manually announce the error using `announceForAccessibility` or use `sendAccessibilityEvent` with event `TYPE_VIEW_ACCESSIBILITY_FOCUSED`:

```kotlin
fun setError(error: String) {
	error.text = error
	error.visibility = View.VISIBLE
	error.sendAccessibilityEvent(
		AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED
	)
}
```

### Selections

When any selection happens, it should be communicated, e.g., selecting a date in a calendar picker can be announced once the user clicks on the Select button.

**In a dialog:**

```kotlin
buttonOptionOne.setOnClickListener { button ->
	button.announceForAccessibility("Option 1 selected.")
	dismiss()
}
```

### Other Screen States or Actions

Other actions like delete, update, or create of a record should be announced:

```kotlin
buttonDeleteRecord.setOnClickListener { button ->
	button.announceForAccessibility("Record deleted.")
	finish()
}
```

---

## Screen Order

While using a screen reader, disclaimers placed below actionable items might be missed. For example, if a disclaimer is below the Submit button, navigating through the screen reads the Submit button first, and the user might not hear the disclaimer before pressing.

---

## Grouping Views Together

Some views do not make sense when read alone by TalkBack, e.g., a TextView "Start date" with a second TextView with the date, or Profile items with Photo, UserName, and Email. Even list items inside RecyclerView can benefit from grouping into one view. Simply place these views into a ViewGroup and make it focusable:

`android:focusable="true"`

This way, TalkBack will present the whole group simultaneously, and its children views’ descriptions will be read together, making more sense.

**For API level 28+:**

You can use `android:screenReaderFocusable="true"` for the ViewGroup and set `android:focusable="false"` for child views.

**Example with two TextViews grouped in LinearLayout:**

```xml
<LinearLayout
	android:focusable="true">
	<TextView
		android:text="Start date" />
	<TextView
		android:text="10/10/2021" />
</LinearLayout>
```

When grouped, navigating to "Start date" will read “Start date Saturday May first,” providing better accessibility.

---

## Headings

TalkBack can jump through all Headings present on a screen. To mark a view as a heading, set:

`android:accessibilityHeading="true"`

This helps users navigate sections easily, especially when changing TalkBack to Headings mode.

**A good practice:** Set the title of the custom Toolbar or sections in Settings as headings.

**Example:**

```xml
<TextView
	android:text="Important Title"
	android:accessibilityHeading="true" />
```

---

## Labels and Live Region

`android:labelFor="@+id/slider"` pairs an element with its description, e.g., a slider with a TextView showing its value.

`android:accessibilityLiveRegion="polite"` automatically notifies users about changes in the view, useful for conveying updates.

---

## Read Order

The natural reading order can be adjusted using:

- `android:accessibilityTraversalBefore="@id/xyz"`
- `android:accessibilityTraversalAfter="@id/xyz"`

Most layouts are read top-to-bottom by default, but these properties help reorder views when needed.

---

## Don't miss anything