From da899c0cc4372830e5ca053a096b74fff2a19cb8 Mon Sep 17 00:00:00 2001 From: Kacie Bawiec Date: Mon, 3 May 2021 11:48:33 -0700 Subject: [PATCH] Add support for Toggle Button accessibilityRole Summary: Changelog: [General][Added] Add support for "togglebutton" accessibilityRole # Context The role for ToggleButton, which is needed on Android to implement toggle buttons correctly, is not currently supported. # What does this diff do? Adds support for accessibilityRole `"togglebutton"`. On Android, this maps to class `"Android.widget.ToggleButton"`. iOS does not have an equivalent trait for togglebutton, so I set it to be the same as setting `accessibilityRole="button"` for iOS. # Caveats - checked vs selected It seems to me like this role currently requires that you set `accessibilityState={{checked: true/false}}`. The behavior is strange when setting `selected` state, I think because on Android ToggleButtons are meant to use `checked` to indicate toggled on/off. This is tricky because typically on iOS if you have a toggle button, you would use `selected` instead of `checked`, so RN users are likely to mess this up. Possible solutions: 1. document that you should use `checked` state on Android for toggle buttons (and maybe throw a warning if someone passes in `selected`). 2. have RN ignore it if someone passes in accessibilityState `selected`, if this role is used. 3. Have RN convert passed in `selected` state to `checked` on the Android side. Reviewed By: nadiia Differential Revision: D27976046 fbshipit-source-id: 4ce202449cf2371f4bf83c4db2d53120369ee7b0 --- Libraries/Components/View/ViewAccessibility.js | 1 + .../DeprecatedPropTypes/DeprecatedViewAccessibility.js | 1 + React/Views/RCTViewManager.m | 1 + .../react/uimanager/ReactAccessibilityDelegate.java | 7 +++++++ .../res/views/uimanager/values/strings_unlocalized.xml | 4 ++++ .../components/view/accessibilityPropsConversions.h | 2 +- 6 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Libraries/Components/View/ViewAccessibility.js b/Libraries/Components/View/ViewAccessibility.js index dd2056ae529ef1..ccdc6a6688a083 100644 --- a/Libraries/Components/View/ViewAccessibility.js +++ b/Libraries/Components/View/ViewAccessibility.js @@ -16,6 +16,7 @@ import type {SyntheticEvent} from '../../Types/CoreEventTypes'; export type AccessibilityRole = | 'none' | 'button' + | 'togglebutton' | 'link' | 'search' | 'image' diff --git a/Libraries/DeprecatedPropTypes/DeprecatedViewAccessibility.js b/Libraries/DeprecatedPropTypes/DeprecatedViewAccessibility.js index 77c4146a865f5b..ef82aa5c7dedfe 100644 --- a/Libraries/DeprecatedPropTypes/DeprecatedViewAccessibility.js +++ b/Libraries/DeprecatedPropTypes/DeprecatedViewAccessibility.js @@ -15,6 +15,7 @@ module.exports = { DeprecatedAccessibilityRoles: [ 'none', 'button', + 'togglebutton', 'link', 'search', 'image', diff --git a/React/Views/RCTViewManager.m b/React/Views/RCTViewManager.m index 48dcd0a06ce4a3..779b6559c6334b 100644 --- a/React/Views/RCTViewManager.m +++ b/React/Views/RCTViewManager.m @@ -26,6 +26,7 @@ @implementation RCTConvert (UIAccessibilityTraits) (@{ @"none" : @(UIAccessibilityTraitNone), @"button" : @(UIAccessibilityTraitButton), + @"togglebutton" : @(UIAccessibilityTraitButton), @"link" : @(UIAccessibilityTraitLink), @"header" : @(UIAccessibilityTraitHeader), @"search" : @(UIAccessibilityTraitSearchField), diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java index afbe05610b0ff8..b87e976ef62437 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java @@ -82,6 +82,7 @@ private void scheduleAccessibilityEventSender(View host) { public enum AccessibilityRole { NONE, BUTTON, + TOGGLEBUTTON, LINK, SEARCH, IMAGE, @@ -112,6 +113,8 @@ public static String getValue(AccessibilityRole role) { switch (role) { case BUTTON: return "android.widget.Button"; + case TOGGLEBUTTON: + return "android.widget.ToggleButton"; case SEARCH: return "android.widget.EditText"; case IMAGE: @@ -392,6 +395,10 @@ public static void setRole( } else if (role.equals(AccessibilityRole.BUTTON)) { nodeInfo.setRoleDescription(context.getString(R.string.button_description)); nodeInfo.setClickable(true); + } else if (role.equals(AccessibilityRole.TOGGLEBUTTON)) { + nodeInfo.setRoleDescription(context.getString(R.string.toggle_button_description)); + nodeInfo.setClickable(true); + nodeInfo.setCheckable(true); } else if (role.equals(AccessibilityRole.SUMMARY)) { nodeInfo.setRoleDescription(context.getString(R.string.summary_description)); } else if (role.equals(AccessibilityRole.HEADER)) { diff --git a/ReactAndroid/src/main/res/views/uimanager/values/strings_unlocalized.xml b/ReactAndroid/src/main/res/views/uimanager/values/strings_unlocalized.xml index a904f57856fb2a..2d239fdbd93def 100644 --- a/ReactAndroid/src/main/res/views/uimanager/values/strings_unlocalized.xml +++ b/ReactAndroid/src/main/res/views/uimanager/values/strings_unlocalized.xml @@ -16,6 +16,10 @@ name="button_description" translatable="false" >Button + Toggle Button