-
Notifications
You must be signed in to change notification settings - Fork 28.9k
Description
Affected platform: Android
Currently, in the AccessibilityService
, the isFocusable
method in AccessibilityBridge.java
determines if a widget is focusable for accessibility. While this method allows widgets to become focusable based on various properties and flags, there is no direct mechanism to explicitly mark a widget as permanently unfocusable. The only workaround to make a widget unfocusable is to ensure it lacks a label, value, hint, and doesn't match any of the predefined FOCUSABLE_FLAGS
. This indirect approach is limiting and doesn't provide explicit control over focusability in all scenarios.
Use Case
This feature would be particularly useful for creating more nuanced and accessible UI components, mirroring patterns found in other modern UI frameworks.
In Jetpack Compose's Material Date Picker, the <month year>
portion is implemented as an unfocusable live region. The parent composable, which wraps both the <month year>
text and the "Switch to selecting a year" action, is focusable. This design is intentional: when users interact with the next/previous month buttons, only the updated <month year>
text is announced by screen readers, without the month/year being focusable on its own.
Here's the semantic tree structure from Jetpack Compose illustrating this:
(159133)971.View:(99, 816 - 442, 942):GRANULARITY{0}(action:FOCUS/CLEAR_A11Y_FOCUS/CLICK/SCROLL_TO_POSITION):focusable:screenReaderfocusable:clickable:accessibilityFocused
(159195)971.TextView:(131, 852 - 326, 905):TEXT{March 2025}:CONTENT{March 2025}:GRANULARITY{11}(action:A11Y_FOCUS/SCROLL_TO_POSITION):supportsTextLocation:politeLiveRegion
(159257)971.View:(347, 847 - 410, 910):CONTENT{Switch to selecting a year}:GRANULARITY{11}(action:A11Y_FOCUS/SCROLL_TO_POSITION)
You can explore a Jetpack Compose example here: https://github.com/ash2moon/jetpack-calendar
In Flutter, achieving the same component structure as in Jetpack Compose is currently challenging without resorting to semantic announcements as a workaround. The current isFocusable
logic doesn't allow for explicitly marking a node as unfocusable regardless of its other semantic properties.
Here's the Flutter Date Picker example for reference: https://github.com/flutter/flutter/blob/master/examples/api/lib/material/date_picker/show_date_picker.0.dart
Semantic tree structure from Flutter:
(35607)1011.View:(152, 878 - 677, 1014):GRANULARITY{0}(action:A11Y_FOCUS):focusable
(35638)1011.View:(152, 878 - 677, 1014):CONTENT{August 2021 Select year}:GRANULARITY{0}(action:A11Y_FOCUS/CLICK/SCROLL_TO_POSITION):focusable:clickable:politeLiveRegion
Expected Behavior and Solution
Add a new semantic property, named unfocusable
. When set to true
for a semantic node, this property would explicitly force the node to be unfocusable by accessibility services, overriding all other conditions that might otherwise make it focusable.
-
Pros:
- Potentially more semantically aligned with the purpose of live regions, which are primarily for announcements, not direct interaction.
- Simple, easy to understand solution.
-
Cons:
- Confusion between setting
focusable = false
andunfocusable = false
. Developer messages should be logged when conflicting flags are used.
- Confusion between setting
Alternative Solutions
-
Special Handling for Live Regions: Currently, live regions can still become focusable if they possess other focus-inducing properties. We could modify the system so that by default, nodes marked as live regions are implicitly unfocusable unless they are explicitly configured to be focusable through actions or other focus-related semantic properties. This would naturally address the use case outlined in the Date Picker example, where the
<month year>
text is a live region intended for announcements but not direct focus.-
Pros:
- Potentially more semantically aligned with the purpose of live regions, which are primarily for announcements, not direct interaction.
- Could simplify the API and reduce the need for explicit unfocusability control in common live region scenarios.
-
Cons:
- Implicit behavior change that could surprise developers who expect live regions to be focusable in certain situations.
- May not be a general solution for all cases where unfocusability is desired for elements that are not live regions.
- Could make it more complex to intentionally make a live region focusable if needed.
-
-
New
LiveRegion
Widget: Another approach is to create a dedicatedLiveRegion
widget. This widget would inherently manage the semantic properties of a live region but allow developers to provide a closure that returns the text to be announced whenever the content within theLiveRegion
needs to be updated. This widget would have an option to become focusable but by default would stay unfocusable and designed specifically for dynamic announcements.-
Pros:
- Provides a clear and declarative way for developers to create live regions within their UI.
- Encapsulates the logic of live regions within a dedicated widget, making it easier to understand and use.
- Naturally addresses the unfocusability requirement for announcement-only elements.
- Could potentially offer more control over announcement behavior and customization within the widget itself.
-
Cons:
- Complicated design and estimated work to complete this would take significantly longer than the proposed solution.
- Might be perceived as more verbose compared to simply setting an
unfocusable
property on existing semantic nodes. - Could be less flexible if developers want to apply live region semantics to existing widgets without wrapping them in a dedicated
LiveRegion
widget.
-
Sub-issues
Metadata
Metadata
Assignees
Labels
Type
Projects
Status