Inclusive Android Apps #4: The Problem Of Time-Based Actions
Fourth issue covers how to make your Android apps more inclusive by supporting user preferences for time-based actions.
Imagine you're doing something urgent in your bank app. Suddenly, a security prompt appears. You're feeling stressed because of the current state of the world, and then this long prompt appears.
It's visible for only a short time, and, because of the stress, you're reading and processing it more slowly. The prompt disappears, and you're left wondering if it was actually important for you.
Then the app kicks you out, and you need to start all over. Turns out, the prompt was important, telling you that you need to do something to prevent logging out. You just never got to that point.
The Problem of Time-Based Actions
Time-based actions assume everyone can read, understand, and act at the same speed. But not everyone in every situation can.
There are some common time-based actions, such as:
- Toast notifications, which usually disappear after 5-10 seconds
- Snackbars with actions that are dismissed automatically
- Security prompts, which have a timeout for safety
- Tutorial tooltips that auto-advance
- Session timeout warnings
- Timed form submissions
Who This Hurts
- People with motor disabilities, who are slower to tap buttons
- Non-native speakers, who need time to read/understand
- Users with cognitive disabilities, who need time to process
- Elderly users, who may read/act more slowly
- Assistive technology users, for whom it takes longer to navigate
- Anyone in a distracting or stressfull environment
Why Developers (or Designers) Do This
Developers often don't realize users need different amounts of time. When you test with touch, full vision, and native language fluency, 10 seconds feels like plenty. You tap the button in 2 seconds, and you're done.
There's also pressure to prevent accidental actions or security concerns—auto-dismissing prompts feel like a safety feature. But for users who need more time, these 'safety' measures become barriers.
The Solution
Android phones have a setting called “Time to Take Action” that controls the minimum time before temporary messages asking a user to take an action disappear. You can find it from Settings → Accessibility Settings → Timing controls → Time to take action (Accessibility timeout).
What the setting essentially does is lengthen the timeouts internally for operating system-level components and Material3 components. But if you have a custom component that disappears after a timeout (like, for example, a snackbar component), you need to add support for this setting yourself. Let's explore how.
First, we’ll need to query the actual timeout time from the user settings. That can be calculated with the following code:
// 10 seconds
const val DEFAULT_TIMEOUT_MS = 10000
@Composable
fun Component() {
val timeout = LocalAccessibilityManager
.current?
.calculateRecommendedTimeoutMillis(
originalTimeoutMillis = DEFAULT_TIMEOUT_MS,
containsText = true,
containsControls = true,
containsIcons = false
) ?: DEFAULT_TIMEOUT_MS
…
}
We first define the default timeout, which we use for users who have not changed the Time to take action setting. That's defined with DEFAULT_TIMEOUT_MS.
For the actual timeout, we use the LocalAccessibilityManager's calculateRecommendedTimeoutMillis method. It takes the original timeout in milliseconds and boolean flags indicating whether the component using the timeout contains text, actions, or icons. In this example, it contains text and actions, but not an icon.
If the LocalAccessibilityManager is unavailable, we fall back to the default timeout we defined.
calculateRecommendedTimeoutMillis returns the calculated timeout, which we then can use in the component. Let's say we have a session timeout warning, which we want to hide after the timeout:
@Composable
fun SessionTimeoutWarning(
warningVisible: Boolean,
timeout: Long,
hideWarning: () -> Unit,
...
) {
...
LaunchedEffect(warningVisible) {
if (warningVisible) {
delay(timeout)
hideWarning()
}
}
SessionTimeoutWarningContent(...)
}
Inside a LaunchedEffect, if the parent component has triggered showing the session timeout warning, we first deplay the amount of the calculated timeout, and only after that hide the warning.
This change respects user settings: users who need 30 seconds get 30 seconds, while default users still see your original 10-second timeout.
What If You Need a Timeout?
Some timeouts are necessary (session expiration, payment confirmation). In these cases:
- Make the minimum timeout as long as reasonable
- Allow users to extend the time before it expires
- Provide a clear visual countdown
- Offer alternative ways to complete the action
Read More
Support Time to Take Action with Compose
Author: Eevis Panula
The blog post I wrote about supporting Time to Take Action. It was also used as the basis for this newsletter issue.
Understanding SC 2.2.1: Timing Adjustable (Level A)
Author: Web Accessibility Initiative WAI
If you're working with a product subject to accessibility legislation, your app must comply with WCAG (Web Content Accessibility Guidelines). There is a Success Criterion 2.2.1 Timing Adjustable, and one way to pass it is to support time adjustment, as explained in this newsletter issue. This link explains the success criteria.
AccessibilityManager
Author: Android Developers Documentation
This link leads to AccessibilityManager's official documentation. LocalAccessibilityManager provides this class.
That’s a wrap for the fourth issue of Inclusive Android Apps.
What time-based patterns have you encountered that frustrated users? Hit reply and let me know!
Next month: We will talk about drag-and-drop pattern and the accessibility problems it has.
Thanks for reading!
-Eevis
eevis.codes