Scripting

One of the biggest strengths in Total Control is the scripting capability. Total Control offers rich set of API to control one or multiple Android devices. It offers 2 sets of APIs: JavaScript and REST API. JavaScript will run the script locally, REST API offers flexibility in language and hosts. You can also use REST API to control multiple PCs running "Total Control" application.

JavaScript API

Language

Total Control provide the following framework for JavaScript (ECMAScript 5 with selected ES6 features)

  • Mozilla's Rhino 1.7.7 with Total Control 7 (or below), Rhino 1.7.12 with Total Control 8 and Rhino 1.7.14 with Total Control 9 (Update 20). See https://github.com/mozilla/rhino for more information.
  • RingoJS 2.0.

The bonus with Rhino is the ability to call Java API (Total Control 8 is using OpenJDK 15) directly if Rhino + RingoJS do not provide sufficient functionality.

Total Control offers many classes, several examples:

  • Device
  • DeviceArray
  • UiElement (Total Control 8)
  • UiElementArray (Total Control 8)
  • Notification
  • Keyboard
  • Excel

Device and DeviceArray Classes

When a device is connected (auto connect or "Connect" button is pressed), a device object from "Device" class is created, use static method "searchObject" to locate the device objects. For multiple device objects, it offers "DeviceArray" class (subclass from Array). Devices in DeviceArray objects will be perform the same task at the same time.

Device class offers close to 100 methods and properties to manipulate a device. DeviceArray class offers about 20+ commonly used methods. Please refer to {{JavaScript API documentation}} for all methods. You can extend Device and DeviceArray with ease, (See Extending Device and DeviceArray).

Use "Device.searchObject()" to locate created device objects, the device object format is "device@<10 digits>".

// Return one device object
var mySamsung = Device.searchObject('Samsung-S9');
// Return all device objects, DeviceArray
var allDevices = Device.searchObject(tcConst.DevAll);
// Return device objects belong to same group, DeviceArray
var allGroupX = Device.searchObject(tcConst.DevGroup, 'first row');
var allGroupY = Device.searchObject(tcConst.DevGroup, 'second row');
// Combine 2 groups to form a larger group, DeviceArray
var groupXY = allGroupX.concat(allGroupY);

Since DeviceArray() is a subclass of Array(), it inherits most of the methods from Array class, since all the TC specific methods are tied to DeviceArray, if you have an array, use "var ary = new DeviceArray().concat(ary)" to convert to DeviceArray.

// This will fail since there is no "click" method in Array
var device = Device.getMain();
var ary = [device];
ary.click(100,100);

// This will work
var device = Device.getMain();
var ary = new DeviceArray(device);
ary.click(100, 100);    // or ary.clickSync("OK");

Couple of examples:

// click location 100,200 on device name "Samsung-S10".
var device = Device.searchObject('Samsung-S10');
if (device) {
    device.click(100,200); 	// or device.clickSync("Start");
}
// click in the middle of the screen on all connected devices.
var devices = Device.searchObject(tcConst.DevAll);
if (devices) {
    devices.click(0.5, 0.5); 	// or device.clickSync("John");
}

Directory and Userlib.js

By default, the scripting directory is located at \Users\<user name>\Documents\Scripts directory, you can change it by clicking "Script" in Main Window, select "Script List", top line to change the directory.

Within it, you can create a file called "Userlib.js", this file will always be loaded before script execution, you can include commonly used functions, add prototypes to existing classes or bring in 3rd party software.

To debug "Userlib.js", use "Terminal", to reload "Userlib.js", click reload icon on the bottom right Terminal window.

Absolute vs Relative Coordinates

For x, y coordinates, TC offers "absolute" and "relative" coordinates (the system settings show coordinates will show both coordinates), absolute coordinates from (0, 0) to (width – 1, height – 1), relative coordinates are usually 4 decimal points from (0, 0) to (0.9999, 0.9999). The relative coordinates multiply by device width and height will get the absolute coordinates. Coordinates are not ideal, Professional supports AAI that use text in the UI elements to retrieve the coordinates in the runtime.

Extending Device and DeviceArray

The added bonus of JavaScript is the extensibility, you can extend the methods by adding prototype to the classes. Assuming you want to create a method "longPress" for both single and multiple devices, one way to write it is:

Device.prototype.longPress = function(x, y) {
    var retval = this.click(x, y, tcConst.STATE_DOWN);
    if (retval != 0) {
        return retval;
    }
    delay(500);
    return this.click(x, y, tcConst.STATE_UP);
}

DeviceArray.prototype.longPress = function(x, y) {
    for (let i = 0; i < this.length; ++i) {
        retval = this[i].longPress(x,y);
        if (retval != 0) {
            return retval;
        }
}
return 0;
}

This implementation not efficient for large number of devices in DeviceArray, the method can take up to 50 seconds if there are 100 devices in the array.

The best way is to send STATE_DOWN to all devices first, then wait till the remaining of 500 ms runs out. Fortunately, Device and DeviceArray (multiple devices) introduced "sendAll", it will execute the method specified and wait until time specified is expired. This way, the execution time is almost 500 ms. Since "sendAll" is available in Device and DeviceArray, the code to implement Device and DeviceArray is exactly the same.

Device.prototype.longPress = function(x, y) {
var retval = this.sendAll(Device.prototype.click, 
     [x, y, tcConst.STATE_DOWN], 500);
    if (retval != 0) {
        return retval;
    }
    return this.sendAll(Device.prototype.click, [x, y, tcConst.STATE_UP]);
}

DeviceArray.prototype.longPress = Device.prototype.longPress; 
 

sendAll only applies to methods that returns 0 on success.

Scripting Tools

There are many tools available in Total Control, click "Script" will open a new window:

Terminal: Open Rhino + RingoJS command prompt, you can use it for testing or development purpose. Click button on the bottom right to reload the interpreter and Userlib.js. Can use load("filename.js") to run a script.

Script List ⇒ Path: Script default path, click icon to change the path to other directory.

Script List ⇒ JS source files: Use to quickly execute a JavaScript file, it provide a simple editor for quick change or click arrow key to execute the script.

Script List ⇒ Record Script: Record the actions on the devices into an Excel file, Excel file can also be used to generate JS script or JSON file (maybe useful for REST API). Users with no experience in JavaScript can use this tool to generate simple script.

Script List ⇒ Image Helper. Generate BMP file from main device screen content, the image is needed for seekImage(), it extends BMP file to provide additional information such as app name, activity, width and height information. seekImage() will utilize these information without providing lots of parameters.

Script List ⇒ Color Helper. Load the screen content from the main device (like image helper), a magnified color chooser to pick RGB values of the colors and generate seekColor() with complex parameters. Can support single and multiple colors.

Script List ⇒ UI Explorer. Open UI Explorer window, click capture to capture the existing main phone window and allow users to experience query language to select UI elements. A Helper window will provide helper description for each keys in query language.

Execute (will be renamed to Task). Create a task to run a script on various number of conditions such as date & time, number of iterations, regular intervals or the devices. The output and the results of the task execution will be saved for review. Task can be also be created or changed via JS API. Runner execution will be shown as a task here.

Inspect: Inspect the various internal variables related to scripts and engines.