public static CharSequence getTalkbackDescription()

in android/src/main/java/com/facebook/flipper/plugins/inspector/descriptors/utils/AccessibilityUtil.java [456:550]


  public static CharSequence getTalkbackDescription(View view) {
    final AccessibilityNodeInfoCompat node = ViewAccessibilityHelper.createNodeInfoFromView(view);
    if (node == null) {
      return null;
    }
    try {
      final CharSequence contentDescription = node.getContentDescription();
      final CharSequence nodeText = node.getText();

      final boolean hasNodeText = !TextUtils.isEmpty(nodeText);
      final boolean isEditText = view instanceof EditText;

      StringBuilder talkbackSegments = new StringBuilder();
      AccessibilityRoleUtil.AccessibilityRole role = AccessibilityRoleUtil.getRole(view);
      String roleString = getRoleDescription(view);
      boolean disabled =
          AccessibilityEvaluationUtil.isActionableForAccessibility(node) && !node.isEnabled();

      // EditText's prioritize their own text content over a contentDescription so skip this
      if (!TextUtils.isEmpty(contentDescription) && (!isEditText || !hasNodeText)) {

        // first prepend any status modifiers
        addStateSegments(talkbackSegments, node, role);

        // next add content description
        talkbackSegments.append(contentDescription + delimiter);

        // then role
        if (roleString.length() > 0) {
          talkbackSegments.append(roleString + delimiter);
        }

        // lastly disabled is appended if applicable
        if (disabled) {
          talkbackSegments.append("disabled" + delimiter);
        }

        return removeFinalDelimiter(talkbackSegments);
      }

      // EditText
      if (hasNodeText) {
        // skipped status checks above for EditText

        // password
        if (node.isPassword()) {
          talkbackSegments.append("password" + delimiter);
        }

        // description
        talkbackSegments.append(nodeText + delimiter);

        // role
        if (roleString.length() > 0) {
          talkbackSegments.append(roleString + delimiter);
        }

        // disabled
        if (disabled) {
          talkbackSegments.append("disabled" + delimiter);
        }

        return removeFinalDelimiter(talkbackSegments);
      }

      // If there are child views and no contentDescription the text of all non-focusable children,
      // comma separated, becomes the description.
      if (view instanceof ViewGroup) {
        final StringBuilder concatChildDescription = new StringBuilder();
        final ViewGroup viewGroup = (ViewGroup) view;

        for (int i = 0, count = viewGroup.getChildCount(); i < count; i++) {
          final View child = viewGroup.getChildAt(i);

          final AccessibilityNodeInfoCompat childNodeInfo = AccessibilityNodeInfoCompat.obtain();
          ViewCompat.onInitializeAccessibilityNodeInfo(child, childNodeInfo);

          if (AccessibilityEvaluationUtil.isSpeakingNode(childNodeInfo, child)
              && !AccessibilityEvaluationUtil.isAccessibilityFocusable(childNodeInfo, child)) {
            CharSequence childNodeDescription = getTalkbackDescription(child);
            if (!TextUtils.isEmpty(childNodeDescription)) {
              concatChildDescription.append(childNodeDescription + delimiter);
            }
          }
          childNodeInfo.recycle();
        }

        return removeFinalDelimiter(concatChildDescription);
      }

      return null;
    } finally {
      node.recycle();
    }
  }