Remove accessibility panel from Layout Inspector in non-accessibility mode

Summary: Removes the Accessibility panel from the layout inspector since all of these properties are shown (and logged) in the Accessibility Inspector along with other properties that may be useful. This will make it easier to track accessibility use and also will help more people discover the accessibility feature when they need it.

Reviewed By: blavalla

Differential Revision: D9523532

fbshipit-source-id: f6d3a745980ec631ec8bf2e59017382f4c2edd5a
This commit is contained in:
Sara Valderrama
2018-08-28 09:48:47 -07:00
committed by Facebook Github Bot
parent a75b3f22ea
commit 7bd264bd10
3 changed files with 4 additions and 275 deletions

View File

@@ -196,8 +196,7 @@ public class ViewDescriptor extends NodeDescriptor<View> {
} }
return Arrays.asList( return Arrays.asList(
new Named<>("View", viewProps.build()), new Named<>("View", viewProps.build()));
new Named<>("Accessibility", getAccessibilityData(node)));
} }
@Override @Override
@@ -205,36 +204,13 @@ public class ViewDescriptor extends NodeDescriptor<View> {
return Arrays.asList( return Arrays.asList(
new Named<>(axNodeInfoPropsTitle, AccessibilityUtil.getAccessibilityNodeInfoData(node)), new Named<>(axNodeInfoPropsTitle, AccessibilityUtil.getAccessibilityNodeInfoData(node)),
new Named<>(axTalkbackPropsTitle, AccessibilityUtil.getTalkbackData(node)), new Named<>(axTalkbackPropsTitle, AccessibilityUtil.getTalkbackData(node)),
new Named<>(axViewPropsTitle, AccessibilityUtil.getViewAXData(node))); new Named<>(axViewPropsTitle, AccessibilityUtil.getViewData(node)));
}
private static SonarObject getAccessibilityData(View view) {
final SonarObject.Builder accessibilityProps = new SonarObject.Builder();
// This needs to be an empty string to be mutable. See t20470623.
CharSequence contentDescription =
view.getContentDescription() != null ? view.getContentDescription() : "";
accessibilityProps.put("content-description", InspectorValue.mutable(contentDescription));
accessibilityProps.put("focusable", InspectorValue.mutable(view.isFocusable()));
accessibilityProps.put("node-info", AccessibilityUtil.getAccessibilityNodeInfoProperties(view));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
accessibilityProps.put(
"important-for-accessibility",
AccessibilityUtil.sImportantForAccessibilityMapping.get(
view.getImportantForAccessibility()));
}
AccessibilityUtil.addTalkbackProperties(accessibilityProps, view);
return accessibilityProps.build();
} }
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
@Override @Override
public void setValue(View node, String[] path, SonarDynamic value) { public void setValue(View node, String[] path, SonarDynamic value) {
if (path[0].equals("Accessibility") if (path[0].equals(axViewPropsTitle)
|| path[0].equals(axViewPropsTitle)
|| path[0].equals(axNodeInfoPropsTitle) || path[0].equals(axNodeInfoPropsTitle)
|| path[0].equals(axTalkbackPropsTitle)) { || path[0].equals(axTalkbackPropsTitle)) {
setAccessibilityValue(node, path, value); setAccessibilityValue(node, path, value);

View File

@@ -510,75 +510,6 @@ public final class AccessibilityUtil {
} }
} }
/**
* Creates a {@link SonarObject} of useful properties of AccessibilityNodeInfo, to be shown in the
* Sonar Layout Inspector. All properties are immutable since they are all derived from various
* {@link View} properties.
*
* @param view The {@link View} to derive the AccessibilityNodeInfo properties from.
* @return {@link SonarObject} containing the properties.
*/
@Nullable
public static SonarObject getAccessibilityNodeInfoProperties(View view) {
final AccessibilityNodeInfoCompat nodeInfo =
ViewAccessibilityHelper.createNodeInfoFromView(view);
if (nodeInfo == null) {
return null;
}
final SonarObject.Builder nodeInfoProps = new SonarObject.Builder();
final Rect bounds = new Rect();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
final SonarArray.Builder actionsArrayBuilder = new SonarArray.Builder();
for (AccessibilityNodeInfoCompat.AccessibilityActionCompat action :
nodeInfo.getActionList()) {
final String actionLabel = (String) action.getLabel();
if (actionLabel != null) {
actionsArrayBuilder.put(actionLabel);
} else {
actionsArrayBuilder.put(
AccessibilityUtil.sAccessibilityActionMapping.get(action.getId(), false));
}
}
nodeInfoProps.put("actions", actionsArrayBuilder.build());
}
nodeInfoProps
.put("clickable", nodeInfo.isClickable())
.put("content-description", nodeInfo.getContentDescription())
.put("text", nodeInfo.getText())
.put("accessibility-focused", nodeInfo.isAccessibilityFocused())
.put("long-clickable", nodeInfo.isLongClickable())
.put("focusable", nodeInfo.isFocusable());
nodeInfo.getBoundsInParent(bounds);
nodeInfoProps.put(
"parent-bounds",
new SonarObject.Builder()
.put("width", bounds.width())
.put("height", bounds.height())
.put("top", bounds.top)
.put("left", bounds.left)
.put("bottom", bounds.bottom)
.put("right", bounds.right));
nodeInfo.getBoundsInScreen(bounds);
nodeInfoProps.put(
"screen-bounds",
new SonarObject.Builder()
.put("width", bounds.width())
.put("height", bounds.height())
.put("top", bounds.top)
.put("left", bounds.left)
.put("bottom", bounds.bottom)
.put("right", bounds.right));
nodeInfo.recycle();
return nodeInfoProps.build();
}
/** /**
* Creates a {@link SonarObject} of useful properties of AccessibilityNodeInfo, to be shown in the * Creates a {@link SonarObject} of useful properties of AccessibilityNodeInfo, to be shown in the
* Sonar Layout Inspector accessibility extension. All properties are immutable since they are all derived from * Sonar Layout Inspector accessibility extension. All properties are immutable since they are all derived from
@@ -697,7 +628,7 @@ public final class AccessibilityUtil {
} }
} }
public static SonarObject getViewAXData(View view) { public static SonarObject getViewData(View view) {
final SonarObject.Builder props = new SonarObject.Builder(); final SonarObject.Builder props = new SonarObject.Builder();
// This needs to be an empty string to be mutable. See t20470623. // This needs to be an empty string to be mutable. See t20470623.

View File

@@ -2,8 +2,6 @@
package com.facebook.sonar.plugins.litho; package com.facebook.sonar.plugins.litho;
import static com.facebook.litho.annotations.ImportantForAccessibility.IMPORTANT_FOR_ACCESSIBILITY_NO;
import static com.facebook.litho.annotations.ImportantForAccessibility.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS;
import static com.facebook.sonar.plugins.inspector.InspectorValue.Type.Color; import static com.facebook.sonar.plugins.inspector.InspectorValue.Type.Color;
import static com.facebook.sonar.plugins.inspector.InspectorValue.Type.Enum; import static com.facebook.sonar.plugins.inspector.InspectorValue.Type.Enum;
import static com.facebook.sonar.plugins.inspector.InspectorValue.Type.Number; import static com.facebook.sonar.plugins.inspector.InspectorValue.Type.Number;
@@ -30,8 +28,6 @@ import com.facebook.sonar.plugins.inspector.Named;
import com.facebook.sonar.plugins.inspector.NodeDescriptor; import com.facebook.sonar.plugins.inspector.NodeDescriptor;
import com.facebook.sonar.plugins.inspector.Touch; import com.facebook.sonar.plugins.inspector.Touch;
import com.facebook.sonar.plugins.inspector.descriptors.ObjectDescriptor; import com.facebook.sonar.plugins.inspector.descriptors.ObjectDescriptor;
import com.facebook.sonar.plugins.inspector.descriptors.utils.AccessibilityRoleUtil;
import com.facebook.sonar.plugins.inspector.descriptors.utils.AccessibilityUtil;
import com.facebook.yoga.YogaAlign; import com.facebook.yoga.YogaAlign;
import com.facebook.yoga.YogaDirection; import com.facebook.yoga.YogaDirection;
import com.facebook.yoga.YogaEdge; import com.facebook.yoga.YogaEdge;
@@ -49,9 +45,6 @@ import javax.annotation.Nullable;
public class DebugComponentDescriptor extends NodeDescriptor<DebugComponent> { public class DebugComponentDescriptor extends NodeDescriptor<DebugComponent> {
private static final String axViewPropsTitle = "DebugLayoutNode";
private static final String axNodeInfoPropsTitle = "NodeInfo & TalkBack";
private Map<String, List<Pair<String[], SonarDynamic>>> mOverrides = new HashMap<>(); private Map<String, List<Pair<String[], SonarDynamic>>> mOverrides = new HashMap<>();
private DebugComponent.Overrider mOverrider = private DebugComponent.Overrider mOverrider =
new DebugComponent.Overrider() { new DebugComponent.Overrider() {
@@ -100,10 +93,6 @@ public class DebugComponentDescriptor extends NodeDescriptor<DebugComponent> {
override.second); override.second);
} catch (Exception ignored) { } catch (Exception ignored) {
} }
} else if (override.first[0].equals("Accessibility")
|| override.first[0].equals(axViewPropsTitle)
|| override.first[0].equals(axNodeInfoPropsTitle)) {
applyAccessibilityOverride(node, override.first[1], override.second);
} }
} }
} }
@@ -175,98 +164,9 @@ public class DebugComponentDescriptor extends NodeDescriptor<DebugComponent> {
data.add(new Named<>("State", stateData)); data.add(new Named<>("State", stateData));
} }
final SonarObject accessibilityData = getAccessibilityData(node);
if (accessibilityData != null) {
data.add(new Named<>("Accessibility", accessibilityData));
}
return data; return data;
} }
@Override
public List<Named<SonarObject>> getAXData(DebugComponent node) throws Exception {
NodeDescriptor componentDescriptor = descriptorForClass(node.getComponent().getClass());
if (componentDescriptor.getClass() != ObjectDescriptor.class) {
return componentDescriptor.getAXData(node.getComponent());
}
final List<Named<SonarObject>> sections = new ArrayList<>();
final SonarObject derivedData = getDerivedAXData(node);
if (derivedData != null) {
sections.add(new Named<>(axNodeInfoPropsTitle, derivedData));
}
final SonarObject viewData = getViewAXData(node);
if (viewData != null) {
sections.add(new Named<>(axViewPropsTitle, viewData));
}
return sections;
}
@Nullable
private static SonarObject getViewAXData(DebugComponent node) {
final DebugLayoutNode layout = node.getLayoutNode();
if (layout == null) {
return null;
}
final SonarObject.Builder props = new SonarObject.Builder();
// This needs to be an empty string to be mutable. See t20470623.
final CharSequence contentDescription =
layout.getContentDescription() != null ? layout.getContentDescription() : "";
props.put("content-description", InspectorValue.mutable(contentDescription));
props.put("focusable", InspectorValue.mutable(layout.getFocusable()));
props.put(
"important-for-accessibility",
AccessibilityUtil.sImportantForAccessibilityMapping.get(
layout.getImportantForAccessibility()));
return props.build();
}
@Nullable
private static SonarObject getDerivedAXData(DebugComponent node) {
final DebugLayoutNode layout = node.getLayoutNode();
if (layout == null) {
return null;
}
final View hostView = node.getComponentHost();
final SonarObject.Builder props = new SonarObject.Builder();
// No host view exists, so this component is inherently not accessible. Add the reason why this
// is the case and then return.
if (hostView == node.getLithoView() || hostView == null) {
final int importantForAccessibility = layout.getImportantForAccessibility();
final boolean isAccessibilityEnabled =
AccessibilityUtil.isAccessibilityEnabled(node.getContext());
String ignoredReason;
if (!isAccessibilityEnabled) {
ignoredReason = "No accessibility service is running.";
} else if (importantForAccessibility == IMPORTANT_FOR_ACCESSIBILITY_NO) {
ignoredReason = "Component has importantForAccessibility set to NO.";
} else if (importantForAccessibility == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) {
ignoredReason = "Component has importantForAccessibility set to NO_HIDE_DESCENDANTS.";
} else {
ignoredReason = "Component does not have content, or accessibility handlers.";
}
props.put("talkback-ignored", true);
props.put("talkback-ignored-reasons", ignoredReason);
return props.build();
}
// host view exists so add node info and TalkBack properties
props.put("node-info", AccessibilityUtil.getAccessibilityNodeInfoData(hostView));
AccessibilityUtil.addTalkbackProperties(props, hostView);
return props.build();
}
@Nullable @Nullable
private static SonarObject getLayoutData(DebugComponent node) { private static SonarObject getLayoutData(DebugComponent node) {
final DebugLayoutNode layout = node.getLayoutNode(); final DebugLayoutNode layout = node.getLayoutNode();
@@ -466,57 +366,6 @@ public class DebugComponentDescriptor extends NodeDescriptor<DebugComponent> {
return false; return false;
} }
@Nullable
private static SonarObject getAccessibilityData(DebugComponent node) {
final DebugLayoutNode layout = node.getLayoutNode();
if (layout == null) {
return null;
}
final View hostView = node.getComponentHost();
final SonarObject.Builder accessibilityProps = new SonarObject.Builder();
// This needs to be an empty string to be mutable. See t20470623.
final CharSequence contentDescription =
layout.getContentDescription() != null ? layout.getContentDescription() : "";
accessibilityProps.put("content-description", InspectorValue.mutable(contentDescription));
accessibilityProps.put("focusable", InspectorValue.mutable(layout.getFocusable()));
accessibilityProps.put(
"important-for-accessibility",
AccessibilityUtil.sImportantForAccessibilityMapping.get(
layout.getImportantForAccessibility()));
// No host view exists, so this component is inherently not accessible. Add the reason why this
// is the case and then return.
if (hostView == node.getLithoView() || hostView == null) {
final int importantForAccessibility = layout.getImportantForAccessibility();
final boolean isAccessibilityEnabled =
AccessibilityUtil.isAccessibilityEnabled(node.getContext());
String ignoredReason;
if (!isAccessibilityEnabled) {
ignoredReason = "No accessibility service is running.";
} else if (importantForAccessibility == IMPORTANT_FOR_ACCESSIBILITY_NO) {
ignoredReason = "Component has importantForAccessibility set to NO.";
} else if (importantForAccessibility == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) {
ignoredReason = "Component has importantForAccessibility set to NO_HIDE_DESCENDANTS.";
} else {
ignoredReason = "Component does not have content, or accessibility handlers.";
}
accessibilityProps.put("talkback-ignored", true);
accessibilityProps.put("talkback-ignored-reasons", ignoredReason);
return accessibilityProps.build();
}
accessibilityProps.put(
"node-info", AccessibilityUtil.getAccessibilityNodeInfoProperties(hostView));
AccessibilityUtil.addTalkbackProperties(accessibilityProps, hostView);
return accessibilityProps.build();
}
@Override @Override
public void setValue(DebugComponent node, String[] path, SonarDynamic value) { public void setValue(DebugComponent node, String[] path, SonarDynamic value) {
List<Pair<String[], SonarDynamic>> overrides = mOverrides.get(node.getGlobalKey()); List<Pair<String[], SonarDynamic>> overrides = mOverrides.get(node.getGlobalKey());
@@ -547,17 +396,6 @@ public class DebugComponentDescriptor extends NodeDescriptor<DebugComponent> {
return attributes; return attributes;
} }
@Override
public List<Named<String>> getAXAttributes(DebugComponent node) {
final View hostView = node.getComponentHost();
List<Named<String>> attributes = new ArrayList<>();
String role = AccessibilityRoleUtil.getRole(hostView).toString();
if (!role.equals("NONE")) {
attributes.add(new Named<>("role", role));
}
return attributes;
}
@Override @Override
public SonarObject getExtraInfo(DebugComponent node) { public SonarObject getExtraInfo(DebugComponent node) {
SonarObject.Builder extraInfo = new SonarObject.Builder(); SonarObject.Builder extraInfo = new SonarObject.Builder();
@@ -659,22 +497,6 @@ public class DebugComponentDescriptor extends NodeDescriptor<DebugComponent> {
return descriptor.matches(query, node); return descriptor.matches(query, node);
} }
private static void applyAccessibilityOverride(
DebugLayoutNode node, String key, SonarDynamic value) {
switch (key) {
case "focusable":
node.setFocusable(value.asBoolean());
break;
case "important-for-accessibility":
node.setImportantForAccessibility(
AccessibilityUtil.sImportantForAccessibilityMapping.get(value.asString()));
break;
case "content-description":
node.setContentDescription(value.asString());
break;
}
}
private static void applyLayoutOverride(DebugLayoutNode node, String[] path, SonarDynamic value) { private static void applyLayoutOverride(DebugLayoutNode node, String[] path, SonarDynamic value) {
switch (path[0]) { switch (path[0]) {
case "background": case "background":