Example #1
0
  public static void sendAccessibilityEvent(final JSONObject message) {
    if (!sEnabled) return;

    final int eventType = message.optInt("eventType", -1);
    if (eventType < 0) {
      Log.e(LOGTAG, "No accessibility event type provided");
      return;
    }

    if (Versions.preJB) {
      // Before Jelly Bean we send events directly from here while spoofing the source by setting
      // the package and class name manually.
      ThreadUtils.postToBackgroundThread(
          new Runnable() {
            @Override
            public void run() {
              sendDirectAccessibilityEvent(eventType, message);
            }
          });
    } else {
      // In Jelly Bean we populate an AccessibilityNodeInfo with the minimal amount of data to have
      // it work with TalkBack.
      final LayerView view = GeckoAppShell.getLayerView();
      if (view == null) return;

      if (sVirtualCursorNode == null)
        sVirtualCursorNode = AccessibilityNodeInfo.obtain(view, VIRTUAL_CURSOR_POSITION);
      sVirtualCursorNode.setEnabled(message.optBoolean("enabled", true));
      sVirtualCursorNode.setClickable(message.optBoolean("clickable"));
      sVirtualCursorNode.setCheckable(message.optBoolean("checkable"));
      sVirtualCursorNode.setChecked(message.optBoolean("checked"));
      sVirtualCursorNode.setPassword(message.optBoolean("password"));

      final JSONArray textArray = message.optJSONArray("text");
      StringBuilder sb = new StringBuilder();
      if (textArray != null && textArray.length() > 0) {
        sb.append(textArray.optString(0));
        for (int i = 1; i < textArray.length(); i++) {
          sb.append(" ").append(textArray.optString(i));
        }
      }
      sVirtualCursorNode.setText(sb.toString());
      sVirtualCursorNode.setContentDescription(message.optString("description"));

      JSONObject bounds = message.optJSONObject("bounds");
      if (bounds != null) {
        Rect relativeBounds =
            new Rect(
                bounds.optInt("left"), bounds.optInt("top"),
                bounds.optInt("right"), bounds.optInt("bottom"));
        sVirtualCursorNode.setBoundsInParent(relativeBounds);
        int[] locationOnScreen = new int[2];
        view.getLocationOnScreen(locationOnScreen);
        Rect screenBounds = new Rect(relativeBounds);
        screenBounds.offset(locationOnScreen[0], locationOnScreen[1]);
        sVirtualCursorNode.setBoundsInScreen(screenBounds);
      }

      final JSONObject braille = message.optJSONObject("brailleOutput");
      if (braille != null) {
        sendBrailleText(
            view,
            braille.optString("text"),
            braille.optInt("selectionStart"),
            braille.optInt("selectionEnd"));
      }

      ThreadUtils.postToUiThread(
          new Runnable() {
            @Override
            public void run() {
              // If this is an accessibility focus, a lot of internal voodoo happens so we perform
              // an
              // accessibility focus action on the view, and it in turn sends the right events.
              switch (eventType) {
                case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED:
                  sEventMessage = message;
                  view.performAccessibilityAction(
                      AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
                  break;
                case AccessibilityEvent.TYPE_ANNOUNCEMENT:
                case AccessibilityEvent.TYPE_VIEW_SCROLLED:
                  sEventMessage = null;
                  final AccessibilityEvent accEvent = AccessibilityEvent.obtain(eventType);
                  view.onInitializeAccessibilityEvent(accEvent);
                  populateEventFromJSON(accEvent, message);
                  view.getParent().requestSendAccessibilityEvent(view, accEvent);
                  break;
                default:
                  sEventMessage = message;
                  view.sendAccessibilityEvent(eventType);
                  break;
              }
            }
          });
    }
  }