private AccessibilityNodeInfo findNodeRegularRecursive(
      UiSelector subSelector, AccessibilityNodeInfo fromNode, int index) {

    if (subSelector.isMatchFor(fromNode, index)) {
      if (DEBUG) {
        Log.d(LOG_TAG, formatLog(String.format("%s", subSelector.dumpToString(false))));
      }
      if (subSelector.isLeaf()) {
        return fromNode;
      }
      if (subSelector.hasChildSelector()) {
        mLogIndent++; // next selector
        subSelector = subSelector.getChildSelector();
        if (subSelector == null) {
          Log.e(LOG_TAG, "Error: A child selector without content");
          return null; // there is an implementation fault
        }
      } else if (subSelector.hasParentSelector()) {
        mLogIndent++; // next selector
        subSelector = subSelector.getParentSelector();
        if (subSelector == null) {
          Log.e(LOG_TAG, "Error: A parent selector without content");
          return null; // there is an implementation fault
        }
        // the selector requested we start at this level from
        // the parent node from the one we just matched
        fromNode = fromNode.getParent();
        if (fromNode == null) return null;
      }
    }

    int childCount = fromNode.getChildCount();
    boolean hasNullChild = false;
    for (int i = 0; i < childCount; i++) {
      AccessibilityNodeInfo childNode = fromNode.getChild(i);
      if (childNode == null) {
        Log.w(
            LOG_TAG,
            String.format("AccessibilityNodeInfo returned a null child (%d of %d)", i, childCount));
        if (!hasNullChild) {
          Log.w(LOG_TAG, String.format("parent = %s", fromNode.toString()));
        }
        hasNullChild = true;
        continue;
      }
      if (!childNode.isVisibleToUser()) {
        if (VERBOSE)
          Log.v(LOG_TAG, String.format("Skipping invisible child: %s", childNode.toString()));
        continue;
      }
      AccessibilityNodeInfo retNode = findNodeRegularRecursive(subSelector, childNode, i);
      if (retNode != null) {
        return retNode;
      }
    }
    return null;
  }
  private AccessibilityNodeInfo findNodePatternRecursive(
      UiSelector subSelector,
      AccessibilityNodeInfo fromNode,
      int index,
      UiSelector originalPattern) {

    if (subSelector.isMatchFor(fromNode, index)) {
      if (subSelector.isLeaf()) {
        if (mPatternIndexer == 0) {
          if (DEBUG)
            Log.d(LOG_TAG, formatLog(String.format("%s", subSelector.dumpToString(false))));
          return fromNode;
        } else {
          if (DEBUG)
            Log.d(LOG_TAG, formatLog(String.format("%s", subSelector.dumpToString(false))));
          mPatternCounter++; // count the pattern matched
          mPatternIndexer--; // decrement until zero for the instance requested

          // At a leaf selector within a group and still not instance matched
          // then reset the  selector to continue search from current position
          // in the accessibility tree for the next pattern match up until the
          // pattern index hits 0.
          subSelector = originalPattern;
          // starting over with next pattern search so reset to parent level
          mLogIndent = mLogParentIndent;
        }
      } else {
        if (DEBUG) Log.d(LOG_TAG, formatLog(String.format("%s", subSelector.dumpToString(false))));

        if (subSelector.hasChildSelector()) {
          mLogIndent++; // next selector
          subSelector = subSelector.getChildSelector();
          if (subSelector == null) {
            Log.e(LOG_TAG, "Error: A child selector without content");
            return null;
          }
        } else if (subSelector.hasParentSelector()) {
          mLogIndent++; // next selector
          subSelector = subSelector.getParentSelector();
          if (subSelector == null) {
            Log.e(LOG_TAG, "Error: A parent selector without content");
            return null;
          }
          fromNode = fromNode.getParent();
          if (fromNode == null) return null;
        }
      }
    }

    int childCount = fromNode.getChildCount();
    boolean hasNullChild = false;
    for (int i = 0; i < childCount; i++) {
      AccessibilityNodeInfo childNode = fromNode.getChild(i);
      if (childNode == null) {
        Log.w(
            LOG_TAG,
            String.format("AccessibilityNodeInfo returned a null child (%d of %d)", i, childCount));
        if (!hasNullChild) {
          Log.w(LOG_TAG, String.format("parent = %s", fromNode.toString()));
        }
        hasNullChild = true;
        continue;
      }
      if (!childNode.isVisibleToUser()) {
        if (DEBUG)
          Log.d(LOG_TAG, String.format("Skipping invisible child: %s", childNode.toString()));
        continue;
      }
      AccessibilityNodeInfo retNode =
          findNodePatternRecursive(subSelector, childNode, i, originalPattern);
      if (retNode != null) {
        return retNode;
      }
    }
    return null;
  }