FindNode Examples

Query in Action I

The most basic query is "{}" or in TC:

var output = device.sendAai({})

This returns most of the nodes on the screen and the default return is a list of nodes ID (action: "getIds"):

{count: 89, ids: ['80006cbe','7440','7bc2','7f83','8344','8705','8ac6','8e87','1f6e7',…]}

You can do something like:

{query: “CC:!=0"} or {query:”CC:>0}: Non-zero child count.

{query:”IT:>10000"}, accept custom input type value that is greater than 10 thousand.

{query:"CC:!=0&&IT:>10000"}, find nodes with non-zero child count AND input type is greater than 10,000.

{query:”TP:textInput&&IX:2”, action:”setText(Hello)”}, find third text field and enter “Hello” in the text field.

{query:”T:Input text here”, action:”setText(Hello)"}, find empty text field has initial hint text, search the hint and enter “Hello”.

{query:”C:.TextView&&T: Contacts"}
>> device.sendAai({query:"T:*REAL, \nSANTA CLARA*", action:"getText"})
{retval: '3367 EL CAMINO REAL, 
>> device.sendAai({actions:["scrollIntoView(T:ci:john)", "click"]})

Query in Action II

Example 1: Finding nodes on the bottom of the screen:

>> device.sendAai({query:"LB:-1", action:"getText"})
{retval: ['Chats','Calls','Contacts','Notifications']}

By using offset (OX), index (IX) or query such as "T:", you can locate almost every node on the above examples, below 3 examples on click "Contacts" icon:

>> device.sendAai({query:"LB:1&&IX:2", action:"click"})
{retval: true}
>> device.sendAai({query:"LB:-1&&T:Contacts&&OY:-1", action:"click"})
{retval: true}
>> device.sendAai({query:"LB:-1", action:"click(T:Contacts&&OY:-1)"})
{retval: true}

The purpose of the line mode is to control the icons on the top/bottom. The red counter intersects with Chats icon will be removed. So for the line of icons, it is 4 nodes instead of 5 nodes:

>> device.sendAai({query:"LB:1"})
{count: 4, ids: ['14735','17080','18ac7','1a50e']}

If you want the counter, use other query (IX:-1 or ON:last can be used to prevent finding other "Chats" on the screen, pick the last "Chats"), the second line below will work since offset will not ignore intersected nodes:

>> device.sendAai({query:"T:Chats&&IX:-1&&OY:-1&&OX:1", action:"getText"})
{retval: '1'}
>> device.sendAai({query:"LB:-1&&T:Chats&&OY:-1&&OX:1", action:"getText"})
{retval: '1'}

Example 2: Retrieve information from About phone:

To obtain the information:

>> device.sendAai({query:"T:Model name&&OX:1", action:"getText"})
{retval: 'Galaxy S10+'}

Alternatively, you can use UiElement class:

>> var obj = UiElement.findObject(device, "T:Model name&&OX:1")
UiElement: 3d012
>> obj.getText()
Galaxy S10+

Example 3: Assuming you want to first page stock tickers from Yahoo Finance:

>> device.sendAai({query:"R:.ticker&&T:/[A-Z]{1,4}/", action:"getText"}).retval.forEach(
    (p) => {print( p + ":" +
            device.sendAai({action:"getDescription(OX:1&&T:" + p + ")"}).retval

Example 4: Enter text in Skype text box:

Before entering text:

After text is input, need to click the button to send:

This can be done by using in one query command:

>> var input = "Hello";
>> device.sendAai({query:"LB:1&&TP:textInput", actions:[aaix("setText", input), "click(OX:2)"]});
{count: 2, list: [{retval: true},{retval: true}]}

aaix("setText", input) will return 'setText("Hello")', much better than 'setText("'+input+'")', useful for multiple arguments.

The following function to find the person, click, send a message and return back to main page.

function sendAai(device, obj) {
    var retval = device.sendAai(obj);
    if (retval == null) {
        throw "Error on: " + JSON.stringify(obj) + ":" + lastError();
    print("$ " + JSON.stringify(obj) + "\n" + JSON.stringify(retval));
    return retval;

function sendSkype(device, name, text) {
    sendAai(device, {actions:[
        aaix("scrollIntoView", "T:" + name), 
        aaix("setText", text), 
        "waitQuery(T:Type a message)",

sendSkype(device, "John", "I will get back to you");

Example 5: On the first example, you can use “T:<text>” and offset to click the icons, some applications do not provide the text:

Since this is display on the last line, we can use “LB:-1” to return the nodes, then use “IX” to locate a single node from the list of nodes, to click the search icon:

device.sendAai({query:"LB:-1&&IX:2", action:"click"})

Example 6: In certain chat window, it shows the name (or phone number), to obtain it, use the following queries:

>> device.sendAai({query:"LT:1&&IX:1", action:"getText"})
{retval: (999)999-9999}

To go back, click left arrow:

>> device.sendAai({query:"LT:1&&IX:0", action:"click"})
{retval: true}

Note: The new version of "Messages", "LT" and "LB" no longer works, you can still retrieve first line or last line of information, use "VG" to obtain group information and "RN" to reduce to interested nodes..

First line:

>> device.sendAai({query:"TP:reduced&&IX:0&&VG&&RN"})
{count: 6, ids: ['1669cf','168f59','16931a','1696db','169a9c','167151']}

Last line:

>> device.sendAai({query:"TP:reduced&&IX:-1&&VG&&RN"})
{count: 5, ids: ['16227c','162dbf','15db29','15deea','16570a']}

After receiving the nodes, can select the nodes using addQuery() or perform actions.

Example 7: Locate and click with ease.

To click the arrow, use:

>> device.sendAai({query:"T:Channels&&OX:1", action:"click"})
{retval: true}

Query in Action III

Example 1: Consider the following grocery app:

To add oranges into cart, "scrollIntoView" will scroll until "*Orange*" is found and store "Valencia Oranges …" node in ML, VG&&RN will obtain ViewGroup and optimize the number of nodes. Use UI Explorer to find out the resource ID of the price and the "+" button to save into cart.

>> device.sendAai({actions:[
{count: 4, list: [{retval: true},{count: 8},{retval: '$6.99'},{retval: true}]}

Example 2: Use "checked" to manipulate the checkboxes.

To expand, need to use to match different kind of white space:

>> device.sendAai({query:"T:/3:00\\sAM/&&OX:1", action:"click"})
{retval: true}

To change the checked box next to today from true to false, use "checked", still need to use "3:00 AM" because there may have other alarms with "Today" on the screen.

>> device.sendAai({query:"T:/3:00\\sAM/&&OY:1&&OX:1", actions:["getChecked", "setChecked(false)", "getChecked"]})
{count: 3, list: [{retval: true},{changedCount: 1},{retval: false}]}

For recurring alarm, from Sunday to Saturday, for instance, it is using "D:Sunday" and "T:S" to represent the first checkbox. Use intersectX (TX) to get all checked boxes. In this example "C:.CheckBox" is not needed but nice to have as example:

>> device.sendAai({action:"getDescription(D:Sunday&&C:.CheckBox&&TX)"})
{retval: ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday']}

To check on all checkboxes, setChecked does not support query, it returns how many has been changed.

>> device.sendAai({query:"D:Sunday&&C:.CheckBox&&TX", action:"setChecked(true)"})
{changedCount: 7}

There are several ways to turn off Sunday and Saturday:

>> device.sendAai({query:"D:/Sunday|Saturday/", action:"setChecked(false)"})
{changedCount: 2}
>> device.sendAai({query:"T:S", action:"setChecked(false)"})
{changedCount: 2}

To obtain the value of these checkboxes:
>> device.sendAai({query:"D:Sunday&&C:.CheckBox&&TX", action:"getChecked"})
{retval: [false,true,true,true,true,true,false]}

Example 3: The order of OY and OX is important, below is one of the developer options:

“Disable adb authorization timeout” does not have node on the right side so apply offset on X will get null:

>> device.sendAai({query:"T:Disable adb authorization*&&OX:1&&OY:1"})
>> lastError()
Offset out of range

If the order of "OX" and "OY" is reversed, it will work, it applies offset on Y before X, will get proper node:

>> device.sendAai({query:"T:Disable adb authorization*&&OY:1&&OX:1"})
{count: 1, ids: ['25c8d4']}
>> device.sendAai({query:"T:Disable adb authorization*&&OY:1&&OX:1", action:"getChecked"})
{retval: false}
>> device.sendAai({query:"T:Disable adb authorization*&&OY:1&&OX:1", actions:["setChecked(true)", "getChecked"]})
{count: 2, list: [{changedCount: 1},{retval: true}]}

Put everything together, use "openAndroidSetting" to open developer options:

>> device.sendAai({actions:[
    "scrollIntoView(T:Disable adb authorization*)",
{count: 5, list: [{retval: true},{retval: true},{count: 1},{changedCount: 1},{retval: true}]}

Example 4: Change developer option "Window animation scale" to "2x", need to use "+" to T:*2x" because it is a new window, new query is required.

>> device.sendAai({actions:[
    "scrollIntoView(T:Window animation scale)",
{count: 5, list: [{retval: true},{retval: true},{retval: true},{retval: true},{retval: true}]}