1

I'm trying perform click using following code but here says that exists some limitations and i can see this in my tests.

But seems that this bug is caused because Rect() not contains X, Y coordenates, why everytime that i click in a place where not is supported (probably some limitation like was said on readme file on the example) is executed this line in findSmallestNodeAtPoint() routine:

if (!bounds.contains(x, y)) {
      System.out.println("ERROR DETECTED!!! :::::: NOT bounds.contains(x, y) :::::::");
      return null;
   }

Here in this question, also is mentioned this example of Github and was gived a answer with a code example working 100% (tested) from android Nougat+ (api 24 and above), but in my case i need fix this code below to my app also support perform click in previous versions of android.

Then already knowing where this code is failing, i want know what can be made related to:

!bounds.contains(x, y)

The main part of code is:

private static void logNodeHierachy(AccessibilityNodeInfo nodeInfo, int depth) {
    Rect bounds = new Rect();
    nodeInfo.getBoundsInScreen(bounds);

    StringBuilder sb = new StringBuilder();
    if (depth > 0) {
        for (int i=0; i<depth; i++) {
            sb.append("  ");
        }
        sb.append("\u2514 ");
    }
    sb.append(nodeInfo.getClassName());
    sb.append(" (" + nodeInfo.getChildCount() +  ")");
    sb.append(" " + bounds.toString());
    if (nodeInfo.getText() != null) {
        sb.append(" - \"" + nodeInfo.getText() + "\"");
    }
    System.out.println(sb.toString());

    for (int i=0; i<nodeInfo.getChildCount(); i++) {
        AccessibilityNodeInfo childNode = nodeInfo.getChild(i);
        if (childNode != null) {
            logNodeHierachy(childNode, depth + 1);
        }
    }
}

private static AccessibilityNodeInfo findSmallestNodeAtPoint(AccessibilityNodeInfo sourceNode, int x, int y) {
    Rect bounds = new Rect();
    sourceNode.getBoundsInScreen(bounds);

    if (!bounds.contains(x, y)) {
        System.out.println(":::::: NOT bounds.contains(x, y) :::::::");
        return null;
    }

    for (int i=0; i<sourceNode.getChildCount(); i++) {
        AccessibilityNodeInfo nearestSmaller = findSmallestNodeAtPoint(sourceNode.getChild(i), x, y);
        if (nearestSmaller != null) {
            return nearestSmaller;
        }
    }
    return sourceNode;
}

public void click(int x, int y) {
    System.out.println(String.format("Click [%d, %d]", x, y));
    AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
    if (nodeInfo == null) return;
    AccessibilityNodeInfo nearestNodeToMouse = findSmallestNodeAtPoint(nodeInfo, x, y);
    if (nearestNodeToMouse != null) {
        logNodeHierachy(nearestNodeToMouse, 0);
        nearestNodeToMouse.performAction(AccessibilityNodeInfo.ACTION_CLICK);
    }
    nodeInfo.recycle();
}

1 Answers1

4

OK, i answer my own question, already that the experts in AccessibilityService thinking that i'm building a malware and not like of help these kind of people.


Apparently seems that not is possible escape of use Rect() and getBoundsInScreen() based in this answer.

Also i found another code similar, ref:

public void click(int x, int y) {

    clickAtPosition(x, y, getRootInActiveWindow());
}

public static void clickAtPosition(int x, int y, AccessibilityNodeInfo node) {
    if (node == null) return;

    if (node.getChildCount() == 0) {
        Rect buttonRect = new Rect();
        node.getBoundsInScreen(buttonRect);
        if (buttonRect.contains(x, y)) {
            // Maybe we need to think if a large view covers item?
            node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
            System.out.println("1º - Node Information: " + node.toString());
        }
    } else {
        Rect buttonRect = new Rect();
        node.getBoundsInScreen(buttonRect);
        if (buttonRect.contains(x, y)) {
            // Maybe we need to think if a large view covers item?
            node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
            System.out.println("2º - Node Information: " + node.toString());
        }
        for (int i = 0; i < node.getChildCount(); i++) {
            clickAtPosition(x, y, node.getChild(i));
        }
    }
}

and also have trouble. But is better than code linked on question above :D.

In my tests only not was able to perform click on android virtual keyboard.