Additional Accessibility Roles and States (#24095)

Summary:
Assistive technologies use the accessibility role of a component to tell the disabled user what the component is, and provide hints about how to use it. Many important roles do not have analog AccessibilityTraits on iOS. This PR adds many critical roles, such as editabletext, checkbox, menu, and switch to name a few.

Accessibility states are used to convey the current state of a component. This PR adds several critical states such as checked, unchecked, on and off.

[general] [change] - Adds critical accessibility roles and states.
Pull Request resolved: https://github.com/facebook/react-native/pull/24095

Differential Revision: D15079245

Pulled By: cpojer

fbshipit-source-id: 941b30eb8f5d565597e5ea3a04687d9809cbe372
This commit is contained in:
Marc Mulcahy authored and Facebook Github Bot committed 2019-04-25 06:13:07 -07:00
1 parent 421ffb05ae
commit 1aeac1c625
10 files changed
+743 -120

No files matched your search

@@ -9,6 +9,9 @@ import android.graphics.Color;
import android.view.View;
import android.view.ViewParent;
import androidx.core.view.ViewCompat;
import java.util.HashMap;
import com.facebook.react.R;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.uimanager.AccessibilityDelegateUtil.AccessibilityRole;
@@ -57,6 +60,13 @@ public abstract class BaseViewManager<T extends View, C extends LayoutShadowNode
new MatrixMathHelper.MatrixDecompositionContext();
private static double[] sTransformDecompositionArray = new double[16];
public static final HashMap<String, Integer> sStateDescription= new HashMap<String, Integer>();
static {
sStateDescription.put("busy", R.string.state_busy_description);
sStateDescription.put("expanded", R.string.state_expanded_description);
sStateDescription.put("collapsed", R.string.state_collapsed_description);
}
@ReactProp(name = PROP_BACKGROUND_COLOR, defaultInt = Color.TRANSPARENT, customType = "Color")
public void setBackgroundColor(@Nonnull T view, int backgroundColor) {
view.setBackgroundColor(backgroundColor);
@@ -112,12 +122,14 @@ public abstract class BaseViewManager<T extends View, C extends LayoutShadowNode
@ReactProp(name = PROP_ACCESSIBILITY_LABEL)
public void setAccessibilityLabel(@Nonnull T view, String accessibilityLabel) {
view.setContentDescription(accessibilityLabel);
view.setTag(R.id.accessibility_label, accessibilityLabel);
updateViewContentDescription(view);
}
@ReactProp(name = PROP_ACCESSIBILITY_HINT)
public void setAccessibilityHint(@Nonnull T view, String accessibilityHint) {
view.setTag(R.id.accessibility_hint, accessibilityHint);
updateViewContentDescription(view);
}
@ReactProp(name = PROP_ACCESSIBILITY_ROLE)
@@ -125,27 +137,47 @@ public abstract class BaseViewManager<T extends View, C extends LayoutShadowNode
if (accessibilityRole == null) {
return;
}
view.setTag(R.id.accessibility_role, AccessibilityRole.fromValue(accessibilityRole));
}
@ReactProp(name = PROP_ACCESSIBILITY_STATES)
public void setViewStates(@Nonnull T view, @Nullable ReadableArray accessibilityStates) {
view.setSelected(false);
view.setEnabled(true);
if (accessibilityStates == null) {
return;
}
view.setTag(R.id.accessibility_states, accessibilityStates);
for (int i = 0; i < accessibilityStates.size(); i++) {
String state = accessibilityStates.getString(i);
if (state.equals("selected")) {
view.setSelected(true);
} else if (state.equals("disabled")) {
view.setEnabled(false);
if (sStateDescription.containsKey(state)) {
updateViewContentDescription(view);
}
}
}
private void updateViewContentDescription(@Nonnull T view) {
final String accessibilityLabel = (String) view.getTag(R.id.accessibility_label);
final ReadableArray accessibilityStates = (ReadableArray) view.getTag(R.id.accessibility_states);
final String accessibilityHint = (String) view.getTag(R.id.accessibility_hint);
StringBuilder contentDescription = new StringBuilder();
if (accessibilityLabel != null) {
contentDescription.append(accessibilityLabel + ", ");
}
if (accessibilityStates != null) {
for (int i = 0; i < accessibilityStates.size(); i++) {
String state = accessibilityStates.getString(i);
if (sStateDescription.containsKey(state)) {
contentDescription.append(view.getContext().getString(sStateDescription.get(state)) + ", ");
}
}
}
if (accessibilityHint != null) {
contentDescription.append(accessibilityHint + ", ");
}
if (contentDescription.length() > 0) {
view.setContentDescription(contentDescription.toString());
}
}
@ReactProp(name = PROP_IMPORTANT_FOR_ACCESSIBILITY)
public void setImportantForAccessibility(@Nonnull T view, @Nullable String importantForAccessibility) {
if (importantForAccessibility == null || importantForAccessibility.equals("auto")) {