/** Interrupts the speech controller. */
  private void interrupt() {
    final TalkBackService service = TalkBackService.getInstance();
    if (service == null) {
      LogUtils.log(Log.ERROR, "Failed to get TalkBackService instance.");
      return;
    }

    final SpeechController speechController = service.getSpeechController();
    speechController.interrupt();
  }
  /**
   * Sends the instruction text to the speech controller for queuing.
   *
   * @param resId The resource value of the instruction string.
   * @param formatArgs Optional formatting arguments.
   * @see String#format(String, Object...)
   */
  private void speakInternal(int resId, Object... formatArgs) {
    final TalkBackService service = TalkBackService.getInstance();
    if (service == null) {
      LogUtils.log(Log.ERROR, "Failed to get TalkBackService instance.");
      return;
    }

    final SpeechController speechController = service.getSpeechController();
    final String text = getString(resId, formatArgs);
    speechController.speak(text, null, null, 0, 0, null, null, mUtteranceCompleteRunnable);
  }
  /**
   * Populates a {@link RadialMenu} with items specific to the provided node based on {@link
   * NodeMenuRule}s.
   *
   * @param menu The menu to populate.
   * @param node The node with which to populate the menu.
   * @return {@code true} if successful, {@code false} otherwise.
   */
  public boolean prepareMenuForNode(RadialMenu menu, AccessibilityNodeInfoCompat node) {
    if (node == null) {
      return false;
    }

    // Always reset the menu since it is based on the current cursor.
    menu.clear();

    // Track which rules accept the node.
    final LinkedList<NodeMenuRule> matchingRules = new LinkedList<NodeMenuRule>();
    for (NodeMenuRule rule : mRules) {
      if (rule.accept(mService, node)) {
        matchingRules.add(rule);
      }
    }

    boolean canCollapseMenu = false;

    for (NodeMenuRule rule : matchingRules) {
      final List<RadialMenuItem> ruleResults = rule.getMenuItemsForNode(mService, node);
      if (ruleResults.isEmpty()) {
        continue;
      }

      final CharSequence subMenuName = rule.getUserFriendlyMenuName(mService);
      final RadialSubMenu ruleSubMenu =
          menu.addSubMenu(RadialMenu.NONE, 0, RadialMenu.NONE, subMenuName);
      ruleSubMenu.addAll(ruleResults);

      canCollapseMenu |= rule.canCollapseMenu();
    }

    // Collapse if the menu contains only a single collapsible sub-menu.
    if ((menu.size() == 1) && canCollapseMenu) {
      collapseSubMenus(menu);
    }

    if (menu.size() == 0) {
      mSpeechController.speak(
          mService.getString(R.string.title_local_breakout_no_items),
          SpeechController.QUEUE_MODE_FLUSH_ALL,
          FeedbackItem.FLAG_NO_HISTORY,
          null);
      return false;
    }

    return true;
  }