Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get view ID using Accessibility Service in android

I am a beginner to android. I want to get view id of the view, user is currently looking at. I make my question a bit more clear.Suppose user opens MakeMyTrip and navigates upto Flight booking page.Now i want to get the View id of that particular layout. Below is my service class and xml configuration file.

public class MyAccessibilityService extends AccessibilityService {
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {

    AccessibilityNodeInfo source = event.getSource();

    Log.d("ViewID",source.getViewIdResourceName());


}

@Override
public void onInterrupt() {

}



<accessibility-service
xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeWindowContentChanged"
android:accessibilityFeedbackType="feedbackGeneric"
android:accessibilityFlags="flagReportViewIds"
android:canRetrieveWindowContent="true"
android:description="@string/accessibility_service_description"
android:packageNames="com.makemytrip" />
like image 934
Raghu Avatar asked Feb 05 '23 12:02

Raghu


1 Answers

My guess is that your call to

Log.d("ViewID",source.getViewIdResourceName());

Is doing this:

Log.d("ViewID", null)

The source node of a window_content_changed event is going to be the root node of the layout whose content is updated. It is HIGHLY unlikely that this will have a viewIDResourceName. Most views don't have a resource name, and the view IDs that are accessible via direct access to the views are just auto generated hashes that don't mean anything. Only views with actual viewResourceNames have their names reported to accessibility services. So, if the element doesn't have an R.id.viewResourceName the accessibility service will report null for that value. Android Log utility cannot log a null value, you at least have to give it an empty string.

You should do this instead.

String viewIdName = source.getViewIdResourceName();
Log.d("ViewID", (viewIdName != null) ? viewIdName : "NO VIEW ID");

Notably, for where your printing it out, you will ALWAYS get "NO VIEW ID". You're going to have to crawl down the view hierarchy to find a view that has a resource name. Find some buttons or something where you've assigned IDs! Or potentially listen for different types of accessibility events. Watch out though! Not all events have sourceNodes! So, if you listen to

android:accessibilityEventTypes="typeAllMask"

You'll want to check for null source nodes as well. Or you'll get a different type of null pointer exception.

EDIT: Basic recursive function to log the entire accessibility node view hierarchy.

    public static void logViewHierarchy(AccessibilityNodeInfo nodeInfo, final int depth) {

    if (nodeInfo == null) return;

    String spacerString = "";

    for (int i = 0; i < depth; ++i) {
        spacerString += '-';
    }
    //Log the info you care about here... I choce classname and view resource name, because they are simple, but interesting.
    Log.d("TAG", spacerString + nodeInfo.getClassName() + " " + nodeInfo.getViewIdResourceName());

    for (int i = 0; i < nodeInfo.getChildCount(); ++i) {
        logViewHierarchy(nodeInfo.getChild(i), depth+1);
    }
}

//Then call it like this from anywhere in your service, don't necessarily have to use the root node.  
logViewHierarchy(getRootInActiveWindow(), 0);
like image 115
ChrisCM Avatar answered Feb 07 '23 12:02

ChrisCM