From d3f09198168362861583bb4b11c9451d0420bd81 Mon Sep 17 00:00:00 2001 From: Ziqi Chen Date: Wed, 8 Aug 2018 00:50:37 -0700 Subject: [PATCH] added accessibilityHints implementation on Android Summary: Implemented a version of accessibility Hints on android by adding hint text to the end of contentDescription. There is already an existing prop on js and iOS implementation. Changes involve: * adding a prop on native android code for accessibilityHints * setting the accessibilityDelegate after the props are all loaded. * Instead of directly updating the accessibility delegate, the prop setters now update state by setting the values of the variables. Once all props are set, the accessibility delegate is set based on the props * BaseViewManager keeps track of whether or not accessibility props have been set * AccessibilityDelegateUtil keeps track of what the props have been set to. (Renamed AccessibilityRoleUtil to AccessibilityDelegateUtil) Currently, this is the easiest way of emulating the way accessibility hints work on iOS, and I think having an android counter part is better than having nothing. It's different from iOS in that it will announce the hint before the role, and also cannot be turned off. Ex: if I set the accessibility like this: ``` Tester ``` Talk back will read: `accessibility label, accessibility Hint, button, selected` In the future for next steps, I plan on investigating the process of making a second announcement after the first Reviewed By: achen1 Differential Revision: D9037226 fbshipit-source-id: 8d484e1114eb69aa5f5314b3755b351b8ea80b09 --- ...il.java => AccessibilityDelegateUtil.java} | 37 +++++++++++-------- .../react/uimanager/BaseViewManager.java | 28 +++++++++++++- .../main/res/views/uimanager/values/ids.xml | 7 ++++ .../java/com/facebook/react/uimanager/BUCK | 1 + 4 files changed, 57 insertions(+), 16 deletions(-) rename ReactAndroid/src/main/java/com/facebook/react/uimanager/{AccessibilityRoleUtil.java => AccessibilityDelegateUtil.java} (75%) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/AccessibilityRoleUtil.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/AccessibilityDelegateUtil.java similarity index 75% rename from ReactAndroid/src/main/java/com/facebook/react/uimanager/AccessibilityRoleUtil.java rename to ReactAndroid/src/main/java/com/facebook/react/uimanager/AccessibilityDelegateUtil.java index 1be25440c..c834c85fd 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/AccessibilityRoleUtil.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/AccessibilityDelegateUtil.java @@ -23,7 +23,7 @@ import javax.annotation.Nullable; * AccessibilityNodeInfo. */ -public class AccessibilityRoleUtil { +public class AccessibilityDelegateUtil { /** * These roles are defined by Google's TalkBack screen reader, and this list should be kept up to @@ -41,7 +41,9 @@ public class AccessibilityRoleUtil { IMAGEBUTTON("android.widget.ImageView"), KEYBOARDKEY("android.inputmethodservice.Keyboard$Key"), TEXT("android.widget.ViewGroup"), - ADJUSTABLE("android.widget.SeekBar"); + ADJUSTABLE("android.widget.SeekBar"), + SUMMARY("android.widget.ViewGroup"), + HEADER("android.widget.ViewGroup"); @Nullable private final String mValue; @@ -64,11 +66,11 @@ public class AccessibilityRoleUtil { } } - private AccessibilityRoleUtil() { + private AccessibilityDelegateUtil() { // No instances } - public static void setRole(final View view, final AccessibilityRole role) { + public static void setDelegate(final View view) { // if a view already has an accessibility delegate, replacing it could cause problems, // so leave it alone. if (!ViewCompat.hasAccessibilityDelegate(view)) { @@ -79,7 +81,18 @@ public class AccessibilityRoleUtil { public void onInitializeAccessibilityNodeInfo( View host, AccessibilityNodeInfoCompat info) { super.onInitializeAccessibilityNodeInfo(host, info); - setRole(info, role, view.getContext()); + String accessibilityHint = (String) view.getTag(R.id.accessibility_hint); + AccessibilityRole accessibilityRole = getAccessibilityRole((String) view.getTag(R.id.accessibility_role)); + setRole(info, accessibilityRole, view.getContext()); + if (!(accessibilityHint == null)) { + String contentDescription=(String)info.getContentDescription(); + if (contentDescription != null) { + contentDescription = contentDescription + ", " + accessibilityHint; + info.setContentDescription(contentDescription); + } else { + info.setContentDescription(accessibilityHint); + } + } } }); } @@ -89,7 +102,7 @@ public class AccessibilityRoleUtil { * Strings for setting the Role Description in english */ - //TODO: Eventually support fot other languages on talkback + //TODO: Eventually support for other languages on talkback public static void setRole(AccessibilityNodeInfoCompat nodeInfo, final AccessibilityRole role, final Context context) { nodeInfo.setClassName(role.getValue()); @@ -118,16 +131,10 @@ public class AccessibilityRoleUtil { /** * Method for setting accessibilityRole on view properties. */ - public static void updateAccessibilityRole(View view, String role) { + public static AccessibilityRole getAccessibilityRole(String role) { if (role == null) { - view.setAccessibilityDelegate(null); - } - try { - setRole(view, AccessibilityRole.valueOf(role.toUpperCase())); - } catch (NullPointerException e) { - view.setAccessibilityDelegate(null); - } catch (IllegalArgumentException e) { - view.setAccessibilityDelegate(null); + return AccessibilityRole.NONE; } + return AccessibilityRole.valueOf(role.toUpperCase()); } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java index e2c57825f..67f7932c8 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java @@ -28,6 +28,7 @@ public abstract class BaseViewManager + + + + + + + diff --git a/ReactAndroid/src/test/java/com/facebook/react/uimanager/BUCK b/ReactAndroid/src/test/java/com/facebook/react/uimanager/BUCK index 608ba5605..c51368c73 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/uimanager/BUCK +++ b/ReactAndroid/src/test/java/com/facebook/react/uimanager/BUCK @@ -16,6 +16,7 @@ rn_robolectric_test( deps = [ YOGA_TARGET, react_native_dep("libraries/fbcore/src/test/java/com/facebook/powermock:powermock"), + react_native_dep("third-party/android/support/v4:lib-support-v4"), react_native_dep("third-party/java/fest:fest"), react_native_dep("third-party/java/jsr-305:jsr-305"), react_native_dep("third-party/java/junit:junit"),