Refactor: split into modules autojs, common, app and automator
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
package com.example.autojs;
|
||||
package com.stardust.autojs;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
@@ -21,6 +21,6 @@ public class ExampleInstrumentedTest {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getTargetContext();
|
||||
|
||||
assertEquals("com.example.autojs.test", appContext.getPackageName());
|
||||
assertEquals("com.stardust.autojs.test", appContext.getPackageName());
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,12 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
|
||||
package="com.example.autojs"
|
||||
>
|
||||
|
||||
<application android:allowBackup="true"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
package="com.stardust.autojs"
|
||||
>
|
||||
|
||||
<application
|
||||
android:label="@string/app_name"
|
||||
>
|
||||
<activity android:name=".engine.ScriptExecuteActivity"/>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
||||
294
autojs/src/main/assets/javascript_engine_init.js
Normal file
294
autojs/src/main/assets/javascript_engine_init.js
Normal file
@@ -0,0 +1,294 @@
|
||||
|
||||
if(__engine__ == "rhino"){
|
||||
__importClassOld__ = importClass;
|
||||
var importClass = function(pack){
|
||||
if(typeof(pack) == "string"){
|
||||
__importClassOld__(Packages[pack]);
|
||||
}else{
|
||||
__importClassOld__(pack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var toast = function(text){
|
||||
__runtime__.toast(text);
|
||||
}
|
||||
|
||||
var launchPackage = function(package){
|
||||
__runtime__.app.launchPackage(package);
|
||||
}
|
||||
|
||||
var launch = function(a, b){
|
||||
if(arguments.length == 2){
|
||||
__runtime__.app.launch(a, b);
|
||||
}else{
|
||||
__runtime__.app.launchPackage(a);
|
||||
}
|
||||
}
|
||||
|
||||
var launchApp = function(appName){
|
||||
__runtime__.app.launchApp(appName);
|
||||
}
|
||||
|
||||
var getPackageName = function(appName){
|
||||
return __runtime__.app.getPackageName(appName);
|
||||
}
|
||||
|
||||
var openAppSetting = function(packageName){
|
||||
return __runtime__.app.openAppSetting(packageName);
|
||||
}
|
||||
|
||||
|
||||
var sleep = function(millis){
|
||||
__runtime__.sleep(millis);
|
||||
}
|
||||
|
||||
var isStopped = function(){
|
||||
return __runtime__.isStopped();
|
||||
}
|
||||
|
||||
var notStopped = function(){
|
||||
return !isStopped();
|
||||
}
|
||||
|
||||
var stop = function(){
|
||||
__runtime__.stop();
|
||||
}
|
||||
|
||||
var console = __runtime__.console;
|
||||
|
||||
var log = function(str){
|
||||
console.log(str);
|
||||
}
|
||||
|
||||
var print = log;
|
||||
|
||||
var err = function(e){
|
||||
console.e(e);
|
||||
}
|
||||
|
||||
var openConsole = function(){
|
||||
console.show();
|
||||
}
|
||||
|
||||
var clearConsole = function(){
|
||||
console.clear();
|
||||
}
|
||||
|
||||
var shell = function(cmd, root){
|
||||
root = root ? 1 : 0;
|
||||
return __runtime__.shell(cmd, root);
|
||||
}
|
||||
|
||||
var currentPackage = function(){
|
||||
return __runtime__.automator.currentPackage();
|
||||
}
|
||||
|
||||
var currentActivity = function(){
|
||||
return __runtime__.automator.currentActivity();
|
||||
}
|
||||
|
||||
var __this__ = this;
|
||||
|
||||
var back = function(){
|
||||
return __runtime__.automator.back();
|
||||
}
|
||||
|
||||
var home = function(){
|
||||
return __runtime__.automator.home();
|
||||
}
|
||||
|
||||
var powerDialog = function(){
|
||||
return __runtime__.automator.powerDialog();
|
||||
}
|
||||
|
||||
var notifications = function(){
|
||||
return __runtime__.automator.notifications();
|
||||
}
|
||||
|
||||
var quickSettings = function(){
|
||||
return __runtime__.automator.quickSettings();
|
||||
}
|
||||
|
||||
var recents = function(){
|
||||
return __runtime__.automator.recents();
|
||||
}
|
||||
|
||||
var splitScreen = function(){
|
||||
return __runtime__.automator.splitScreen();
|
||||
}
|
||||
|
||||
|
||||
function performAction(action, args){
|
||||
if(args.length == 4){
|
||||
return action(__runtime__.automator.bounds(args[0], args[1], args[2], args[3]));
|
||||
}else if(args.length == 2){
|
||||
return action(__runtime__.automator.text(args[0], args[1]));
|
||||
}else {
|
||||
return action(__runtime__.automator.text(args[0], -1));
|
||||
}
|
||||
}
|
||||
|
||||
var click = function(){
|
||||
return performAction(function(target){
|
||||
return __runtime__.automator.click(target);
|
||||
}, arguments);
|
||||
}
|
||||
|
||||
var longClick = function(a, b, c, d){
|
||||
return performAction(function(target){
|
||||
return __runtime__.automator.longClick(target);
|
||||
}, arguments);
|
||||
}
|
||||
|
||||
|
||||
var scrollUp = function(a, b, c, d){
|
||||
if(arguments.length == 0)
|
||||
return __runtime__.automator.scrollAllUp();
|
||||
if(arguments.length == 1 && typeof a === 'number')
|
||||
return __runtime__.automator.scrollUp(a);
|
||||
return performAction(function(target){
|
||||
return __runtime__.automator.scrollUp(target);
|
||||
}, arguments);
|
||||
}
|
||||
|
||||
var scrollDown = function(a, b, c, d){
|
||||
if(arguments.length == 0)
|
||||
return __runtime__.automator.scrollAllDown();
|
||||
if(arguments.length == 1 && typeof a === 'number')
|
||||
return __runtime__.automator.scrollDown(a);
|
||||
return performAction(function(target){
|
||||
return __runtime__.automator.scrollDown(target);
|
||||
}, arguments);
|
||||
}
|
||||
|
||||
var input = function(a, b){
|
||||
if(arguments.length == 1){
|
||||
return __runtime__.automator.setText(__runtime__.editable(-1), a);
|
||||
}else{
|
||||
return __runtime__.automator.setText(__runtime__.editable(a), b);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var setClip = function(text){
|
||||
__runtime__.setClip(text);
|
||||
}
|
||||
|
||||
|
||||
var Tap = function(x, y){
|
||||
return shell("input tap " + x + " " + y, true).code == 1;
|
||||
}
|
||||
|
||||
var Swipe = function(x1, y1, x2, y2, duration){
|
||||
if(arguments.length == 5){
|
||||
return shell("input swipe " + x1 + " " + y1 + " " + x2 + " " + y2 + " " + duration, true).code == 1;
|
||||
}
|
||||
return shell("input swipe " + x1 + " " + y1 + " " + x2 + " " + y2, true).code == 1;
|
||||
}
|
||||
|
||||
var KeyCode = function(keyCode){
|
||||
return shell("input keyevent " + keyCode, true).code == 1;
|
||||
}
|
||||
|
||||
var Home = function(){
|
||||
return KeyCode(3);
|
||||
}
|
||||
|
||||
var Back = function(){
|
||||
return KeyCode(4);
|
||||
}
|
||||
|
||||
var Power = function(){
|
||||
return KeyCode(26);
|
||||
}
|
||||
|
||||
var Up = function(){
|
||||
return KeyCode(19);
|
||||
}
|
||||
|
||||
var Down = function(){
|
||||
return KeyCode(20);
|
||||
}
|
||||
|
||||
var Left = function(){
|
||||
return KeyCode(21);
|
||||
}
|
||||
|
||||
var Right = function(){
|
||||
return KeyCode(22);
|
||||
}
|
||||
|
||||
var OK = function(){
|
||||
return KeyCode(23);
|
||||
}
|
||||
|
||||
var VolumeUp = function(){
|
||||
return KeyCode(24);
|
||||
}
|
||||
|
||||
var VolumeDown = function(){
|
||||
return KeyCode(25);
|
||||
}
|
||||
|
||||
var Menu = function(){
|
||||
return KeyCode(1);
|
||||
}
|
||||
|
||||
var Camera = function(){
|
||||
return KeyCode(27);
|
||||
}
|
||||
|
||||
var Text = function(text){
|
||||
return shell("input text " + text, true).code == 1;
|
||||
}
|
||||
|
||||
var __selector__ = __runtime__.selector();
|
||||
var __obj__ = new java.lang.Object();
|
||||
|
||||
for(var x in __selector__){
|
||||
if(!__obj__[x] && !this[x]){
|
||||
this[x] = (function(method) {
|
||||
return function(){
|
||||
var s = __runtime__.selector();
|
||||
//这里不知道怎么写。尴尬。只能写成这样。
|
||||
if(arguments.length == 0){
|
||||
return s[method]();
|
||||
}else if(arguments.length == 1){
|
||||
return s[method](arguments[0]);
|
||||
}else if(arguments.length == 2){
|
||||
return s[method](arguments[0], arguments[1]);
|
||||
}else if(arguments.length == 3){
|
||||
return s[method](arguments[0], arguments[1], arguments[2]);
|
||||
}else if(arguments.length == 4){
|
||||
return s[method](arguments[0], arguments[1], arguments[2], arguments[3]);
|
||||
}else{
|
||||
return s[method].call(s, Array.prototype.slice.call(arguments));
|
||||
}
|
||||
};
|
||||
})(x);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var open = function(path, mode){
|
||||
return com.stardust.pio.PFile.open(path, mode);
|
||||
}
|
||||
|
||||
__importClassOld__(com.stardust.autojs.runtime.api.Shell);
|
||||
|
||||
var newInjectableWebClient = function(){
|
||||
return new com.stardust.autojs.runtime.api.InjectableWebClient(org.mozilla.javascript.Context.getCurrentContext(), __this__);
|
||||
}
|
||||
|
||||
var newInjectableWebView = function(activity){
|
||||
return new com.stardust.autojs.runtime.api.InjectableWebView(activity, org.mozilla.javascript.Context.getCurrentContext(), __this__);
|
||||
}
|
||||
|
||||
/*
|
||||
importClass("com.stardust.script__runtime__.service.AccessibilityDelegate");
|
||||
|
||||
var addAccessibilityDelegate = function(delegate){
|
||||
__runtime__.addAccessibilityDelegate(delegate);
|
||||
}
|
||||
*/
|
||||
46
autojs/src/main/assets/nodejs_engine_init.js
Normal file
46
autojs/src/main/assets/nodejs_engine_init.js
Normal file
@@ -0,0 +1,46 @@
|
||||
var __requireOld__ = require;
|
||||
var __nodejs_modules__ = {
|
||||
'websocket' : com.iwebpp.wspp.WebSocket,
|
||||
'websocketserver': com.iwebpp.wspp.WebSocketServer,
|
||||
'net': com.iwebpp.node.net.TCP,
|
||||
'tcp': com.iwebpp.node.net.TCP,
|
||||
'udt': com.iwebpp.node.net.UDT,
|
||||
'readable': com.iwebpp.node.stream.Readable2,
|
||||
'writable': com.iwebpp.node.stream.Writable2,
|
||||
'duplex': com.iwebpp.node.stream.Duplex,
|
||||
'transform': com.iwebpp.node.stream.Transform,
|
||||
'passthrough': com.iwebpp.node.stream.PassThrough,
|
||||
'dns': com.iwebpp.node.Dns,
|
||||
'url': com.iwebpp.node.Url,
|
||||
}
|
||||
|
||||
var require = function(module){
|
||||
if (module === 'http'){
|
||||
return {
|
||||
get: function(url, listener){
|
||||
return com.iwebpp.node.http.http.get(NodeCurrentContext, url, listener);
|
||||
},
|
||||
request: function(url, listener) {
|
||||
return com.iwebpp.node.http.http.request(NodeCurrentContext, url, listener);
|
||||
},
|
||||
createServer: function(listener) {
|
||||
return com.iwebpp.node.http.http.createServer(NodeCurrentContext, listener);
|
||||
},
|
||||
};
|
||||
}
|
||||
if (module === 'httpp'){
|
||||
return {
|
||||
get: function(url, listener){
|
||||
return com.iwebpp.node.http.httpp.get(NodeCurrentContext, url, listener);
|
||||
},
|
||||
request: function(url, listener) {
|
||||
return com.iwebpp.node.http.httpp.request(NodeCurrentContext, url, listener);
|
||||
},
|
||||
createServer: function(listener) {
|
||||
return com.iwebpp.node.http.httpp.createServer(NodeCurrentContext, listener);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return __requireOld__(module);
|
||||
};
|
||||
@@ -1,172 +0,0 @@
|
||||
package autojs;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.Pref;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.droid.runtime.DroidRuntime;
|
||||
import com.stardust.scriptdroid.droid.script.JavaScriptEngine;
|
||||
import com.stardust.scriptdroid.droid.script.ScriptExecuteActivity;
|
||||
import com.stardust.scriptdroid.service.VolumeChangeObverseService;
|
||||
import com.stardust.scriptdroid.tool.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/23.
|
||||
*/
|
||||
|
||||
public class Droid {
|
||||
|
||||
public static final String STAY = "\"stay\";";
|
||||
|
||||
public static final String UI = "\"ui\";";
|
||||
|
||||
public static final String AUTO = "\"auto\";";
|
||||
|
||||
public interface OnRunFinishedListener extends Serializable {
|
||||
void onRunFinished(Object result);
|
||||
|
||||
void onException(@NonNull Exception e);
|
||||
}
|
||||
|
||||
public static class SimpleOnRunFinishedListener implements OnRunFinishedListener {
|
||||
|
||||
@Override
|
||||
public void onRunFinished(Object result) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onException(@NonNull Exception e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static final DroidRuntime RUNTIME = DroidRuntime.getRuntime();
|
||||
public static final JavaScriptEngine JAVA_SCRIPT_ENGINE = JavaScriptEngine.getDefault();
|
||||
private static final OnRunFinishedListener DEFAULT_LISTENER = new SimpleOnRunFinishedListener() {
|
||||
@Override
|
||||
public void onException(@NonNull Exception e) {
|
||||
if (!causedByInterruptedException(e)) {
|
||||
RUNTIME.toast(App.getApp().getString(R.string.text_error) + ": " + e.getMessage());
|
||||
Timber.e(e.getMessage());
|
||||
}
|
||||
}
|
||||
};
|
||||
private static Droid instance = new Droid();
|
||||
private VolumeChangeObverseService.OnVolumeChangeListener mOnVolumeChangeListener = new VolumeChangeObverseService.OnVolumeChangeListener() {
|
||||
@Override
|
||||
public void onVolumeChange() {
|
||||
if (Pref.isRunningVolumeControlEnabled()) {
|
||||
stopAllAndToast();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
private Droid() {
|
||||
VolumeChangeObverseService.addOnVolumeChangeListener(mOnVolumeChangeListener);
|
||||
}
|
||||
|
||||
public static Droid getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static boolean causedByInterruptedException(Throwable e) {
|
||||
while (e != null) {
|
||||
if (e instanceof InterruptedException) {
|
||||
return true;
|
||||
}
|
||||
e = e.getCause();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void runScriptFile(File file) {
|
||||
runScriptFile(file, null, new RunningConfig());
|
||||
}
|
||||
|
||||
public void runScriptFile(File file, OnRunFinishedListener listener, RunningConfig config) {
|
||||
Timber.v(DateFormat.getTimeInstance().format(new Date()) + " " + App.getResString(R.string.text_start_running) + " " + file);
|
||||
listener = listener == null ? DEFAULT_LISTENER : listener;
|
||||
int errorMsgId = PathChecker.check(file.getPath());
|
||||
if(errorMsgId != PathChecker.CHECK_RESULT_OK){
|
||||
listener.onException(new IOException(App.getResString(errorMsgId)));
|
||||
}
|
||||
ScriptEngine
|
||||
runScript(FileUtils.readString(file), listener, config.path(file.getPath()));
|
||||
}
|
||||
|
||||
|
||||
public void runScriptFile(String path) {
|
||||
runScriptFile(new File(path));
|
||||
}
|
||||
|
||||
public void runScript(String script) {
|
||||
runScript(script, null, RunningConfig.getDefault());
|
||||
}
|
||||
|
||||
public void runScript(String script, OnRunFinishedListener listener, RunningConfig config) {
|
||||
App.getApp().startService(new Intent(App.getApp(), VolumeChangeObverseService.class));
|
||||
listener = listener == null ? DEFAULT_LISTENER : listener;
|
||||
if (!TextUtils.isEmpty(config.prepareScript))
|
||||
script = config.prepareScript + "\n" + script;
|
||||
if (config.runInNewThread) {
|
||||
if (script.startsWith(UI)) {
|
||||
ScriptExecuteActivity.runScript(script, listener, config);
|
||||
} else {
|
||||
new Thread(new RunScriptRunnable(script, listener, config)).start();
|
||||
}
|
||||
} else {
|
||||
new RunScriptRunnable(script, listener, config).run();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public int stopAll() {
|
||||
return JAVA_SCRIPT_ENGINE.stopAll();
|
||||
}
|
||||
|
||||
|
||||
public void stopAllAndToast() {
|
||||
int n = stopAll();
|
||||
if (n > 0)
|
||||
RUNTIME.toast(String.format(App.getResString(R.string.text_already_stop_n_scripts), n));
|
||||
else
|
||||
RUNTIME.toast(App.getResString(R.string.text_no_running_script));
|
||||
}
|
||||
|
||||
private static class RunScriptRunnable implements Runnable {
|
||||
|
||||
private final String mScript;
|
||||
private OnRunFinishedListener mOnRunFinishedListener;
|
||||
|
||||
RunScriptRunnable(String script, OnRunFinishedListener listener, RunningConfig config) {
|
||||
mOnRunFinishedListener = listener;
|
||||
mScript = script;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (mScript.startsWith(AUTO))
|
||||
DroidRuntime.getRuntime().ensureAccessibilityServiceEnabled();
|
||||
mOnRunFinishedListener.onRunFinished(JAVA_SCRIPT_ENGINE.execute(mScript));
|
||||
} catch (Exception e) {
|
||||
mOnRunFinishedListener.onException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package autojs;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.stardust.scriptdroid.R;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
|
||||
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/4/1.
|
||||
*/
|
||||
|
||||
public class PathChecker {
|
||||
public static final int CHECK_RESULT_OK = 0;
|
||||
|
||||
private Activity mActivity;
|
||||
|
||||
public PathChecker(Activity activity) {
|
||||
mActivity = activity;
|
||||
}
|
||||
|
||||
|
||||
public static int check(final String path) {
|
||||
if (TextUtils.isEmpty(path))
|
||||
return R.string.text_path_is_empty;
|
||||
if (!new File(path).exists())
|
||||
return R.string.text_file_not_exists;
|
||||
return CHECK_RESULT_OK;
|
||||
}
|
||||
|
||||
public boolean checkAndToastError(String path) {
|
||||
int result = checkWithStoragePermission(path);
|
||||
if (result != CHECK_RESULT_OK) {
|
||||
Toast.makeText(mActivity, result, Toast.LENGTH_SHORT).show();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private int checkWithStoragePermission(String path) {
|
||||
if (!hasStorageReadPermission(mActivity)) {
|
||||
return R.string.text_no_file_rw_permission;
|
||||
}
|
||||
return check(path);
|
||||
}
|
||||
|
||||
private static boolean hasStorageReadPermission(Activity activity) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
return Build.VERSION.SDK_INT < Build.VERSION_CODES.M ||
|
||||
activity.checkSelfPermission(READ_EXTERNAL_STORAGE) == PERMISSION_GRANTED;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package autojs;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/2/1.
|
||||
*/
|
||||
public class RunningConfig {
|
||||
|
||||
private static final RunningConfig RUNNING_CONFIG = new RunningConfig();
|
||||
public String path;
|
||||
public String prepareScript = "";
|
||||
|
||||
public static RunningConfig getDefault() {
|
||||
return RUNNING_CONFIG;
|
||||
}
|
||||
|
||||
public boolean runInNewThread = true;
|
||||
|
||||
public RunningConfig runInNewThread(boolean runInNewThread) {
|
||||
this.runInNewThread = runInNewThread;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RunningConfig path(String path) {
|
||||
this.path = path;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RunningConfig prepareScript(String script) {
|
||||
this.prepareScript = script;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -1,442 +0,0 @@
|
||||
package autojs.runtime;
|
||||
|
||||
import android.accessibilityservice.AccessibilityService;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.SpannableString;
|
||||
import android.text.Spanned;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import android.util.Log;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.jraska.console.Console;
|
||||
import com.jraska.console.timber.ConsoleTree;
|
||||
import com.stardust.automator.AccessibilityEventCommandHost;
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.Pref;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.accessibility.AccessibilityInfoProvider;
|
||||
import com.stardust.scriptdroid.droid.runtime.action.Action;
|
||||
import com.stardust.scriptdroid.droid.runtime.action.ActionFactory;
|
||||
import com.stardust.scriptdroid.droid.runtime.action.ActionPerformAccessibilityDelegate;
|
||||
import com.stardust.scriptdroid.droid.runtime.action.ActionTarget;
|
||||
import com.stardust.scriptdroid.droid.runtime.api.UiSelector;
|
||||
import com.stardust.scriptdroid.service.AccessibilityWatchDogService;
|
||||
import com.stardust.scriptdroid.tool.AccessibilityServiceTool;
|
||||
import com.stardust.scriptdroid.tool.FileUtils;
|
||||
import com.stardust.scriptdroid.tool.IntentTool;
|
||||
import com.stardust.scriptdroid.tool.Shell;
|
||||
import com.stardust.scriptdroid.ui.console.ConsoleActivity;
|
||||
import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder;
|
||||
import com.stardust.view.accessibility.AccessibilityServiceUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/27.
|
||||
*/
|
||||
|
||||
public class DroidRuntime {
|
||||
|
||||
static {
|
||||
Timber.plant(new ConsoleTree.Builder()
|
||||
.minPriority(Log.VERBOSE)
|
||||
.verboseColor(0xff909090)
|
||||
.debugColor(0xffc88b48)
|
||||
.infoColor(0xffc9c9c9)
|
||||
.warnColor(0xffa97db6)
|
||||
.errorColor(0xffff534e)
|
||||
.assertColor(0xffff5540)
|
||||
.build());
|
||||
}
|
||||
|
||||
private static class PerformGlobalActionCommand implements AccessibilityEventCommandHost.Command {
|
||||
|
||||
boolean result;
|
||||
private int mGlobalAction;
|
||||
|
||||
PerformGlobalActionCommand(int globalAction) {
|
||||
mGlobalAction = globalAction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(AccessibilityService service, AccessibilityEvent event) {
|
||||
result = service.performGlobalAction(mGlobalAction);
|
||||
}
|
||||
}
|
||||
|
||||
private static final String TAG = "DroidRuntime";
|
||||
private static DroidRuntime runtime;
|
||||
|
||||
private final Object mActionPerformLock = new Object();
|
||||
private Handler mUIHandler;
|
||||
private Context mContext;
|
||||
|
||||
public static void initRuntime(Context context){
|
||||
runtime = new DroidRuntime(context);
|
||||
}
|
||||
|
||||
public static DroidRuntime getRuntime() {
|
||||
return runtime;
|
||||
}
|
||||
|
||||
private DroidRuntime(Context context) {
|
||||
mContext = context;
|
||||
mUIHandler = new Handler(mContext.getMainLooper());
|
||||
}
|
||||
|
||||
public boolean launchPackage(String packageName) {
|
||||
try {
|
||||
PackageManager packageManager = App.getApp().getPackageManager();
|
||||
App.getApp().startActivity(packageManager.getLaunchIntentForPackage(packageName));
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public boolean launchApp(String appName) {
|
||||
return launchPackage(getPackageName(appName));
|
||||
}
|
||||
|
||||
public String getPackageName(String appName) {
|
||||
PackageManager packageManager = App.getApp().getPackageManager();
|
||||
List<ApplicationInfo> installedApplications = packageManager.getInstalledApplications(PackageManager.GET_META_DATA);
|
||||
for (ApplicationInfo applicationInfo : installedApplications) {
|
||||
if (packageManager.getApplicationLabel(applicationInfo).toString().equals(appName)) {
|
||||
return applicationInfo.processName;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public boolean openAppSetting(String packageName) {
|
||||
return IntentTool.goToAppSetting(App.getApp(), packageName);
|
||||
}
|
||||
|
||||
public ActionTarget text(String text, int i) {
|
||||
return new ActionTarget.TextActionTarget(text, i);
|
||||
}
|
||||
|
||||
public ActionTarget bounds(int left, int top, int right, int bottom) {
|
||||
return new ActionTarget.BoundsActionTarget(new Rect(left, top, right, bottom));
|
||||
}
|
||||
|
||||
public ActionTarget editable(int i) {
|
||||
return new ActionTarget.EditableActionTarget(i);
|
||||
}
|
||||
|
||||
public ActionTarget id(String id) {
|
||||
return new ActionTarget.IdActionTarget(id);
|
||||
}
|
||||
|
||||
public boolean click(ActionTarget target) {
|
||||
return performAction(target.createAction(AccessibilityNodeInfo.ACTION_CLICK));
|
||||
}
|
||||
|
||||
public boolean longClick(ActionTarget target) {
|
||||
return performAction(target.createAction(AccessibilityNodeInfo.ACTION_LONG_CLICK));
|
||||
}
|
||||
|
||||
public boolean scrollUp(ActionTarget target) {
|
||||
return performAction(target.createAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD));
|
||||
}
|
||||
|
||||
public boolean scrollDown(ActionTarget target) {
|
||||
return performAction(target.createAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD));
|
||||
}
|
||||
|
||||
public boolean scrollUp(int i) {
|
||||
return performAction(ActionFactory.createScrollAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD, i));
|
||||
}
|
||||
|
||||
public boolean scrollDown(int i) {
|
||||
return performAction(ActionFactory.createScrollAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD, i));
|
||||
}
|
||||
|
||||
public boolean scrollAllUp() {
|
||||
return performAction(ActionFactory.createScrollMaxAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD));
|
||||
}
|
||||
|
||||
public boolean scrollAllDown() {
|
||||
return performAction(ActionFactory.createScrollMaxAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD));
|
||||
}
|
||||
|
||||
public boolean focus(ActionTarget target) {
|
||||
return performAction(target.createAction(AccessibilityNodeInfo.ACTION_FOCUS));
|
||||
}
|
||||
|
||||
public boolean select(ActionTarget target) {
|
||||
return performAction(target.createAction(AccessibilityNodeInfo.ACTION_SELECT));
|
||||
}
|
||||
|
||||
public boolean setText(ActionTarget target, String text) {
|
||||
return performAction(target.createAction(AccessibilityNodeInfo.ACTION_SET_TEXT, text));
|
||||
}
|
||||
|
||||
public void setClip(final String text) {
|
||||
mUIHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
((ClipboardManager) App.getApp().getSystemService(Context.CLIPBOARD_SERVICE)).setPrimaryClip(ClipData.newPlainText(TAG, text));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean back() {
|
||||
return performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK);
|
||||
}
|
||||
|
||||
public boolean home() {
|
||||
return performGlobalAction(AccessibilityService.GLOBAL_ACTION_HOME);
|
||||
}
|
||||
|
||||
public boolean powerDialog() {
|
||||
return performGlobalAction(AccessibilityService.GLOBAL_ACTION_POWER_DIALOG);
|
||||
}
|
||||
|
||||
public boolean notifications() {
|
||||
return performGlobalAction(AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS);
|
||||
}
|
||||
|
||||
public boolean quickSettings() {
|
||||
return performGlobalAction(AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS);
|
||||
}
|
||||
|
||||
public boolean recents() {
|
||||
return performGlobalAction(AccessibilityService.GLOBAL_ACTION_RECENTS);
|
||||
}
|
||||
|
||||
public boolean splitScreen() {
|
||||
return performGlobalAction(AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN);
|
||||
}
|
||||
|
||||
public boolean swipeDown() {
|
||||
return performGlobalAction(AccessibilityService.GESTURE_SWIPE_DOWN);
|
||||
}
|
||||
|
||||
public boolean swipeDownLeft() {
|
||||
return performGlobalAction(AccessibilityService.GESTURE_SWIPE_DOWN_AND_LEFT);
|
||||
}
|
||||
|
||||
public boolean swipeDownRight() {
|
||||
return performGlobalAction(AccessibilityService.GESTURE_SWIPE_DOWN_AND_RIGHT);
|
||||
}
|
||||
|
||||
public boolean swipeDownUp() {
|
||||
return performGlobalAction(AccessibilityService.GESTURE_SWIPE_DOWN_AND_UP);
|
||||
}
|
||||
|
||||
public boolean swipeUp() {
|
||||
return performGlobalAction(AccessibilityService.GESTURE_SWIPE_UP);
|
||||
}
|
||||
|
||||
public boolean swipeUpLeft() {
|
||||
return performGlobalAction(AccessibilityService.GESTURE_SWIPE_UP_AND_LEFT);
|
||||
}
|
||||
|
||||
public boolean swipeUpRight() {
|
||||
return performGlobalAction(AccessibilityService.GESTURE_SWIPE_UP_AND_RIGHT);
|
||||
}
|
||||
|
||||
public boolean swipeUpDown() {
|
||||
return performGlobalAction(AccessibilityService.GESTURE_SWIPE_UP_AND_DOWN);
|
||||
}
|
||||
|
||||
public boolean swipeLeft() {
|
||||
return performGlobalAction(AccessibilityService.GESTURE_SWIPE_LEFT);
|
||||
}
|
||||
|
||||
public boolean swipeLeftRight() {
|
||||
return performGlobalAction(AccessibilityService.GESTURE_SWIPE_LEFT_AND_RIGHT);
|
||||
}
|
||||
|
||||
public boolean swipeLeftUp() {
|
||||
return performGlobalAction(AccessibilityService.GESTURE_SWIPE_LEFT_AND_UP);
|
||||
}
|
||||
|
||||
public boolean swipeLeftDown() {
|
||||
return performGlobalAction(AccessibilityService.GESTURE_SWIPE_LEFT_AND_DOWN);
|
||||
}
|
||||
|
||||
public boolean swipeRight() {
|
||||
return performGlobalAction(AccessibilityService.GESTURE_SWIPE_RIGHT);
|
||||
}
|
||||
|
||||
public boolean swipeRightLeft() {
|
||||
return performGlobalAction(AccessibilityService.GESTURE_SWIPE_RIGHT_AND_LEFT);
|
||||
}
|
||||
|
||||
public boolean swipeRightUp() {
|
||||
return performGlobalAction(AccessibilityService.GESTURE_SWIPE_RIGHT_AND_UP);
|
||||
}
|
||||
|
||||
public boolean swipeRightDown() {
|
||||
return performGlobalAction(AccessibilityService.GESTURE_SWIPE_RIGHT_AND_DOWN);
|
||||
}
|
||||
|
||||
private boolean performGlobalAction(final int action) {
|
||||
ensureAccessibilityServiceEnabled();
|
||||
PerformGlobalActionCommand command = new PerformGlobalActionCommand(action);
|
||||
AccessibilityEventCommandHost.getInstance().executeAndWaitForEvent(command);
|
||||
return command.result;
|
||||
}
|
||||
|
||||
public boolean paste(ActionTarget target) {
|
||||
return performAction(target.createAction(AccessibilityNodeInfo.ACTION_PASTE));
|
||||
}
|
||||
|
||||
public void log(@Nullable Object o) {
|
||||
String str = o + "";
|
||||
SpannableString spannableString = new SpannableString(str);
|
||||
spannableString.setSpan(new ForegroundColorSpan(Color.BLACK), 0, str.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
Console.writeLine(spannableString);
|
||||
}
|
||||
|
||||
public void err(@Nullable Object o) {
|
||||
Timber.e("" + o);
|
||||
}
|
||||
|
||||
public void console() {
|
||||
App.getApp().startActivity(new Intent(App.getApp(), ConsoleActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
}
|
||||
|
||||
public void clearConsole() {
|
||||
Console.clear();
|
||||
}
|
||||
|
||||
private <T> T performAction(Action action) {
|
||||
ensureAccessibilityServiceEnabled();
|
||||
ActionPerformAccessibilityDelegate.setAction(action);
|
||||
synchronized (mActionPerformLock) {
|
||||
try {
|
||||
mActionPerformLock.wait();
|
||||
} catch (InterruptedException e) {
|
||||
ActionPerformAccessibilityDelegate.setAction(ActionPerformAccessibilityDelegate.NO_ACTION);
|
||||
throw new ScriptStopException(App.getApp().getString(R.string.text_script_stopped), e);
|
||||
}
|
||||
}
|
||||
return (T) action.getResult();
|
||||
}
|
||||
|
||||
public void ensureAccessibilityServiceEnabled() {
|
||||
if (AccessibilityWatchDogService.getInstance() == null) {
|
||||
String errorMessage = null;
|
||||
if (AccessibilityServiceUtils.isAccessibilityServiceEnabled(App.getApp(), AccessibilityWatchDogService.class)) {
|
||||
errorMessage = App.getApp().getString(R.string.text_auto_operate_service_enabled_but_not_running);
|
||||
} else {
|
||||
if (Pref.def().getBoolean(App.getApp().getString(R.string.key_enable_accessibility_service_by_root), false)) {
|
||||
if (!AccessibilityServiceTool.enableAccessibilityServiceByRootAndWaitFor(AccessibilityWatchDogService.class, 3000)) {
|
||||
errorMessage = App.getApp().getString(R.string.text_enable_accessibility_service_by_root_timeout);
|
||||
}
|
||||
} else {
|
||||
errorMessage = App.getApp().getString(R.string.text_no_accessibility_permission);
|
||||
}
|
||||
}
|
||||
if (errorMessage != null) {
|
||||
toast(errorMessage);
|
||||
throw new ScriptStopException(errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void toast(final String text) {
|
||||
mUIHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(App.getApp(), text, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void sleep(long millis) {
|
||||
try {
|
||||
Thread.sleep(millis);
|
||||
} catch (InterruptedException e) {
|
||||
throw new ScriptStopException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void addAccessibilityEventListener(final Object delegate) {
|
||||
if (delegate == null)
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
public Shell.CommandResult shell(String cmd, int root) {
|
||||
return Shell.execCommand(cmd, root != 0);
|
||||
}
|
||||
|
||||
public String currentPackage() {
|
||||
ensureAccessibilityServiceEnabled();
|
||||
return AccessibilityInfoProvider.getInstance().getLatestPackage();
|
||||
}
|
||||
|
||||
public String currentActivity() {
|
||||
ensureAccessibilityServiceEnabled();
|
||||
return AccessibilityInfoProvider.getInstance().getLatestActivity();
|
||||
}
|
||||
|
||||
public UiSelector selector() {
|
||||
return new UiSelector();
|
||||
}
|
||||
|
||||
public boolean isStopped() {
|
||||
return Thread.currentThread().isInterrupted();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
Thread.interrupted();
|
||||
}
|
||||
|
||||
public String readFile(String path) {
|
||||
return FileUtils.readString(new File(Environment.getExternalStorageDirectory() + "/" + path));
|
||||
}
|
||||
|
||||
public ThemeColorMaterialDialogBuilder dialog() {
|
||||
if (App.currentActivity() == null) {
|
||||
throw new ScriptStopException(App.getApp().getString(R.string.text_cannot_create_dialog_when_app_invisible));
|
||||
}
|
||||
return new ThemeColorMaterialDialogBuilder(App.currentActivity()) {
|
||||
|
||||
public MaterialDialog show() {
|
||||
mUIHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
superShow();
|
||||
}
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
private void superShow() {
|
||||
super.show();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void notifyActionPerformed() {
|
||||
synchronized (mActionPerformLock) {
|
||||
mActionPerformLock.notify();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package autojs.runtime.action;
|
||||
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/27.
|
||||
*/
|
||||
|
||||
public abstract class Action {
|
||||
|
||||
private boolean mPerformUtilSucceed = false;
|
||||
private volatile Object mResult = false;
|
||||
|
||||
public Action(boolean performUtilSucceed) {
|
||||
mPerformUtilSucceed = performUtilSucceed;
|
||||
}
|
||||
|
||||
public Action() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
public abstract boolean perform(AccessibilityNodeInfo root);
|
||||
|
||||
public boolean performUtilSucceed() {
|
||||
return mPerformUtilSucceed;
|
||||
}
|
||||
|
||||
public Action setPerformUtilSucceed(boolean performUtilSucceed) {
|
||||
mPerformUtilSucceed = performUtilSucceed;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Object getResult() {
|
||||
return mResult;
|
||||
}
|
||||
|
||||
public void setResult(Object result) {
|
||||
mResult = result;
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
package autojs.runtime.action;
|
||||
|
||||
import android.accessibilityservice.AccessibilityService;
|
||||
import android.util.Log;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.scriptdroid.droid.runtime.DroidRuntime;
|
||||
import com.stardust.view.accessibility.AccessibilityDelegate;
|
||||
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/21.
|
||||
*/
|
||||
|
||||
public class ActionPerformAccessibilityDelegate implements AccessibilityDelegate {
|
||||
|
||||
private static final String TAG = "ActionPerformDelegate";
|
||||
|
||||
public static final Action NO_ACTION = null;
|
||||
|
||||
private static final Object ACTION_LOCK = new Object();
|
||||
|
||||
private static Action action;
|
||||
|
||||
//private Executor mExecutor = Executors.newFixedThreadPool(5);
|
||||
|
||||
public static void setAction(Action action) {
|
||||
synchronized (ACTION_LOCK) {
|
||||
ActionPerformAccessibilityDelegate.action = action;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onAccessibilityEvent(AccessibilityService service, AccessibilityEvent event) {
|
||||
synchronized (ACTION_LOCK) {
|
||||
if (action == NO_ACTION)
|
||||
return false;
|
||||
AccessibilityNodeInfo root = service.getRootInActiveWindow();
|
||||
if (root == null) {
|
||||
Log.v(TAG, "root = null");
|
||||
return false;
|
||||
}
|
||||
performAction(root, action);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void performAction(final AccessibilityNodeInfo root, final Action action) {
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Log.i(TAG, "perform action:" + action);
|
||||
if (action.perform(root)) {
|
||||
action.setResult(true);
|
||||
onActionPerformed();
|
||||
} else if (!action.performUtilSucceed()) {
|
||||
action.setResult(false);
|
||||
onActionPerformed();
|
||||
}
|
||||
}
|
||||
}.run();
|
||||
}
|
||||
|
||||
|
||||
private void onActionPerformed() {
|
||||
synchronized (ACTION_LOCK) {
|
||||
action = NO_ACTION;
|
||||
DroidRuntime.getRuntime().notifyActionPerformed();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
package autojs.script;
|
||||
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.BuildConfig;
|
||||
import com.stardust.scriptdroid.tool.FileUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/27.
|
||||
*/
|
||||
|
||||
public abstract class JavaScriptEngine {
|
||||
|
||||
private static JavaScriptEngine defaultEngine;
|
||||
|
||||
public static JavaScriptEngine getDefault() {
|
||||
return defaultEngine;
|
||||
}
|
||||
|
||||
public static void setDefault(JavaScriptEngine engine) {
|
||||
defaultEngine = engine;
|
||||
}
|
||||
|
||||
Map<String, Object> mVariableMap = new HashMap<>();
|
||||
|
||||
public abstract Object execute(String script);
|
||||
|
||||
public void set(String varName, Object value) {
|
||||
mVariableMap.put(varName, value);
|
||||
}
|
||||
|
||||
public abstract void removeAndDestroy();
|
||||
|
||||
public abstract int stopAll();
|
||||
|
||||
public abstract String[] getGlobalFunctions();
|
||||
|
||||
static class Init {
|
||||
private static final String INIT_SCRIPT = readInitScript();
|
||||
|
||||
private static String readInitScript() {
|
||||
try {
|
||||
return FileUtils.readString(App.getApp().getAssets().open("javasccript_engine_init.js"));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
static String getInitScript() {
|
||||
if (BuildConfig.DEBUG) {
|
||||
// 调试时不缓存INIT_SCRIPT否则修改javasccript_engine_init.js后不会更新
|
||||
return readInitScript();
|
||||
} else {
|
||||
return INIT_SCRIPT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
package autojs.script;
|
||||
|
||||
import com.iwebpp.node.NodeContext;
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.droid.Droid;
|
||||
import com.stardust.scriptdroid.droid.runtime.DroidRuntime;
|
||||
import com.stardust.scriptdroid.tool.FileUtils;
|
||||
|
||||
import org.mozilla.javascript.Context;
|
||||
import org.mozilla.javascript.Scriptable;
|
||||
import org.mozilla.javascript.ScriptableObject;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/25.
|
||||
*/
|
||||
|
||||
public class NodeJsJavaScriptEngine extends RhinoJavaScriptEngine {
|
||||
|
||||
public NodeJsJavaScriptEngine(DroidRuntime runtime) {
|
||||
super(runtime);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object execute(String script) {
|
||||
NodeContext nodectx = new NodeContext();
|
||||
Context context = createContext();
|
||||
Scriptable scope = createScope(context);
|
||||
ScriptableObject.putProperty(scope, "NodeCurrentContext", Context.javaToJS(nodectx, scope));
|
||||
init(context, scope);
|
||||
Object result = context.evaluateString(scope, script, "<script>", 1, null);
|
||||
try {
|
||||
nodectx.execute();
|
||||
} catch (Throwable throwable) {
|
||||
throw new RuntimeException(throwable);
|
||||
}
|
||||
if (!script.startsWith(Droid.UI) && !script.startsWith(Droid.STAY))
|
||||
removeAndDestroy();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init(Context context, Scriptable scope) {
|
||||
super.init(context, scope);
|
||||
try {
|
||||
context.evaluateString(scope, FileUtils.readString(App.getApp().getAssets().open("nodejs_engine_init.js")), "<nodejs_init>", 1, null);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void putProperties(Context context, Scriptable scope) {
|
||||
super.putProperties(context, scope);
|
||||
ScriptableObject.putProperty(scope, "NodeHostEnv", Context.javaToJS(this, scope));
|
||||
}
|
||||
}
|
||||
@@ -1,191 +0,0 @@
|
||||
package autojs.script;
|
||||
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.droid.Droid;
|
||||
import com.stardust.scriptdroid.droid.runtime.DroidRuntime;
|
||||
import com.stardust.scriptdroid.droid.runtime.ScriptStopException;
|
||||
import com.stardust.scriptdroid.droid.script.file.ScriptFile;
|
||||
|
||||
import org.mozilla.javascript.Context;
|
||||
import org.mozilla.javascript.ContextFactory;
|
||||
import org.mozilla.javascript.ImporterTopLevel;
|
||||
import org.mozilla.javascript.Scriptable;
|
||||
import org.mozilla.javascript.ScriptableObject;
|
||||
import org.mozilla.javascript.commonjs.module.RequireBuilder;
|
||||
import org.mozilla.javascript.commonjs.module.provider.ModuleSource;
|
||||
import org.mozilla.javascript.commonjs.module.provider.SoftCachingModuleScriptProvider;
|
||||
import org.mozilla.javascript.commonjs.module.provider.UrlModuleSourceProvider;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/1.
|
||||
*/
|
||||
|
||||
public class RhinoJavaScriptEngine extends JavaScriptEngine {
|
||||
|
||||
static {
|
||||
ContextFactory.initGlobal(new InterruptibleContextFactory());
|
||||
}
|
||||
|
||||
private final Set<Thread> mThreads = new HashSet<>();
|
||||
private String[] mFunctions;
|
||||
|
||||
public RhinoJavaScriptEngine(DroidRuntime runtime) {
|
||||
set("autojs", runtime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object execute(String script) {
|
||||
Context context = createContext();
|
||||
Scriptable scope = createScope(context);
|
||||
init(context, scope);
|
||||
Object result = context.evaluateString(scope, script, "<script>", 1, null);
|
||||
if (!script.startsWith(Droid.UI) && !script.startsWith(Droid.STAY))
|
||||
removeAndDestroy();
|
||||
return result;
|
||||
}
|
||||
|
||||
protected Scriptable createScope(Context context) {
|
||||
ImporterTopLevel importerTopLevel = new ImporterTopLevel();
|
||||
importerTopLevel.initStandardObjects(context, false);
|
||||
return importerTopLevel;
|
||||
}
|
||||
|
||||
protected Context createContext() {
|
||||
Context context = Context.enter();
|
||||
context.setOptimizationLevel(-1);
|
||||
context.setLanguageVersion(Context.VERSION_1_7);
|
||||
context.setInstructionObserverThreshold(10000);
|
||||
return context;
|
||||
}
|
||||
|
||||
protected void init(Context context, Scriptable scope) {
|
||||
putProperties(context, scope);
|
||||
initRequireBuilder(context, scope);
|
||||
context.evaluateString(scope, Init.getInitScript(), "<init>", 1, null);
|
||||
mThreads.add(Thread.currentThread());
|
||||
}
|
||||
|
||||
protected void putProperties(Context context, Scriptable scope) {
|
||||
ScriptableObject.putProperty(scope, "context", App.getApp());
|
||||
ScriptableObject.putProperty(scope, "__engine__", "rhino");
|
||||
for (Map.Entry<String, Object> variable : mVariableMap.entrySet()) {
|
||||
ScriptableObject.putProperty(scope, variable.getKey(), Context.javaToJS(variable.getValue(), scope));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void initRequireBuilder(Context context, Scriptable scope) {
|
||||
List<URI> list = Collections.singletonList(new File(ScriptFile.DEFAULT_DIRECTORY_PATH).toURI());
|
||||
AssetAndUrlModuleSourceProvider provider = new AssetAndUrlModuleSourceProvider(App.getApp(), list);
|
||||
new RequireBuilder()
|
||||
.setModuleScriptProvider(new SoftCachingModuleScriptProvider(provider))
|
||||
.setSandboxed(true)
|
||||
.createRequire(context, scope)
|
||||
.install(scope);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int stopAll() {
|
||||
int n;
|
||||
synchronized (mThreads) {
|
||||
for (Thread thread : mThreads) {
|
||||
thread.interrupt();
|
||||
}
|
||||
n = mThreads.size();
|
||||
mThreads.clear();
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String[] getGlobalFunctions() {
|
||||
if (mFunctions == null)
|
||||
mFunctions = getGlobalFunctionsInner();
|
||||
return mFunctions;
|
||||
}
|
||||
|
||||
private String[] getGlobalFunctionsInner() {
|
||||
Scriptable scriptable = (Scriptable) execute("this");
|
||||
Object[] ids = scriptable.getIds();
|
||||
String[] functions = new String[ids.length];
|
||||
for (int i = 0; i < ids.length; i++) {
|
||||
functions[i] = ids[i].toString();
|
||||
}
|
||||
return functions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAndDestroy() {
|
||||
synchronized (mThreads) {
|
||||
mThreads.remove(Thread.currentThread());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class InterruptibleContextFactory extends ContextFactory {
|
||||
|
||||
@Override
|
||||
protected void observeInstructionCount(Context cx, int instructionCount) {
|
||||
if (Thread.currentThread().isInterrupted()) {
|
||||
Context.exit();
|
||||
throw new ScriptStopException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Context makeContext() {
|
||||
Context cx = super.makeContext();
|
||||
cx.setInstructionObserverThreshold(10000);
|
||||
return cx;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class AssetAndUrlModuleSourceProvider extends UrlModuleSourceProvider {
|
||||
|
||||
private static final String MODULES_PATH = "modules";
|
||||
private android.content.Context mContext;
|
||||
private List<String> mModules;
|
||||
private final URI mBaseURI = URI.create("file:///android_asset/modules");
|
||||
|
||||
public AssetAndUrlModuleSourceProvider(android.content.Context context, List<URI> list) {
|
||||
super(list, null);
|
||||
mContext = context;
|
||||
try {
|
||||
mModules = Arrays.asList(mContext.getAssets().list(MODULES_PATH));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected ModuleSource loadFromPrivilegedLocations(String moduleId, Object validator) throws IOException, URISyntaxException {
|
||||
String moduleIdWithExtension = moduleId;
|
||||
if (!moduleIdWithExtension.endsWith(".js")) {
|
||||
moduleIdWithExtension += ".js";
|
||||
}
|
||||
if (mModules.contains(moduleIdWithExtension)) {
|
||||
return new ModuleSource(new InputStreamReader(mContext.getAssets().open(MODULES_PATH + "/" + moduleIdWithExtension)), null,
|
||||
URI.create(moduleIdWithExtension), mBaseURI, validator);
|
||||
}
|
||||
return super.loadFromPrivilegedLocations(moduleId, validator);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package autojs.script;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.droid.Droid;
|
||||
import com.stardust.scriptdroid.droid.RunningConfig;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/2/5.
|
||||
*/
|
||||
|
||||
public class ScriptExecuteActivity extends Activity {
|
||||
|
||||
private static final String EXTRA_SCRIPT = "EXTRA_SCRIPT";
|
||||
private static final String EXTRA_ON_RUN_FINISHED_LISTENER = "EXTRA_ON_RUN_FINISHED_LISTENER";
|
||||
private Object mResult;
|
||||
private String mScript;
|
||||
private Droid.OnRunFinishedListener mOnRunFinishedListener;
|
||||
|
||||
|
||||
public static void runScript(String script, Droid.OnRunFinishedListener listener, RunningConfig config) {
|
||||
App.getApp().startActivity(new Intent(App.getApp(), ScriptExecuteActivity.class)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
.putExtra(EXTRA_SCRIPT, script)
|
||||
.putExtra(EXTRA_ON_RUN_FINISHED_LISTENER, listener));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
handleIntent(getIntent());
|
||||
runScript();
|
||||
}
|
||||
|
||||
private void handleIntent(Intent intent) {
|
||||
mScript = intent.getStringExtra(EXTRA_SCRIPT);
|
||||
mOnRunFinishedListener = (Droid.OnRunFinishedListener) intent.getSerializableExtra(EXTRA_ON_RUN_FINISHED_LISTENER);
|
||||
}
|
||||
|
||||
private void runScript() {
|
||||
Droid.JAVA_SCRIPT_ENGINE.set("activity", this);
|
||||
try {
|
||||
mResult = Droid.JAVA_SCRIPT_ENGINE.execute(mScript);
|
||||
} catch (Exception e) {
|
||||
mOnRunFinishedListener.onException(e);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
mOnRunFinishedListener.onRunFinished(mResult);
|
||||
super.finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
Droid.JAVA_SCRIPT_ENGINE.set("activity", null);
|
||||
Droid.JAVA_SCRIPT_ENGINE.removeAndDestroy();
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
package autojs.script.file;
|
||||
|
||||
import android.os.Environment;
|
||||
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.droid.Droid;
|
||||
import com.stardust.scriptdroid.tool.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FilenameFilter;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/23.
|
||||
*/
|
||||
|
||||
public class ScriptFile extends File {
|
||||
|
||||
public static final String DEFAULT_DIRECTORY_PATH = Environment.getExternalStorageDirectory() + App.getApp().getString(R.string.folder_name);
|
||||
public static final ScriptFile DEFAULT_DIRECTORY = new ScriptFile(DEFAULT_DIRECTORY_PATH);
|
||||
|
||||
private String mSimplifyPath;
|
||||
private String mSimplifiedName;
|
||||
|
||||
public ScriptFile(String path) {
|
||||
super(path);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
mSimplifiedName = FileUtils.getNameWithoutExtension(getPath());
|
||||
mSimplifyPath = getPath();
|
||||
if (mSimplifyPath.startsWith(Environment.getExternalStorageDirectory().getPath())) {
|
||||
mSimplifyPath = mSimplifyPath.substring(Environment.getExternalStorageDirectory().getPath().length());
|
||||
}
|
||||
}
|
||||
|
||||
public ScriptFile(ScriptFile parent, String child) {
|
||||
super(parent, child);
|
||||
init();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
Droid.getInstance().runScriptFile(this);
|
||||
}
|
||||
|
||||
public boolean renameTo(String newName) {
|
||||
return renameTo(new File(getParent(), newName));
|
||||
}
|
||||
|
||||
public String getSimplifiedPath() {
|
||||
return mSimplifyPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptFile getParentFile() {
|
||||
String p = this.getParent();
|
||||
if (p == null)
|
||||
return null;
|
||||
return new ScriptFile(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptFile[] listFiles() {
|
||||
return listFiles(new FileFilter() {
|
||||
@Override
|
||||
public boolean accept(File file) {
|
||||
return file.isDirectory() || (file.getName().endsWith(".js") && !file.getName().startsWith("."));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptFile[] listFiles(FilenameFilter filter) {
|
||||
String ss[] = list();
|
||||
if (ss == null) return null;
|
||||
ArrayList<ScriptFile> files = new ArrayList<>();
|
||||
for (String s : ss)
|
||||
if ((filter == null) || filter.accept(this, s))
|
||||
files.add(new ScriptFile(this, s));
|
||||
return files.toArray(new ScriptFile[files.size()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptFile[] listFiles(FileFilter filter) {
|
||||
String ss[] = list();
|
||||
if (ss == null) return null;
|
||||
ArrayList<ScriptFile> files = new ArrayList<>();
|
||||
for (String s : ss) {
|
||||
ScriptFile f = new ScriptFile(this, s);
|
||||
if ((filter == null) || filter.accept(f))
|
||||
files.add(f);
|
||||
}
|
||||
return files.toArray(new ScriptFile[files.size()]);
|
||||
|
||||
}
|
||||
|
||||
public String getSimplifiedName() {
|
||||
return mSimplifiedName;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package autojs.script.file;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/23.
|
||||
*/
|
||||
|
||||
public abstract class ScriptFileList {
|
||||
|
||||
private static ScriptFileList impl;
|
||||
|
||||
public static void setImpl(ScriptFileList list) {
|
||||
impl = list;
|
||||
}
|
||||
|
||||
public static ScriptFileList getImpl() {
|
||||
return impl;
|
||||
}
|
||||
|
||||
public abstract void add(ScriptFile scriptFile);
|
||||
|
||||
public abstract ScriptFile get(int i);
|
||||
|
||||
public abstract void remove(int i);
|
||||
|
||||
public abstract void rename(int position, String newName, boolean renameFile);
|
||||
|
||||
public abstract int size();
|
||||
|
||||
public boolean deleteFromFileSystem(int i) {
|
||||
if (i < 0 || i >= size())
|
||||
return false;
|
||||
File file = get(i);
|
||||
remove(i);
|
||||
return file.delete();
|
||||
}
|
||||
|
||||
public abstract boolean containsPath(String path);
|
||||
|
||||
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
package autojs.script.file;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.tool.FileUtils;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/23.
|
||||
*/
|
||||
|
||||
public class SharedPrefScriptFileList extends ScriptFileList {
|
||||
|
||||
private static final Gson GSON = new Gson();
|
||||
|
||||
private static final String SP_KEY_SCRIPT_NAME = "script_name";
|
||||
private static final String SP_KEY_SCRIPT_PATH = "script_path";
|
||||
|
||||
private static ScriptFileList instance = new SharedPrefScriptFileList(App.getApp());
|
||||
|
||||
private SharedPreferences mSharedPreferences;
|
||||
private List<String> mScriptPath;
|
||||
private List<String> mScriptName;
|
||||
|
||||
public static ScriptFileList getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public SharedPrefScriptFileList(Context context) {
|
||||
mSharedPreferences = context.getSharedPreferences("SharedPrefScriptFileList", Context.MODE_PRIVATE);
|
||||
readFromSharedPref();
|
||||
}
|
||||
|
||||
|
||||
private void readFromSharedPref() {
|
||||
Type type = new TypeToken<List<String>>() {
|
||||
}.getType();
|
||||
mScriptName = GSON.fromJson(mSharedPreferences.getString(SP_KEY_SCRIPT_NAME, ""), type);
|
||||
mScriptPath = GSON.fromJson(mSharedPreferences.getString(SP_KEY_SCRIPT_PATH, ""), type);
|
||||
if (mScriptName == null || mScriptPath == null || mScriptName.size() != mScriptPath.size()) {
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
private void reset() {
|
||||
mScriptName = new ArrayList<>();
|
||||
mScriptPath = new ArrayList<>();
|
||||
syncWithSharedPref();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(ScriptFile scriptFile) {
|
||||
mScriptName.add(scriptFile.getSimplifiedName());
|
||||
mScriptPath.add(scriptFile.getSimplifiedPath());
|
||||
syncWithSharedPref();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptFile get(int i) {
|
||||
return new ScriptFile(mScriptPath.get(i));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(int i) {
|
||||
mScriptName.remove(i);
|
||||
mScriptPath.remove(i);
|
||||
syncWithSharedPref();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rename(int position, String newName, boolean renameFile) {
|
||||
mScriptName.set(position, newName);
|
||||
if (renameFile) {
|
||||
String newPath = FileUtils.renameWithoutExtension(mScriptPath.get(position), newName);
|
||||
mScriptPath.set(position, newPath);
|
||||
}
|
||||
syncWithSharedPref();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return mScriptPath.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsPath(String path) {
|
||||
return mScriptPath.contains(path);
|
||||
}
|
||||
|
||||
protected void syncWithSharedPref() {
|
||||
SharedPreferences.Editor editor = mSharedPreferences.edit();
|
||||
editor.putString(SP_KEY_SCRIPT_NAME, GSON.toJson(mScriptName));
|
||||
editor.putString(SP_KEY_SCRIPT_PATH, GSON.toJson(mScriptPath));
|
||||
editor.apply();
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
package autojs.script.file;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/27.
|
||||
*/
|
||||
|
||||
public class StorageScriptFileList extends ScriptFileList {
|
||||
|
||||
private List<ScriptFile> mFiles;
|
||||
private ScriptFile mFolder;
|
||||
|
||||
public StorageScriptFileList() {
|
||||
this(ScriptFile.DEFAULT_DIRECTORY_PATH);
|
||||
}
|
||||
|
||||
|
||||
public ScriptFile getFolder() {
|
||||
return mFolder;
|
||||
}
|
||||
|
||||
public StorageScriptFileList(ScriptFile folder) {
|
||||
if (!folder.isDirectory()) {
|
||||
throw new IllegalArgumentException("file is not folder:" + folder);
|
||||
}
|
||||
mFolder = folder;
|
||||
mFiles = Arrays.asList(folder.listFiles(new FileFilter() {
|
||||
@Override
|
||||
public boolean accept(File file) {
|
||||
return file.isDirectory() || (file.getName().endsWith(".js") && !file.getName().startsWith("."));
|
||||
}
|
||||
}));
|
||||
Collections.sort(mFiles, new Comparator<ScriptFile>() {
|
||||
@Override
|
||||
public int compare(ScriptFile o1, ScriptFile o2) {
|
||||
if (o1.isDirectory() != o2.isDirectory()) {
|
||||
return o1.isDirectory() ? -1 : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public StorageScriptFileList(String path) {
|
||||
this(new ScriptFile(path));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void add(ScriptFile scriptFile) {
|
||||
try {
|
||||
scriptFile.createNewFile();
|
||||
mFiles.add(scriptFile);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptFile get(int i) {
|
||||
return mFiles.get(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(int i) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rename(int position, String newName, boolean renameFile) {
|
||||
if (!renameFile)
|
||||
throw new UnsupportedOperationException();
|
||||
mFiles.get(position).renameTo(newName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return mFiles.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsPath(String path) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.stardust.autojs;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/2/1.
|
||||
*/
|
||||
public class ExecutionConfig implements Serializable {
|
||||
|
||||
private static final ExecutionConfig RUNNING_CONFIG = new ExecutionConfig();
|
||||
public String path;
|
||||
public String prepareScript = "";
|
||||
|
||||
public static ExecutionConfig getDefault() {
|
||||
return RUNNING_CONFIG;
|
||||
}
|
||||
|
||||
public boolean runInNewThread = true;
|
||||
|
||||
public ExecutionConfig runInNewThread(boolean runInNewThread) {
|
||||
this.runInNewThread = runInNewThread;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ExecutionConfig path(String path) {
|
||||
this.path = path;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ExecutionConfig prepareScript(String script) {
|
||||
this.prepareScript = script;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
package com.stardust.autojs;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.stardust.autojs.engine.JavaScriptEngine;
|
||||
import com.stardust.autojs.engine.ScriptExecuteActivity;
|
||||
import com.stardust.autojs.engine.ScriptExecutionListener;
|
||||
import com.stardust.autojs.engine.ScriptExecutionTask;
|
||||
import com.stardust.autojs.script.ScriptSource;
|
||||
import com.stardust.autojs.engine.SimpleScriptExecutionListener;
|
||||
import com.stardust.autojs.runtime.ScriptRuntime;
|
||||
import com.stardust.autojs.runtime.api.Console;
|
||||
import com.stardust.autojs.engine.JavaScriptEngineManager;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/23.
|
||||
*/
|
||||
|
||||
public class ScriptEngineService {
|
||||
|
||||
private static ScriptEngineService instance;
|
||||
|
||||
public static ScriptEngineService getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static void setInstance(ScriptEngineService service) {
|
||||
instance = service;
|
||||
}
|
||||
|
||||
private ScriptRuntime mRuntime;
|
||||
private Context mContext;
|
||||
private Console mConsole;
|
||||
private final JavaScriptEngineManager mJavaScriptEngineManager;
|
||||
private final ScriptExecutionListener mDefaultListener = new SimpleScriptExecutionListener() {
|
||||
|
||||
@Override
|
||||
public void onStart(JavaScriptEngine engine, ScriptSource source) {
|
||||
mConsole.v(DateFormat.getTimeInstance().format(new Date()) + " " + mContext.getString(R.string.text_start_running) + " " + source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onException(JavaScriptEngine engine, ScriptSource source, Exception e) {
|
||||
if (!causedByInterruptedException(e)) {
|
||||
mRuntime.toast(mContext.getString(R.string.text_error) + ": " + e.getMessage());
|
||||
mConsole.e(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
ScriptEngineService(ScriptEngineServiceBuilder builder) {
|
||||
mRuntime = builder.mRuntime;
|
||||
mContext = builder.mContext;
|
||||
mJavaScriptEngineManager = builder.mJavaScriptEngineManager;
|
||||
mConsole = builder.mConsole;
|
||||
}
|
||||
|
||||
public ScriptRuntime getRuntime() {
|
||||
return mRuntime;
|
||||
}
|
||||
|
||||
public JavaScriptEngineManager getJavaScriptEngineManager() {
|
||||
return mJavaScriptEngineManager;
|
||||
}
|
||||
|
||||
public Console getConsole() {
|
||||
return mConsole;
|
||||
}
|
||||
|
||||
public ScriptExecutionListener getDefaultListener() {
|
||||
return mDefaultListener;
|
||||
}
|
||||
|
||||
public JavaScriptEngine createScriptEngine() {
|
||||
return mJavaScriptEngineManager.createEngine();
|
||||
}
|
||||
|
||||
public static boolean causedByInterruptedException(Throwable e) {
|
||||
while (e != null) {
|
||||
if (e instanceof InterruptedException) {
|
||||
return true;
|
||||
}
|
||||
e = e.getCause();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void execute(ScriptExecutionTask task) {
|
||||
ScriptExecutionListener listener = task.getExecutionListenerOrDefault(mDefaultListener);
|
||||
ScriptSource source = task.getScriptSource();
|
||||
int mode = source.getExecutionMode();
|
||||
if ((mode & ScriptSource.EXECUTION_MODE_UI) != 0) {
|
||||
ScriptExecuteActivity.execute(mContext, task);
|
||||
} else {
|
||||
new Thread(new ScriptExecution(source, listener, task.getExecutionConfig())).start();
|
||||
}
|
||||
}
|
||||
|
||||
public void execute(ScriptSource source, ScriptExecutionListener listener, ExecutionConfig config) {
|
||||
execute(new ScriptExecutionTask(source, listener, config));
|
||||
}
|
||||
|
||||
public int stopAll() {
|
||||
return mJavaScriptEngineManager.stopAll();
|
||||
}
|
||||
|
||||
|
||||
public void stopAllAndToast() {
|
||||
int n = stopAll();
|
||||
if (n > 0)
|
||||
mRuntime.toast(String.format(mContext.getString(R.string.text_already_stop_n_scripts), n));
|
||||
else
|
||||
mRuntime.toast(mContext.getString(R.string.text_no_running_script));
|
||||
}
|
||||
|
||||
public void execute(ScriptSource source, ScriptExecutionListener listener) {
|
||||
execute(source, listener, ExecutionConfig.getDefault());
|
||||
}
|
||||
|
||||
public void execute(ScriptSource source) {
|
||||
execute(source, mDefaultListener, ExecutionConfig.getDefault());
|
||||
}
|
||||
|
||||
private class ScriptExecution extends ScriptExecutionTask implements Runnable {
|
||||
|
||||
public ScriptExecution(ScriptSource source, ScriptExecutionListener listener, ExecutionConfig config) {
|
||||
super(source, listener, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
execute(mRuntime, mJavaScriptEngineManager.createEngine());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.stardust.autojs;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.stardust.autojs.engine.JavaScriptEngineManager;
|
||||
import com.stardust.autojs.runtime.ScriptRuntime;
|
||||
import com.stardust.autojs.runtime.api.Console;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/4/2.
|
||||
*/
|
||||
|
||||
public class ScriptEngineServiceBuilder {
|
||||
|
||||
ScriptRuntime mRuntime;
|
||||
Context mContext;
|
||||
Console mConsole;
|
||||
JavaScriptEngineManager mJavaScriptEngineManager;
|
||||
|
||||
public ScriptEngineServiceBuilder() {
|
||||
|
||||
}
|
||||
|
||||
public ScriptEngineServiceBuilder runtime(ScriptRuntime runtime) {
|
||||
mRuntime = runtime;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ScriptEngineServiceBuilder context(Context context) {
|
||||
mContext = context;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ScriptEngineServiceBuilder console(Console console) {
|
||||
mConsole = console;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ScriptEngineServiceBuilder engineManger(JavaScriptEngineManager manager) {
|
||||
mJavaScriptEngineManager = manager;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ScriptEngineService build() {
|
||||
return new ScriptEngineService(this);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.stardust.autojs.engine;
|
||||
|
||||
import com.stardust.autojs.script.ScriptSource;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/4/2.
|
||||
*/
|
||||
|
||||
public interface JavaScriptEngine {
|
||||
|
||||
void put(String name, Object value);
|
||||
|
||||
Object execute(ScriptSource scriptSource);
|
||||
|
||||
void stop();
|
||||
|
||||
void stopNotRemoveFromManager();
|
||||
|
||||
void destroy();
|
||||
|
||||
void init();
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package com.stardust.autojs.engine;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import com.stardust.autojs.BuildConfig;
|
||||
import com.stardust.autojs.script.ScriptSource;
|
||||
import com.stardust.pio.PFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/27.
|
||||
*/
|
||||
|
||||
public abstract class JavaScriptEngineManager {
|
||||
|
||||
private static final String TAG = "JavaScriptEngineManager";
|
||||
|
||||
private Map<String, Object> mGlobalVariableMap = new HashMap<>();
|
||||
private final Set<JavaScriptEngine> mEngines = new HashSet<>();
|
||||
private boolean mIsStopping = false;
|
||||
|
||||
private final ScriptSource INIT_SCRIPT;
|
||||
|
||||
private android.content.Context mContext;
|
||||
|
||||
public JavaScriptEngineManager(Context context) {
|
||||
mContext = context;
|
||||
INIT_SCRIPT = ScriptSource.of(readInitScript());
|
||||
}
|
||||
|
||||
public JavaScriptEngine createEngine() {
|
||||
JavaScriptEngine engine = createEngineInner();
|
||||
putProperties(engine);
|
||||
engine.init();
|
||||
synchronized (mEngines) {
|
||||
mEngines.add(engine);
|
||||
}
|
||||
return engine;
|
||||
}
|
||||
|
||||
public void put(String varName, Object value) {
|
||||
mGlobalVariableMap.put(varName, value);
|
||||
}
|
||||
|
||||
protected abstract JavaScriptEngine createEngineInner();
|
||||
|
||||
public abstract String[] getGlobalFunctions();
|
||||
|
||||
public android.content.Context getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
protected void putProperties(JavaScriptEngine engine) {
|
||||
for (Map.Entry<String, Object> variable : mGlobalVariableMap.entrySet()) {
|
||||
engine.put(variable.getKey(), variable.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
void removeEngine(RhinoJavaScriptEngine rhinoJavaScriptEngine) {
|
||||
synchronized (mEngines) {
|
||||
if (mIsStopping)
|
||||
return;
|
||||
mEngines.remove(rhinoJavaScriptEngine);
|
||||
}
|
||||
}
|
||||
|
||||
private String readInitScript() {
|
||||
try {
|
||||
return PFile.read(mContext.getAssets().open("javascript_engine_init.js"));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public ScriptSource getInitScript() {
|
||||
if (BuildConfig.DEBUG) {
|
||||
// 调试时不缓存INIT_SCRIPT否则修改javascript_engine_init.js后不会更新
|
||||
return ScriptSource.of(readInitScript());
|
||||
} else {
|
||||
return INIT_SCRIPT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public int stopAll() {
|
||||
synchronized (mEngines) {
|
||||
mIsStopping = true;
|
||||
int n = mEngines.size();
|
||||
for (JavaScriptEngine engine : mEngines) {
|
||||
engine.stopNotRemoveFromManager();
|
||||
}
|
||||
mEngines.clear();
|
||||
mIsStopping = false;
|
||||
return n;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.stardust.autojs.engine;
|
||||
|
||||
import com.iwebpp.node.NodeContext;
|
||||
import com.stardust.pio.PFile;
|
||||
import com.stardust.pio.UncheckedIOException;
|
||||
|
||||
import org.mozilla.javascript.Context;
|
||||
import org.mozilla.javascript.Scriptable;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/4/2.
|
||||
*/
|
||||
|
||||
public class NodeJsJavaScriptEngine extends RhinoJavaScriptEngine {
|
||||
|
||||
private static String initScript;
|
||||
private NodeContext mNodeContext = new NodeContext();
|
||||
|
||||
public NodeJsJavaScriptEngine(RhinoJavaScriptEngineManager engineManager) {
|
||||
super(engineManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
super.init();
|
||||
put("NodeCurrentContext", mNodeContext);
|
||||
getContext().evaluateString(getScriptable(), getNodeJsInitScript(), "<node_js_init>", 1, null);
|
||||
}
|
||||
|
||||
private String getNodeJsInitScript() {
|
||||
if (initScript == null) {
|
||||
try {
|
||||
initScript = PFile.read(getEngineManager().getContext().getAssets().open("nodejs_engine_init.js"));
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
return initScript;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.stardust.autojs.engine;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.stardust.autojs.runtime.ScriptRuntime;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/25.
|
||||
*/
|
||||
|
||||
public class NodeJsJavaScriptEngineManager extends RhinoJavaScriptEngineManager {
|
||||
|
||||
public NodeJsJavaScriptEngineManager(Context context, ScriptRuntime runtime) {
|
||||
super(context, runtime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NodeJsJavaScriptEngine createEngineInner() {
|
||||
NodeJsJavaScriptEngine engine = new NodeJsJavaScriptEngine(this);
|
||||
initRequireBuilder(engine.getContext(), engine.getScriptable());
|
||||
return engine;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package com.stardust.autojs.engine;
|
||||
|
||||
import com.stardust.autojs.runtime.ScriptStopException;
|
||||
import com.stardust.autojs.script.ScriptSource;
|
||||
|
||||
import org.mozilla.javascript.Context;
|
||||
import org.mozilla.javascript.ContextFactory;
|
||||
import org.mozilla.javascript.ImporterTopLevel;
|
||||
import org.mozilla.javascript.Scriptable;
|
||||
import org.mozilla.javascript.ScriptableObject;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/4/2.
|
||||
*/
|
||||
|
||||
public class RhinoJavaScriptEngine implements JavaScriptEngine {
|
||||
|
||||
static {
|
||||
ContextFactory.initGlobal(new InterruptibleContextFactory());
|
||||
}
|
||||
|
||||
private Context mContext;
|
||||
private Scriptable mScriptable;
|
||||
private Thread mThread;
|
||||
private RhinoJavaScriptEngineManager mEngineManager;
|
||||
|
||||
public RhinoJavaScriptEngine(RhinoJavaScriptEngineManager engineManager) {
|
||||
mEngineManager = engineManager;
|
||||
mThread = Thread.currentThread();
|
||||
mContext = createContext();
|
||||
mScriptable = createScope(mContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(String name, Object value) {
|
||||
ScriptableObject.putProperty(mScriptable, name, Context.javaToJS(value, mScriptable));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object execute(ScriptSource source) {
|
||||
return mContext.evaluateString(mScriptable, source.getScript(), "<script>", 1, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
stopNotRemoveFromManager();
|
||||
mEngineManager.removeEngine(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopNotRemoveFromManager() {
|
||||
mThread.interrupt();
|
||||
}
|
||||
|
||||
public RhinoJavaScriptEngineManager getEngineManager() {
|
||||
return mEngineManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
ScriptableObject.putProperty(mScriptable, "__engine__", "rhino");
|
||||
mContext.evaluateString(mScriptable, mEngineManager.getInitScript().getScript(), "<init>", 1, null);
|
||||
}
|
||||
|
||||
|
||||
public Context getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
public Scriptable getScriptable() {
|
||||
return mScriptable;
|
||||
}
|
||||
|
||||
protected Scriptable createScope(Context context) {
|
||||
ImporterTopLevel importerTopLevel = new ImporterTopLevel();
|
||||
importerTopLevel.initStandardObjects(context, false);
|
||||
return importerTopLevel;
|
||||
}
|
||||
|
||||
protected Context createContext() {
|
||||
Context context = Context.enter();
|
||||
context.setOptimizationLevel(-1);
|
||||
context.setLanguageVersion(Context.VERSION_1_7);
|
||||
return context;
|
||||
}
|
||||
|
||||
private static class InterruptibleContextFactory extends ContextFactory {
|
||||
|
||||
@Override
|
||||
protected void observeInstructionCount(Context cx, int instructionCount) {
|
||||
if (Thread.currentThread().isInterrupted()) {
|
||||
Context.exit();
|
||||
throw new ScriptStopException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Context makeContext() {
|
||||
Context cx = super.makeContext();
|
||||
cx.setInstructionObserverThreshold(10000);
|
||||
return cx;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package com.stardust.autojs.engine;
|
||||
|
||||
|
||||
import com.stardust.autojs.runtime.ScriptRuntime;
|
||||
import com.stardust.autojs.script.ScriptSource;
|
||||
|
||||
import org.mozilla.javascript.Context;
|
||||
import org.mozilla.javascript.Scriptable;
|
||||
import org.mozilla.javascript.commonjs.module.RequireBuilder;
|
||||
import org.mozilla.javascript.commonjs.module.provider.ModuleSource;
|
||||
import org.mozilla.javascript.commonjs.module.provider.SoftCachingModuleScriptProvider;
|
||||
import org.mozilla.javascript.commonjs.module.provider.UrlModuleSourceProvider;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/1.
|
||||
*/
|
||||
|
||||
public class RhinoJavaScriptEngineManager extends JavaScriptEngineManager {
|
||||
|
||||
private String[] mFunctions;
|
||||
|
||||
private String mRequirePath = "";
|
||||
|
||||
public RhinoJavaScriptEngineManager(android.content.Context context, ScriptRuntime runtime) {
|
||||
super(context);
|
||||
put("__runtime__", runtime);
|
||||
}
|
||||
|
||||
public RhinoJavaScriptEngine createEngineInner() {
|
||||
RhinoJavaScriptEngine engine = new RhinoJavaScriptEngine(this);
|
||||
initRequireBuilder(engine.getContext(), engine.getScriptable());
|
||||
return engine;
|
||||
}
|
||||
|
||||
public void setRequirePath(String requirePath) {
|
||||
mRequirePath = requirePath;
|
||||
}
|
||||
|
||||
void initRequireBuilder(Context context, Scriptable scope) {
|
||||
List<URI> list = Collections.singletonList(new File(mRequirePath).toURI());
|
||||
AssetAndUrlModuleSourceProvider provider = new AssetAndUrlModuleSourceProvider(getContext(), list);
|
||||
new RequireBuilder()
|
||||
.setModuleScriptProvider(new SoftCachingModuleScriptProvider(provider))
|
||||
.setSandboxed(true)
|
||||
.createRequire(context, scope)
|
||||
.install(scope);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getGlobalFunctions() {
|
||||
if (mFunctions == null)
|
||||
mFunctions = getGlobalFunctionsInner();
|
||||
return mFunctions;
|
||||
}
|
||||
|
||||
private String[] getGlobalFunctionsInner() {
|
||||
JavaScriptEngine engine = createEngine();
|
||||
Scriptable scriptable = (Scriptable) engine.execute(ScriptSource.of("this"));
|
||||
Object[] ids = scriptable.getIds();
|
||||
String[] functions = new String[ids.length];
|
||||
for (int i = 0; i < ids.length; i++) {
|
||||
functions[i] = ids[i].toString();
|
||||
}
|
||||
engine.stop();
|
||||
return functions;
|
||||
}
|
||||
|
||||
|
||||
private static class AssetAndUrlModuleSourceProvider extends UrlModuleSourceProvider {
|
||||
|
||||
private static final String MODULES_PATH = "modules";
|
||||
private android.content.Context mContext;
|
||||
private List<String> mModules;
|
||||
private final URI mBaseURI = URI.create("file:///android_asset/modules");
|
||||
|
||||
public AssetAndUrlModuleSourceProvider(android.content.Context context, List<URI> list) {
|
||||
super(list, null);
|
||||
mContext = context;
|
||||
try {
|
||||
mModules = Arrays.asList(mContext.getAssets().list(MODULES_PATH));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected ModuleSource loadFromPrivilegedLocations(String moduleId, Object validator) throws IOException, URISyntaxException {
|
||||
String moduleIdWithExtension = moduleId;
|
||||
if (!moduleIdWithExtension.endsWith(".js")) {
|
||||
moduleIdWithExtension += ".js";
|
||||
}
|
||||
if (mModules.contains(moduleIdWithExtension)) {
|
||||
return new ModuleSource(new InputStreamReader(mContext.getAssets().open(MODULES_PATH + "/" + moduleIdWithExtension)), null,
|
||||
URI.create(moduleIdWithExtension), mBaseURI, validator);
|
||||
}
|
||||
return super.loadFromPrivilegedLocations(moduleId, validator);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.stardust.autojs.engine;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.stardust.autojs.ScriptEngineService;
|
||||
import com.stardust.autojs.script.ScriptSource;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/2/5.
|
||||
*/
|
||||
|
||||
public class ScriptExecuteActivity extends Activity {
|
||||
|
||||
private static final String EXTRA_TASK = "EXTRA_TASK";
|
||||
private Object mResult;
|
||||
private JavaScriptEngine mJavaScriptEngine;
|
||||
private ScriptExecutionListener mExecutionListener;
|
||||
private ScriptSource mScriptSource;
|
||||
|
||||
|
||||
public static void execute(Context context, ScriptExecutionTask task) {
|
||||
context.startActivity(new Intent(context, ScriptExecuteActivity.class)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
.putExtra(EXTRA_TASK, task));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
handleIntent(getIntent());
|
||||
mJavaScriptEngine = ScriptEngineService.getInstance().createScriptEngine();
|
||||
runScript();
|
||||
}
|
||||
|
||||
private void handleIntent(Intent intent) {
|
||||
ScriptExecutionTask scriptExecutionTask = (ScriptExecutionTask) intent.getSerializableExtra(EXTRA_TASK);
|
||||
mExecutionListener = scriptExecutionTask.getExecutionListener();
|
||||
mScriptSource = scriptExecutionTask.getScriptSource();
|
||||
}
|
||||
|
||||
private void runScript() {
|
||||
mJavaScriptEngine.put("activity", this);
|
||||
try {
|
||||
mResult = mJavaScriptEngine.execute(mScriptSource);
|
||||
} catch (Exception e) {
|
||||
mExecutionListener.onException(mJavaScriptEngine, mScriptSource, e);
|
||||
super.finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
mExecutionListener.onSuccess(mJavaScriptEngine, mScriptSource, mResult);
|
||||
super.finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
mJavaScriptEngine.put("activity", null);
|
||||
mJavaScriptEngine.stop();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.stardust.autojs.engine;
|
||||
|
||||
import com.stardust.autojs.script.ScriptSource;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/4/2.
|
||||
*/
|
||||
|
||||
public interface ScriptExecutionListener extends Serializable {
|
||||
|
||||
void onStart(JavaScriptEngine engine, ScriptSource source);
|
||||
|
||||
void onSuccess(JavaScriptEngine engine, ScriptSource source, Object result);
|
||||
|
||||
void onException(JavaScriptEngine engine, ScriptSource source, Exception e);
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.stardust.autojs.engine;
|
||||
|
||||
import com.stardust.autojs.ExecutionConfig;
|
||||
import com.stardust.autojs.runtime.ScriptRuntime;
|
||||
import com.stardust.autojs.script.ScriptSource;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/4/2.
|
||||
*/
|
||||
|
||||
public class ScriptExecutionTask implements Serializable {
|
||||
|
||||
private ScriptSource mScriptSource;
|
||||
private ScriptExecutionListener mExecutionListener;
|
||||
private ExecutionConfig mExecutionConfig;
|
||||
|
||||
public ScriptExecutionTask(ScriptSource source, ScriptExecutionListener listener, ExecutionConfig config) {
|
||||
mScriptSource = source;
|
||||
mExecutionListener = listener;
|
||||
mExecutionConfig = config;
|
||||
}
|
||||
|
||||
public ScriptSource getScriptSource() {
|
||||
return mScriptSource;
|
||||
}
|
||||
|
||||
public ScriptExecutionListener getExecutionListener() {
|
||||
return mExecutionListener;
|
||||
}
|
||||
|
||||
public ExecutionConfig getExecutionConfig() {
|
||||
return mExecutionConfig;
|
||||
}
|
||||
|
||||
public void execute(ScriptRuntime runtime, JavaScriptEngine engine) {
|
||||
try {
|
||||
if ((mScriptSource.getExecutionMode() & ScriptSource.EXECUTION_MODE_AUTO) != 0) {
|
||||
runtime.ensureAccessibilityServiceEnabled();
|
||||
}
|
||||
mExecutionListener.onStart(engine, mScriptSource);
|
||||
mExecutionListener.onSuccess(engine, mScriptSource, engine.execute(mScriptSource));
|
||||
engine.stop();
|
||||
} catch (Exception e) {
|
||||
mExecutionListener.onException(engine, mScriptSource, e);
|
||||
}
|
||||
}
|
||||
|
||||
public ScriptExecutionListener getExecutionListenerOrDefault(ScriptExecutionListener defaultListener) {
|
||||
if (mExecutionListener == null)
|
||||
return defaultListener;
|
||||
return mExecutionListener;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.stardust.autojs.engine;
|
||||
|
||||
import com.stardust.autojs.script.ScriptSource;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/4/2.
|
||||
*/
|
||||
|
||||
public class SimpleScriptExecutionListener implements ScriptExecutionListener {
|
||||
@Override
|
||||
public void onStart(JavaScriptEngine engine, ScriptSource source) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(JavaScriptEngine engine, ScriptSource source, Object result) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onException(JavaScriptEngine engine, ScriptSource source, Exception e) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.stardust.autojs.runtime;
|
||||
|
||||
import com.stardust.autojs.runtime.action.ActionPerformAccessibilityDelegate;
|
||||
import com.stardust.automator.AccessibilityEventCommandHost;
|
||||
import com.stardust.view.accessibility.AccessibilityInfoProvider;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/4/2.
|
||||
*/
|
||||
|
||||
public interface AccessibilityBridge {
|
||||
|
||||
void ensureServiceEnabled();
|
||||
|
||||
AccessibilityInfoProvider getInfoProvider();
|
||||
|
||||
AccessibilityEventCommandHost getCommandHost();
|
||||
|
||||
ActionPerformAccessibilityDelegate getActionPerformHost();
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.stardust.autojs.runtime;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/4/2.
|
||||
*/
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@Target({ElementType.FIELD})
|
||||
public @interface JavascriptField {
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.stardust.autojs.runtime;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/4/2.
|
||||
*/
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@Target({ElementType.METHOD})
|
||||
public @interface JavascriptInterface {
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package com.stardust.autojs.runtime;
|
||||
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.stardust.autojs.runtime.action.ActionAutomator;
|
||||
import com.stardust.autojs.runtime.api.AppUtils;
|
||||
import com.stardust.autojs.runtime.api.Console;
|
||||
import com.stardust.autojs.runtime.api.UiSelector;
|
||||
import com.stardust.util.Shell;
|
||||
|
||||
;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/27.
|
||||
*/
|
||||
|
||||
public class ScriptRuntime {
|
||||
|
||||
private static final String TAG = "ScriptRuntime";
|
||||
|
||||
private Handler mUIHandler;
|
||||
private Context mContext;
|
||||
private AccessibilityBridge mAccessibilityBridge;
|
||||
|
||||
@JavascriptField
|
||||
public AppUtils app;
|
||||
|
||||
@JavascriptField
|
||||
public Console console;
|
||||
|
||||
@JavascriptField
|
||||
public ActionAutomator automator;
|
||||
|
||||
public ScriptRuntime(Context context, Console console, AccessibilityBridge accessibilityBridge) {
|
||||
mContext = context;
|
||||
mAccessibilityBridge = accessibilityBridge;
|
||||
mUIHandler = new Handler(mContext.getMainLooper());
|
||||
app = new AppUtils(context);
|
||||
this.console = console;
|
||||
automator = new ActionAutomator(accessibilityBridge, this);
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
public void toast(final String text) {
|
||||
mUIHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(mContext, text, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
public void sleep(long millis) {
|
||||
try {
|
||||
Thread.sleep(millis);
|
||||
} catch (InterruptedException e) {
|
||||
throw new ScriptStopException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
public void setClip(final String text) {
|
||||
mUIHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
((ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE)).setPrimaryClip(ClipData.newPlainText(TAG, text));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
public Shell.CommandResult shell(String cmd, int root) {
|
||||
return Shell.execCommand(cmd, root != 0);
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
public UiSelector selector() {
|
||||
return new UiSelector(mAccessibilityBridge);
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
public boolean isStopped() {
|
||||
return Thread.currentThread().isInterrupted();
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
public void stop() {
|
||||
Thread.interrupted();
|
||||
}
|
||||
|
||||
public void stoppedByInterrupted(InterruptedException e) {
|
||||
throw new ScriptStopException(e);
|
||||
}
|
||||
|
||||
public void ensureAccessibilityServiceEnabled() {
|
||||
mAccessibilityBridge.ensureServiceEnabled();
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package autojs.runtime;
|
||||
package com.stardust.autojs.runtime;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/29.
|
||||
@@ -1,4 +1,4 @@
|
||||
package autojs.runtime.action;
|
||||
package com.stardust.autojs.runtime.action;
|
||||
|
||||
import android.util.SparseArray;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.stardust.autojs.runtime.action;
|
||||
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/27.
|
||||
*/
|
||||
|
||||
public abstract class Action {
|
||||
|
||||
private boolean mValid = true;
|
||||
private Object mResult = false;
|
||||
|
||||
public abstract boolean perform(AccessibilityNodeInfo root);
|
||||
|
||||
public Object getResult() {
|
||||
return mResult;
|
||||
}
|
||||
|
||||
public void setResult(Object result) {
|
||||
mResult = result;
|
||||
}
|
||||
|
||||
public void setValid(boolean valid) {
|
||||
mValid = valid;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return mValid;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
package com.stardust.autojs.runtime.action;
|
||||
|
||||
import android.accessibilityservice.AccessibilityService;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.autojs.runtime.AccessibilityBridge;
|
||||
import com.stardust.autojs.runtime.ScriptRuntime;
|
||||
import com.stardust.autojs.runtime.ScriptStopException;
|
||||
import com.stardust.automator.AccessibilityEventCommandHost;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/4/2.
|
||||
*/
|
||||
|
||||
public class ActionAutomator {
|
||||
|
||||
private static class PerformGlobalActionCommand implements AccessibilityEventCommandHost.Command {
|
||||
|
||||
boolean result;
|
||||
private int mGlobalAction;
|
||||
|
||||
PerformGlobalActionCommand(int globalAction) {
|
||||
mGlobalAction = globalAction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(AccessibilityService service, AccessibilityEvent event) {
|
||||
result = service.performGlobalAction(mGlobalAction);
|
||||
}
|
||||
}
|
||||
|
||||
private AccessibilityBridge mAccessibilityBridge;
|
||||
private ScriptRuntime mScriptRuntime;
|
||||
|
||||
public ActionAutomator(AccessibilityBridge accessibilityBridge, ScriptRuntime scriptRuntime) {
|
||||
mAccessibilityBridge = accessibilityBridge;
|
||||
mScriptRuntime = scriptRuntime;
|
||||
}
|
||||
|
||||
public ActionTarget text(String text, int i) {
|
||||
return new ActionTarget.TextActionTarget(text, i);
|
||||
}
|
||||
|
||||
public ActionTarget bounds(int left, int top, int right, int bottom) {
|
||||
return new ActionTarget.BoundsActionTarget(new Rect(left, top, right, bottom));
|
||||
}
|
||||
|
||||
public ActionTarget editable(int i) {
|
||||
return new ActionTarget.EditableActionTarget(i);
|
||||
}
|
||||
|
||||
public ActionTarget id(String id) {
|
||||
return new ActionTarget.IdActionTarget(id);
|
||||
}
|
||||
|
||||
public boolean click(ActionTarget target) {
|
||||
return performAction(target.createAction(AccessibilityNodeInfo.ACTION_CLICK));
|
||||
}
|
||||
|
||||
public boolean longClick(ActionTarget target) {
|
||||
return performAction(target.createAction(AccessibilityNodeInfo.ACTION_LONG_CLICK));
|
||||
}
|
||||
|
||||
public boolean scrollUp(ActionTarget target) {
|
||||
return performAction(target.createAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD));
|
||||
}
|
||||
|
||||
public boolean scrollDown(ActionTarget target) {
|
||||
return performAction(target.createAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD));
|
||||
}
|
||||
|
||||
public boolean scrollUp(int i) {
|
||||
return performAction(ActionFactory.createScrollAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD, i));
|
||||
}
|
||||
|
||||
public boolean scrollDown(int i) {
|
||||
return performAction(ActionFactory.createScrollAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD, i));
|
||||
}
|
||||
|
||||
public boolean scrollAllUp() {
|
||||
return performAction(ActionFactory.createScrollMaxAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD));
|
||||
}
|
||||
|
||||
public boolean scrollAllDown() {
|
||||
return performAction(ActionFactory.createScrollMaxAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD));
|
||||
}
|
||||
|
||||
public boolean focus(ActionTarget target) {
|
||||
return performAction(target.createAction(AccessibilityNodeInfo.ACTION_FOCUS));
|
||||
}
|
||||
|
||||
public boolean select(ActionTarget target) {
|
||||
return performAction(target.createAction(AccessibilityNodeInfo.ACTION_SELECT));
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
public boolean setText(ActionTarget target, String text) {
|
||||
ensureApi(Build.VERSION_CODES.LOLLIPOP);
|
||||
return performAction(target.createAction(AccessibilityNodeInfo.ACTION_SET_TEXT, text));
|
||||
}
|
||||
|
||||
public boolean back() {
|
||||
return performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK);
|
||||
}
|
||||
|
||||
public boolean home() {
|
||||
return performGlobalAction(AccessibilityService.GLOBAL_ACTION_HOME);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
public boolean powerDialog() {
|
||||
ensureApi(Build.VERSION_CODES.LOLLIPOP);
|
||||
return performGlobalAction(AccessibilityService.GLOBAL_ACTION_POWER_DIALOG);
|
||||
}
|
||||
|
||||
private void ensureApi(int i) {
|
||||
if (Build.VERSION.SDK_INT < i) {
|
||||
throw new ScriptStopException();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean notifications() {
|
||||
return performGlobalAction(AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS);
|
||||
}
|
||||
|
||||
public boolean quickSettings() {
|
||||
return performGlobalAction(AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS);
|
||||
}
|
||||
|
||||
public boolean recents() {
|
||||
return performGlobalAction(AccessibilityService.GLOBAL_ACTION_RECENTS);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.N)
|
||||
public boolean splitScreen() {
|
||||
return performGlobalAction(AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN);
|
||||
}
|
||||
|
||||
public boolean swipeDown() {
|
||||
return performGlobalAction(AccessibilityService.GESTURE_SWIPE_DOWN);
|
||||
}
|
||||
|
||||
public boolean swipeDownLeft() {
|
||||
return performGlobalAction(AccessibilityService.GESTURE_SWIPE_DOWN_AND_LEFT);
|
||||
}
|
||||
|
||||
public boolean swipeDownRight() {
|
||||
return performGlobalAction(AccessibilityService.GESTURE_SWIPE_DOWN_AND_RIGHT);
|
||||
}
|
||||
|
||||
public boolean swipeDownUp() {
|
||||
return performGlobalAction(AccessibilityService.GESTURE_SWIPE_DOWN_AND_UP);
|
||||
}
|
||||
|
||||
public boolean swipeUp() {
|
||||
return performGlobalAction(AccessibilityService.GESTURE_SWIPE_UP);
|
||||
}
|
||||
|
||||
public boolean swipeUpLeft() {
|
||||
return performGlobalAction(AccessibilityService.GESTURE_SWIPE_UP_AND_LEFT);
|
||||
}
|
||||
|
||||
public boolean swipeUpRight() {
|
||||
return performGlobalAction(AccessibilityService.GESTURE_SWIPE_UP_AND_RIGHT);
|
||||
}
|
||||
|
||||
public boolean swipeUpDown() {
|
||||
return performGlobalAction(AccessibilityService.GESTURE_SWIPE_UP_AND_DOWN);
|
||||
}
|
||||
|
||||
public boolean swipeLeft() {
|
||||
return performGlobalAction(AccessibilityService.GESTURE_SWIPE_LEFT);
|
||||
}
|
||||
|
||||
public boolean swipeLeftRight() {
|
||||
return performGlobalAction(AccessibilityService.GESTURE_SWIPE_LEFT_AND_RIGHT);
|
||||
}
|
||||
|
||||
public boolean swipeLeftUp() {
|
||||
return performGlobalAction(AccessibilityService.GESTURE_SWIPE_LEFT_AND_UP);
|
||||
}
|
||||
|
||||
public boolean swipeLeftDown() {
|
||||
return performGlobalAction(AccessibilityService.GESTURE_SWIPE_LEFT_AND_DOWN);
|
||||
}
|
||||
|
||||
public boolean swipeRight() {
|
||||
return performGlobalAction(AccessibilityService.GESTURE_SWIPE_RIGHT);
|
||||
}
|
||||
|
||||
public boolean swipeRightLeft() {
|
||||
return performGlobalAction(AccessibilityService.GESTURE_SWIPE_RIGHT_AND_LEFT);
|
||||
}
|
||||
|
||||
public boolean swipeRightUp() {
|
||||
return performGlobalAction(AccessibilityService.GESTURE_SWIPE_RIGHT_AND_UP);
|
||||
}
|
||||
|
||||
public boolean swipeRightDown() {
|
||||
return performGlobalAction(AccessibilityService.GESTURE_SWIPE_RIGHT_AND_DOWN);
|
||||
}
|
||||
|
||||
private boolean performGlobalAction(final int action) {
|
||||
ensureAccessibilityServiceEnabled();
|
||||
PerformGlobalActionCommand command = new PerformGlobalActionCommand(action);
|
||||
mAccessibilityBridge.getCommandHost().executeAndWaitForEvent(command);
|
||||
return command.result;
|
||||
}
|
||||
|
||||
public boolean paste(ActionTarget target) {
|
||||
return performAction(target.createAction(AccessibilityNodeInfo.ACTION_PASTE));
|
||||
}
|
||||
|
||||
|
||||
public String currentPackage() {
|
||||
ensureAccessibilityServiceEnabled();
|
||||
return mAccessibilityBridge.getInfoProvider().getLatestPackage();
|
||||
}
|
||||
|
||||
private void ensureAccessibilityServiceEnabled() {
|
||||
mAccessibilityBridge.ensureServiceEnabled();
|
||||
}
|
||||
|
||||
public String currentActivity() {
|
||||
ensureAccessibilityServiceEnabled();
|
||||
return mAccessibilityBridge.getInfoProvider().getLatestActivity();
|
||||
}
|
||||
|
||||
private <T> T performAction(Action action) {
|
||||
ensureAccessibilityServiceEnabled();
|
||||
mAccessibilityBridge.getActionPerformHost().addAction(action);
|
||||
synchronized (action) {
|
||||
try {
|
||||
action.wait();
|
||||
} catch (InterruptedException e) {
|
||||
action.setValid(false);
|
||||
mScriptRuntime.stoppedByInterrupted(e);
|
||||
}
|
||||
}
|
||||
return (T) action.getResult();
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package autojs.runtime.action;
|
||||
package com.stardust.autojs.runtime.action;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.os.Bundle;
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.stardust.autojs.runtime.action;
|
||||
|
||||
import android.accessibilityservice.AccessibilityService;
|
||||
import android.util.Log;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.view.accessibility.AccessibilityDelegate;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/21.
|
||||
*/
|
||||
|
||||
public class ActionPerformAccessibilityDelegate implements AccessibilityDelegate {
|
||||
|
||||
private static final String TAG = "ActionPerformDelegate";
|
||||
|
||||
private final Queue<Action> mActions = new LinkedList<>();
|
||||
private Action mCurrentAction;
|
||||
|
||||
public void addAction(Action action) {
|
||||
synchronized (mActions) {
|
||||
mActions.offer(action);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onAccessibilityEvent(AccessibilityService service, AccessibilityEvent event) {
|
||||
synchronized (mActions) {
|
||||
mCurrentAction = getCurrentAction();
|
||||
if (mCurrentAction == null)
|
||||
return false;
|
||||
AccessibilityNodeInfo root = service.getRootInActiveWindow();
|
||||
if (root == null) {
|
||||
return false;
|
||||
}
|
||||
performAction(root, mCurrentAction);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private Action getCurrentAction() {
|
||||
if (isCurrentActionValid()) {
|
||||
return mCurrentAction;
|
||||
}
|
||||
if (mActions.isEmpty())
|
||||
return null;
|
||||
return mActions.poll();
|
||||
}
|
||||
|
||||
private boolean isCurrentActionValid() {
|
||||
return mCurrentAction != null && mCurrentAction.isValid();
|
||||
}
|
||||
|
||||
private void performAction(final AccessibilityNodeInfo root, final Action action) {
|
||||
Log.i(TAG, "perform action:" + action);
|
||||
if (action.perform(root)) {
|
||||
action.setResult(true);
|
||||
onActionPerformed(action);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void onActionPerformed(Action action) {
|
||||
mCurrentAction = null;
|
||||
synchronized (action) {
|
||||
action.notify();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package autojs.runtime.action;
|
||||
package com.stardust.autojs.runtime.action;
|
||||
|
||||
import android.graphics.Rect;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package autojs.runtime.action;
|
||||
package com.stardust.autojs.runtime.action;
|
||||
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package autojs.runtime.action;
|
||||
package com.stardust.autojs.runtime.action;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
@@ -1,4 +1,4 @@
|
||||
package autojs.runtime.action;
|
||||
package com.stardust.autojs.runtime.action;
|
||||
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package autojs.runtime.action;
|
||||
package com.stardust.autojs.runtime.action;
|
||||
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package autojs.runtime.action;
|
||||
package com.stardust.autojs.runtime.action;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.util.Log;
|
||||
@@ -1,4 +1,4 @@
|
||||
package autojs.runtime.action;
|
||||
package com.stardust.autojs.runtime.action;
|
||||
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package autojs.runtime.action;
|
||||
package com.stardust.autojs.runtime.action;
|
||||
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.stardust.autojs.runtime.api;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
|
||||
import com.stardust.util.IntentUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/4/2.
|
||||
*/
|
||||
|
||||
public class AppUtils {
|
||||
|
||||
private Context mContext;
|
||||
|
||||
public AppUtils(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
|
||||
public boolean launchPackage(String packageName) {
|
||||
try {
|
||||
PackageManager packageManager = mContext.getPackageManager();
|
||||
mContext.startActivity(packageManager.getLaunchIntentForPackage(packageName));
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public boolean launchApp(String appName) {
|
||||
return launchPackage(getPackageName(appName));
|
||||
}
|
||||
|
||||
public String getPackageName(String appName) {
|
||||
PackageManager packageManager = mContext.getPackageManager();
|
||||
List<ApplicationInfo> installedApplications = packageManager.getInstalledApplications(PackageManager.GET_META_DATA);
|
||||
for (ApplicationInfo applicationInfo : installedApplications) {
|
||||
if (packageManager.getApplicationLabel(applicationInfo).toString().equals(appName)) {
|
||||
return applicationInfo.processName;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public boolean openAppSetting(String packageName) {
|
||||
return IntentUtil.goToAppDetailSettings(mContext, packageName);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.stardust.autojs.runtime.api;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/4/2.
|
||||
*/
|
||||
|
||||
public interface Console {
|
||||
|
||||
void i(@Nullable Object o);
|
||||
|
||||
void i(String str);
|
||||
|
||||
void e(String message);
|
||||
|
||||
void e(@Nullable Object o);
|
||||
|
||||
void v(String v);
|
||||
|
||||
void v(@Nullable Object o);
|
||||
|
||||
void log(@Nullable Object o);
|
||||
|
||||
void log(String string);
|
||||
|
||||
void show();
|
||||
|
||||
void clear();
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package autojs.runtime.api;
|
||||
package com.stardust.autojs.runtime.api;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.util.Log;
|
||||
@@ -9,7 +9,8 @@ import android.webkit.WebSettings;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
|
||||
import com.stardust.scriptdroid.droid.runtime.ScriptStopException;
|
||||
|
||||
import com.stardust.autojs.runtime.ScriptStopException;
|
||||
|
||||
import org.mozilla.javascript.Context;
|
||||
import org.mozilla.javascript.Scriptable;
|
||||
@@ -1,4 +1,4 @@
|
||||
package autojs.runtime.api;
|
||||
package com.stardust.autojs.runtime.api;
|
||||
|
||||
import android.content.Context;
|
||||
import android.webkit.ValueCallback;
|
||||
@@ -1,10 +1,10 @@
|
||||
package autojs.runtime.api;
|
||||
package com.stardust.autojs.runtime.api;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/7.
|
||||
*/
|
||||
|
||||
public class Shell extends com.stardust.scriptdroid.tool.Shell {
|
||||
public class Shell extends com.stardust.util.Shell {
|
||||
|
||||
public Shell(boolean root) {
|
||||
super(root);
|
||||
@@ -1,18 +1,17 @@
|
||||
package autojs.runtime.api;
|
||||
package com.stardust.autojs.runtime.api;
|
||||
|
||||
import android.accessibilityservice.AccessibilityService;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.autojs.runtime.AccessibilityBridge;
|
||||
import com.stardust.automator.AccessibilityEventCommandHost;
|
||||
import com.stardust.automator.ActionArgument;
|
||||
import com.stardust.automator.UiGlobalSelector;
|
||||
import com.stardust.automator.UiObject;
|
||||
import com.stardust.automator.UiObjectCollection;
|
||||
import com.stardust.automator.filter.DfsFilter;
|
||||
import com.stardust.scriptdroid.accessibility.AccessibilityInfoProvider;
|
||||
import com.stardust.scriptdroid.droid.runtime.DroidRuntime;
|
||||
|
||||
import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS;
|
||||
import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_COLUMN_INT;
|
||||
@@ -67,15 +66,22 @@ public class UiSelector extends UiGlobalSelector {
|
||||
|
||||
private static final String TAG = "UiSelector";
|
||||
|
||||
private AccessibilityBridge mAccessibilityBridge;
|
||||
|
||||
public UiSelector(AccessibilityBridge accessibilityBridge) {
|
||||
mAccessibilityBridge = accessibilityBridge;
|
||||
}
|
||||
|
||||
|
||||
public UiObjectCollection find() {
|
||||
ensureAccessibilityServiceEnabled();
|
||||
FindCommand command = new FindCommand();
|
||||
AccessibilityEventCommandHost.getInstance().executeAndWaitForEvent(command);
|
||||
mAccessibilityBridge.getCommandHost().executeAndWaitForEvent(command);
|
||||
return command.result;
|
||||
}
|
||||
|
||||
private void ensureAccessibilityServiceEnabled(){
|
||||
DroidRuntime.getRuntime().ensureAccessibilityServiceEnabled();
|
||||
private void ensureAccessibilityServiceEnabled() {
|
||||
mAccessibilityBridge.ensureServiceEnabled();
|
||||
}
|
||||
|
||||
|
||||
@@ -103,7 +109,7 @@ public class UiSelector extends UiGlobalSelector {
|
||||
addFilter(new DfsFilter() {
|
||||
@Override
|
||||
protected boolean isIncluded(AccessibilityNodeInfo nodeInfo) {
|
||||
String fullId = AccessibilityInfoProvider.getInstance().getLatestPackage() + ":id/" + id;
|
||||
String fullId = mAccessibilityBridge.getInfoProvider().getLatestPackage() + ":id/" + id;
|
||||
return fullId.equals(nodeInfo.getViewIdResourceName());
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.stardust.autojs.script;
|
||||
|
||||
import com.stardust.autojs.script.ScriptSource;
|
||||
import com.stardust.pio.PFile;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/4/2.
|
||||
*/
|
||||
|
||||
public class FileScriptSource extends ScriptSource {
|
||||
|
||||
private File mFile;
|
||||
private String mScript;
|
||||
|
||||
public FileScriptSource(File file) {
|
||||
mFile = file;
|
||||
}
|
||||
|
||||
public FileScriptSource(String path) {
|
||||
this(new File(path));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getScript() {
|
||||
if (mScript == null)
|
||||
mScript = PFile.read(mFile);
|
||||
return mScript;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return mFile.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.stardust.autojs.script;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/4/2.
|
||||
*/
|
||||
|
||||
public class MultiScriptSource extends ScriptSource {
|
||||
|
||||
private String mScript;
|
||||
|
||||
public MultiScriptSource(ScriptSource... sources) {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
for (ScriptSource source : sources) {
|
||||
String script = source.getScript();
|
||||
if (script != null)
|
||||
stringBuilder.append(script).append("\n");
|
||||
}
|
||||
mScript = stringBuilder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getScript() {
|
||||
return mScript;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.stardust.autojs.script;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import com.stardust.util.MapEntries;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/4/2.
|
||||
*/
|
||||
|
||||
public abstract class ScriptSource implements Serializable {
|
||||
|
||||
public static final int EXECUTION_MODE_NORMAL = 0;
|
||||
public static final int EXECUTION_MODE_UI = 0x00000001;
|
||||
public static final int EXECUTION_MODE_AUTO = 0x00000002;
|
||||
|
||||
private static final Map<String, Integer> EXECUTION_MODES = new MapEntries<String, Integer>()
|
||||
.entry("ui", EXECUTION_MODE_UI)
|
||||
.entry("auto", EXECUTION_MODE_AUTO)
|
||||
.map();
|
||||
private static final int EXECUTION_MODE_STRING_MAX_LENGTH = 7;
|
||||
|
||||
private int mExecutionMode = -1;
|
||||
|
||||
|
||||
public abstract String getScript();
|
||||
|
||||
public int getExecutionMode() {
|
||||
if (mExecutionMode == -1) {
|
||||
mExecutionMode = parseExecutionMode(getScript());
|
||||
}
|
||||
return mExecutionMode;
|
||||
}
|
||||
|
||||
private int parseExecutionMode(String script) {
|
||||
if (script.charAt(0) != '"')
|
||||
return EXECUTION_MODE_NORMAL;
|
||||
int i = script.lastIndexOf("\";", EXECUTION_MODE_STRING_MAX_LENGTH + 2);
|
||||
if (i == -1)
|
||||
return EXECUTION_MODE_NORMAL;
|
||||
String modeString = script.substring(1, i);
|
||||
return parseExecutionMode(modeString.split(" "));
|
||||
}
|
||||
|
||||
private int parseExecutionMode(String[] modeStrings) {
|
||||
int mode = 0;
|
||||
for (String modeString : modeStrings) {
|
||||
Integer i = EXECUTION_MODES.get(modeString);
|
||||
if (i != null) {
|
||||
mode |= i;
|
||||
}
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
public static ScriptSource of(String script) {
|
||||
return new StringScriptSource(script);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.stardust.autojs.script;
|
||||
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/4/2.
|
||||
*/
|
||||
|
||||
public class StringScriptSource extends ScriptSource {
|
||||
|
||||
private String mScript;
|
||||
|
||||
public StringScriptSource(String script) {
|
||||
mScript = script;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getScript() {
|
||||
return mScript;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,11 @@
|
||||
<resources>
|
||||
<string name="app_name">autojs</string>
|
||||
<string name="text_error">错误:</string>
|
||||
<string name="text_start_running">开始运行</string>
|
||||
<string name="text_path_is_empty">路径为空</string>
|
||||
<string name="text_file_not_exists">文件不存在</string>
|
||||
<string name="text_no_file_rw_permission">无文件读写权限</string>
|
||||
<string name="text_no_running_script">没有正在运行的脚本</string>
|
||||
<string name="text_already_stop_n_scripts">已停止%d个正在运行的脚本</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.example.autojs;
|
||||
package com.stardust.autojs;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
Reference in New Issue
Block a user