r2-studio / robotmon-scripts

Run Javascript on Android. Screenshot, Touch, ...
Apache License 2.0
78 stars 66 forks source link

Robotmon JavaScript APIs

Only support ES5

Contents

JavaScript Events

Add the following <script> in the <head> section of index.html

start() and stop() should defined in index.js

<script>
  function onEvent(eventType) {
    if (eventType === 'OnPlayClick') {
      JavaScriptInterface.runScript(`start();`);
    } else if (eventType === 'OnPauseClick') {
      JavaScriptInterface.runScript('stop();');
    }
  }

  function onLog(message) {
    console.log(message);
  }
</script>
event name
OnMenuClick
OnPlayClick
OnPauseClick
OnLogClick
OnSettingClick
OnCloseClick

JavaScript Interface

runScript(script)
runScriptCallback(script, callback)
clickIconButton()

Click the app icon button on floating widget.

clickPlayButton()

Click the play button on floating widget.

clickPauseButton()

Click the pause button on floating widget.

clickLogButton()

Click the log button on floating widget.

clickSettingButton()

Click the setting button on floating widget.

clickCloseButton()

Click the close button on floating widget.

setXY(x, y)

Set the position of the floating widget.

getX()

Returns Integer - The x position of the floating widget.

getY()

Returns Integer - The y position of the floating widget.

showMenu()

Show the menu on floating widget.

hideMenu()

Hide the menu on floating widget.

showPlayButton()

Show the play button on floating widget.

showPauseButton()

Show the pause button on floating widget.

JavaScript Raw APIs

getScreenSize()

Returns Object - {width: Integer, height: Integer}

var sizeObj = getScreenSize();
console.log(sizeObj.width, sizeObj.height);
// 1080 1920

getScreenshot()

Returns Integer - The image pointer

var img = getScreenshot();
console.log(img);
// 122344533 <- image pointer
releaseImage(img); // Don't forgot release a pointer

getScreenshotModify(cropX, cropY, cropWidth, cropHeight, resizeWidth, resizeHeight, qualitys)

Get screenshot, crop and resize. For speeding up screenshot.

Returns Integer - The image pointer

var image = getScreenshotModify(200, 200, 100, 100, 50, 50, 80);
console.log(image); // image width = 50, height = 50 
// 12333122
releaseImage(image);

execute(command)

Call exec command in android system. Its permission is same as adb shell

Returns String - The result of the execution

var result = execute("ls -al /sdcard");
console.log(result);
// drwxr-xr-x   2 root  root    64B 12 14 23:44 Robotmon

tap(x, y, during)

Simulate a tap event after during milliseconds have passed.

tap(200, 200, 10);
// Will inject a tap down and a tap up event after 10ms to system

tapDown(x, y, during)

tapDown(200, 200, 40);
// Will inject a tapDown event after 10ms to system

tapUp(x, y, during)

tapUp(200, 200, 40);
// Will inject a tapUo event after 10ms to system

moveTo(x, y, during)

moveTo should be between tapDown and tapUp

tapDown(500, 300, 40);
moveTo(500, 600, 40);
tapUp(500, 600, 40);
// Will inject a swipe down event

swipe(x1, y1, x2, y2, during)

Simulate a swipe event, using tapDown, moveTo and tapUp event. This function may not work in some game, you should implement yourself.

swipe(500, 300, 40); // same as above example
// Will inject a swipe down event

keycode(label, during)

Send a key code event to system Like adb shell input keyevent command Android Keycode List

keycode('HOME', 40); // same as keycode('KEYCODE_HOME', 40);
// Will send a HOME event to system

typing(words, during)

Only allow English words

typing('Hello!', 100);
// Will type 'H' 'e' 'l' 'l' 'o' '!' 6 words

OpenCV

clone(sourceImg)

Duplicate an image to another.

Returns Integer - The image pointer

var oriImage = getScreenshot();
for (var i = 0; i < 10; i++) {
  var cloneImage = clone(oriImage);
  // modify clone Image here
  smooth(cloneImage, 1, 5); // blur
  release(cloneImage);
}
release(oriImage);

smooth(sourceImg, smoothType, size)

Same as OpenCV smooth() function.

smoothType description
0 CV_BLUR_NO_SCALE
1 CV_BLUR
2 CV_GAUSSIAN
3 CV_MEDIAN
4 CV_BILATERAL
var img = getScreenshot();
smooth(img, 2, 5); // Gaussian blur
saveImage(img, getStoragePath + '/smooth.png');
releaseImage(img);

convertColor(sourceImg, code)

Same as OpenCV cvtColor(). Not support different channels. If you want to convert to gray, please use bgrToGray. Note that getScreenshot and getScreenshotModify is BGR order;

code description
40 CV_BGR2HSV
52 CV_BGR2HLS

See more: OpenCV Types

var img = getScreenshot();
// Convert BGR to HSV color
convertColor(img, 40);
releaseImage(img);

bgrToGray(sourceImg)

Convert form bgr (3 channels) to gray (1 channel).

Returns Integer - The gray image pointer

var img = getScreenshot();
var gray = bgrToGray(img); // gray image
releaseImage(img);
releaseImage(gray);

absDiff(sourceImg, targetImg)

Same as OpenCV adbdiff().

Returns Integer - The image pointer of the difference

var img1 = getScreenshot();
sleep(100);
var img2 = getScreenshot();
var diff = absDiff(img1, img2); // in gray order
releaseImage(img1);
releaseImage(img2);
releaseImage(diff);

threshold(sourceImg, thr, maxThr, code)

Same as OpenCV threshold().

code description
0 CV_THRES_BINARY

See more: OpenCV Types

keycode('MENU');
sleep(1000);
var img1 = getScreenshot();
keycode('HOME');
sleep(1000);
var img2 = getScreenshot();
var diff = absDiff(img1, img2); // in gray order
threshold(diff, 100, 255); // set to 0 if <= 100, set to 255 if > 100
var value = getImageColor(diff, 500, 200); // value => {r":255,"g":0,"b":0","a":0}
console.log(value['r']); // current diff value is show on 'r'
// 255
releaseImage(img1);
releaseImage(img2);
releaseImage(diff);

eroid(sourceImg, width, height, x, y)

Same as OpenCV eroid.

width, height, x, y is getStructuringElement() parameters.

var img = getScreenshot();
threshold(img, 100, 255);
eroid(img, 3, 3, 1, 1);
saveImage(img, getStoragePath() + '/test_eroid.png');
releaseImage(img);

dilate(sourceImg, width, height, x, y)

Same as OpenCV dilate.

width, height, x, y is getStructuringElement() parameters.

var img = getScreenshot();
threshold(img, 100, 255);
dilate(img, 3, 3, 1, 1);
saveImage(img, getStoragePath() + '/test_dilate.png');
releaseImage(img);

inRange(sourceImg, minB, minG, minR, minA, maxB, maxG, maxR, maxA)

Same as OpenCV inRange + clone + mask. Filter with range color and clone to new image.

Returns Integer - The filtered image pointer

var img = getScreenshot();
var filteredImg = inRange(img, 0, 255, 255, 255, 255, 255, 255, 255); // only keep blue color pixel
saveImage(filteredImg, getStoragePath() + '/test_filterd.png');
releaseImage(img);
releaseImage(filteredImg);

outRange(sourceImg, minB, minG, minR, minA, maxB, maxG, maxR, maxA)

Same as OpenCV inRange + clone + not + mask. Filter without range color and clone to new image.

Returns Integer - The filtered image pointer

var img = getScreenshot();
var filteredImg = outRange(img, 0, 255, 255, 255, 255, 255, 255, 255); // keep all but blue color
saveImage(filteredImg, getStoragePath() + '/test_filterd.png');
releaseImage(img);
releaseImage(filteredImg);

cloneWithMask(sourceImg, mask)

Same as OpenCV copyTo. Clone image with mask (only support 1 channel)

Returns Integer - new image pointer with mask

var img1 = getScreenshot();
sleep(100);
var img2 = getScreenshot();
var diff = absDiff(img1, img2);
sleep(100);
var img3 = cloneWithMask(img1, diff);
releaseImage(img1);
releaseImage(img2);
releaseImage(img3);
releaseImage(diff);

houghCircles(sourceImg, method, dp, minDist, p1, p2, minR, maxR)

Same as OpenCV houghCircles. For finding circles.

Returns Object - Array of circles

var img = getScreenshot();
var points = houghCircles(img, 3, 1, 8, 4, 8, 6, 14);
console.log(points); // {"0": {"x": 102, "y": "233", "r": 9}}
releaseImage(img);

canny(sourceImg, t1, t2, apertureSize)

Same as OpenCV canny

Returns Integer - The canny image pointer

var img = getScreenshot();
threshold(img, 30, 255);
eroid(img, 5, 5, 1, 1);
var cannyImg = canny(img, 50, 150, 3);
saveImage(cannyImg, getStoragePath() + '/test_canny.png');
releaseImage(img);
releaseImage(cannyImg);

findContours(cannyImgPtr, minArea, maxArea)

Same as OpenCV findContours.

Returns Object - {"0": {x: Integer, y: Integer}

var img = getScreenshot();
threshold(img, 30, 255);
eroid(img, 5, 5, 1, 1);
var cannyImg = canny(img, 50, 150, 3);
var results = findContours(cannyImg, 1000, 10000); // area > 100
console.log(JSON.stringify(results));
// {"0":{"x":537,"y":1850},"1":{"x":133,"y":601}}
releaseImage(img);
releaseImage(cannyImg);

drawCircle(sourceImg, x, y, radius, r, g, b, a)

Draw circle in an image.

var img = getScreenshot();
drawCircle(img, 100, 100, 10, 0, 0, 255, 0); // draw a blue circle
saveImage(img, getStoragePath() + '/test_drawCircle.png');
releaseImage(img);

getIdentityScore(sourceImg, targetImg)

Returns Float - The identity score

keycode('MENU');
sleep(1000);
var img1 = getScreenshot();
keycode('HOME');
sleep(1000);
var img2 = getScreenshot();
var score = getIdentityScore(img1, img2);
console.log(score); // 0.6004924774169922
releaseImage(img1);
releaseImage(img2);

cropImage(sourceImg, x, y, width, height)

Crop image.

Returns Integer - The image pointer

var img = getScreenshot();
var cropImg = cropImage(img, 350, 550, 150, 150);
saveImage(cropImg, getStoragePath() + '/test_crop.png');
releaseImage(img);
releaseImage(cropImg);

findImage(sourceImg, targetImg)

Using OpenCV Template Match to find image.

Returns Object - {x: Integer, y: Integer, score: Float}

var img = getScreenshot();
var cropImg = cropImage(img, 350, 550, 150, 150);
var result = findImage(img, cropImg);
console.log(JSON.stringify(result)); // {"score":0.9999997615814209,"x":350,"y":550}
releaseImage(img);
releaseImage(cropImg);

findImages(sourceImg, targetImg, scoreLimit, resultCountLimit, withoutOverlap)

Same as findImage(), but find multiple times.

Returns String - {"0": {"x": Integer, "y": Integer, "score": Float}, "1": {"x": Integer, "y": Integer, "score": Float}}, Key is String!

var img = getScreenshot();
var cropImg = cropImage(img, 350, 550, 150, 150);
var result = findImages(img, cropImg, 0.95, 3, true);
console.log(JSON.stringify(result)); // {"0":{"score":0.9999997615814209,"x":350,"y":550}}
releaseImage(img);
releaseImage(cropImg);

resizeImage(sourceImg, width, height)

Resize image.

Returns Integer - The image pointer

var img = getScreenshot();
var resizeImg = resizeImage(img, 108, 192);
saveImage(resizeImg, getStoragePath() + '/test_resize.png');
releaseImage(img);
releaseImage(resizeImg);

releaseImage(imagePointer)

Very Important! You should call this function with all image pointers.

var img = getScreenshot(); // keep in memory
releaseImage(img); // release from memory

getImageColor(sourceImg, x, y)

Get color of point from an image.

Returns Object - {r: Integer, g: Integer, b: Integer, a: Integer}

var img = getScreenshot();
var color = getImageColor(img, 100, 100);
console.log(JSON.stringify(color)); // {"a":0,"b":21,"g":36,"r":198}
releaseImage(img);

getImageSize(imgPtr)

Returns Object - {width: Integer, height: Integer}

var img = getScreenshot();
var size = getImageSize(img);
console.log(JSON.stringify(size)); // {"height":1920,"width":1080}
releaseImage(img);

saveImage(imgPtr, path)

Save image to disk.

var img = getScreenshot();
saveImage(img, getStoragePath + '/test_save.png');
releaseImage(img);

openImage(path)

Open image from disk.

Returns Integer - The image pointer

var img = openImage(getStoragePath + '/test_save.png');
releaseImage(img);

sleep(milliseconds)

Like sleep function in C language, pause current process.

console.log('Hello');
sleep(1000);
console.log('Andy');

getStoragePath()

Get Robotmon folder. Like /sdcard/Robotmon.

Returns String - The storage path

console.log(getStoragePath());

getImageFromURL(url)

Get image from an url.

Returns Integer - The image pointer

getImageFromBase64(base64)

Get image from a base64 string.

Returns Integer - The image pointer

getBase64FromImage(imgPtr)

Get base64 string from an image.

Returns String - base64

readFile(path)

Read a file as string.

Returns String - The text of the file

writeFile(path, text)

Write a string to a file.

encrypt(script)

Encrypted a string

Returns String - The encrypted script

runEncryptedScript(script)

Run an encrypted javascript string.

runScript(script)

Run a javascript string.

httpClient(method, url, body, headers)

Do a http request.

Returns String - The result

httpClient('GET', 'http://httpbin.org/get', '', {});
httpClient('POST', 'http://httpbin.org/post', 'body data', {});
httpClient('POST', 'http://httpbin.org/post', 'foo=bar&bar=foo', {'Content-Type': 'application/x-www-form-urlencoded'});

importJS(library)

Import an JS library.

importJS('RBM-0.0.2') // import shared library in libs
importJS('js/customerJS') // import local library

getVirtualButtonHeight()

Returns Integer - The height of the virtual button

RBM library APIs

The RBM library is an API wrapper of the Robotmon JavaScript APIs.

RBM Config

property description
appName The name of the script.
oriScreenWidth The width of developer's phone.
oriScreenHeight The height of developer's phone.
oriVirtualButtonHeight The virtual button height of developer's phone(getVirtualButtonHeight()). If no virtual button in app, just set to 0.
oriResizeFactor The resize ratio of the screenshot in developer's environment. For screencrop(). Range from 0 to 1.
eventDelay The delay milliseconds of the event.
imageThreshold The threshold of image recognition. Range from 0 to 1.
imageQuality The compression level of the image. Range from 0 to 100.
resizeFactor The resize ratio of the screenshot in user's environment. Same as oriResizeFactor is better. Range from 0 to 1.

Using

// Import RBM library
importJS('RBM-0.0.2');

// Initial RBM config
var config = {
  appName: 'com.your.script',
  oriScreenWidth: 1080,
  oriScreenHeight: 1920,
  oriVirtualButtonHeight: 0,
  oriResizeFactor: 0.6,
  eventDelay: 200,
  imageThreshold: 0.85,
  imageQuality: 80,
  resizeFactor: 0.6,
};

// Create RBM instance
var rbm = new RBM(config);

// Important! Calculate the screen size, call it after start pressed!
rbm.init();

// Then using the following APIs of the RBM library

RBM library

rbm.log(args)

For general output of logging information.

rbm.currentApp()

Returns Object - The current app in foreground. {packageName: String, activityName: String}

rbm.startApp(packageName, activityName)

Launch an app by packageName and activityName.

rbm.stopApp(packageName)

Close an app by packageName.

rbm.click(position)
rbm.tapDown(position)
rbm.tapUp(position)
rbm.moveTo(position)
rbm.swipe(from, to, steps)
rbm.keycode(label)
rbm.typing(words)
rbm.sleep()

Sleep with eventDelay.

rbm.getImagePath()
// /sdcard/Robotmon/scripts/com.your.app/images

Returns String - The path of the image folder. All about images used in this library will load and save within this folder.

rbm.screenshot(filename)

Save the screenshot in rbm.getImagePath().

rbm.oriScreencrop(filename, fromX, fromY, toX, toY)

// Examples:
rbm.oriScreencrop('startButton.png', 100, 200, 200, 300)

Crop the original screenshot and save it with filename. This function will resize the image with oriResizeFactor and compress with imageQuality.

rbm.screencrop(filename, fromX, fromY, toX, toY)

// Examples:
rbm.screencrop('startButton.png', 100, 200, 200, 300)

Crop the screenshot and save it with filename. This function will resize the image with resizeFactor and compress with imageQuality.

rbm.findImage(filename, threshold)

// Examples:
rbm.findImage('startButton.png', 0.9)

Returns Object - Find the image with filename in screen. {x: Integer, y: Integer, score: Float}

rbm.findImages(filename, threshold, countLimit, allowOverlap, deep)

// Examples:
rbm.findImages('startButton.png', 0.9, 3, false, false)

Returns Object - Find the image with filename in screen. {x: Integer, y: Integer, score: Float}

rbm.imageExists(filename, threshold)

Returns Boolean - Whether the image exists in screen.

rbm.imageClick(filename, threshold)

Click the image if the image exists in screen.

rbm.imageWaitClick(filename, timeout, threshold)

Click the image if the image exists in screen until timeout (milliseconds).

rbm.imageWaitShow(filename, timeout, threshold)

Block until the image is found or timeout

rbm.imageWaitGone(filename, timeout, threshold)

Block until the image is gone or timeout

rbm.keepScreenshot()

Keep the screenshot in memory. To avoid too many times screencap.

rbm.screencrop(fromX, fromY, toX, toY)

Keep the partial screenshot in memory. To avoid too many times screencap.

rbm.releaseScreenshot()

Release the screenshot in memory.

Using keepScreenshot

// Screencap three times
rbm.imageClick('apple.png', 0.9); // screencap, and release
rbm.imageClick('banana.png', 0.9); // screencap, and release
rbm.imageClick('cat.png', 0.9); // screencap, and release

// Screencap only one time (used when the screen has not changed)
rbm.keepScreenshot(); // screencap
rbm.imageClick('apple.png', 0.9); // no screencap, no release
rbm.imageClick('banana.png', 0.9); // no screencap, no release
rbm.imageClick('cat.png', 0.9); // no screencap, no release
rbm.releaseScreenshot(); // release

gRPC APIs

Message

message Empty {}

message Response {
  string message = 1;
}

message RequestRunScript {
  string script = 1;
}

message RequestScreenshot {
  int32 cropX = 1;
  int32 cropY = 2;
  int32 cropWidth = 3;
  int32 cropHeight = 4;
  int32 resizeWidth = 5;
  int32 resizeHeight = 6;
  int32 quality = 7;
}

message RequestTap {
  int32 x = 1;
  int32 y = 2;
  int32 during = 3;
}

message ResponseScreenshot {
  bytes image = 1;
}

message ResponseScreenSize {
  int32 width = 1;
  int32 height = 2;
}

Service

service GrpcService {
  rpc RunScript(RequestRunScript) returns (Response) {}
  rpc Logs(Empty) returns (stream Response) {}
  rpc GetScreenshot(RequestScreenshot) returns (ResponseScreenshot) {}
  rpc GetScreenSize(Empty) returns (ResponseScreenSize) {}
  rpc Tap(RequestTap) returns (Response) {}
  rpc TapDown(RequestTap) returns (Response) {}
  rpc TapUp(RequestTap) returns (Response) {}
  rpc MoveTo(RequestTap) returns (Response) {}
}

Debug