fix: RootAutomatorEngine.forceStop not working

This commit is contained in:
hyb1996
2017-08-14 20:10:33 +08:00
parent 7b4629aa1d
commit 8034dc7b6b
17 changed files with 125 additions and 51 deletions

View File

@@ -9,8 +9,8 @@ android {
applicationId "com.stardust.scriptdroid" applicationId "com.stardust.scriptdroid"
minSdkVersion 17 minSdkVersion 17
targetSdkVersion 23 targetSdkVersion 23
versionCode 159 versionCode 160
versionName "2.0.16 Beta" versionName "2.0.16 Alpha3"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
multiDexEnabled true multiDexEnabled true
ndk { ndk {

View File

@@ -69,6 +69,11 @@
"type": "markdown", "type": "markdown",
"path":"documentation" "path":"documentation"
}, },
{
"title": "需要Root权限的触摸与多点触摸",
"type": "markdown",
"path":"documentation"
},
{ {
"title": "UI(用户界面)", "title": "UI(用户界面)",
"type": "markdown", "type": "markdown",

View File

@@ -41,6 +41,8 @@ engines模块包含了一些与脚本引擎有关的函数包括运行其他
停止所有正在运行的脚本并显示停止的脚本数量。包括当前脚本自身。 停止所有正在运行的脚本并显示停止的脚本数量。包括当前脚本自身。
### engines.myEngine()
# ScriptExecution # ScriptExecution
执行脚本时返回的对象,可以通过他获取执行的引擎、 执行脚本时返回的对象,可以通过他获取执行的引擎、

View File

@@ -1,9 +1,13 @@
注意本章节的函数在后续版本很可能有改动请勿过分依赖本章节函数的副作用。推荐使用RootAutomator见《需要Root权限的触摸与多点触摸》代替本章的触摸函数。
以下函数均需要root权限可以实现任意位置的点击、滑动、长按、模拟物理按键等。 以下函数均需要root权限可以实现任意位置的点击、滑动、长按、模拟物理按键等。
这些函数通常首字母大写以表示其特殊的权限。 这些函数通常首字母大写以表示其特殊的权限。
这些函数均不返回任何值。 这些函数均不返回任何值。
并且这些函数的执行是异步的、非实时的在不同机型上所用的时间不同。脚本不会等待动作执行完成才继续执行。因此最好在每个函数之后加上适当的sleep来达到期望的效果。 并且这些函数的执行是异步的、非实时的在不同机型上所用的时间不同。脚本不会等待动作执行完成才继续执行。因此最好在每个函数之后加上适当的sleep来达到期望的效果。
例如: 例如:
``` ```
Tap(100, 100); Tap(100, 100);

View File

@@ -10,7 +10,7 @@ var ra = RootAutomator(context);
### RootAutomator.tap(x, y\[, id\]) ### RootAutomator.tap(x, y\[, id\])
* x \<Number\> 横坐标 * x \<Number\> 横坐标
* y \<Number\> 纵坐标 * y \<Number\> 纵坐标
* id \<Number\> 多点触摸id默认为1可以通过setDefaultId指定。 * id \<Number\> 多点触摸id,可选,默认为1可以通过setDefaultId指定。
点击位置(x, y)。其中id是一个整数值用于区分多点触摸不同的id表示不同的"手指",例如: 点击位置(x, y)。其中id是一个整数值用于区分多点触摸不同的id表示不同的"手指",例如:
``` ```
@@ -29,7 +29,7 @@ ra.exit();
* x2 \<Number\> 滑动终点横坐标 * x2 \<Number\> 滑动终点横坐标
* y2 \<Number\> 滑动终点纵坐标 * y2 \<Number\> 滑动终点纵坐标
* duration \<Number\> 滑动时长单位毫秒默认值为300 * duration \<Number\> 滑动时长单位毫秒默认值为300
* id \<Number\> 多点触摸id * id \<Number\> 多点触摸id可选默认为1
模拟一次从(x1, y1)到(x2, y2)的时间为duration毫秒的滑动。 模拟一次从(x1, y1)到(x2, y2)的时间为duration毫秒的滑动。
@@ -37,28 +37,36 @@ ra.exit();
* x \<Number\> 横坐标 * x \<Number\> 横坐标
* y \<Number\> 纵坐标 * y \<Number\> 纵坐标
* duration \<Number\> 按下时长 * duration \<Number\> 按下时长
* id \<Number\> 多点触摸id * id \<Number\> 多点触摸id可选默认为1
模拟按下位置(x, y)时长为duration毫秒。 模拟按下位置(x, y)时长为duration毫秒。
### RootAutomator.longPress(x, y[\, id\])
* x \<Number\> 横坐标
* y \<Number\> 纵坐标
* duration \<Number\> 按下时长
* id \<Number\> 多点触摸id可选默认为1
模拟长按位置(x, y)。
以上为简单模拟触摸操作的函数。如果要模拟一些复杂的手势,需要更底层的函数。 以上为简单模拟触摸操作的函数。如果要模拟一些复杂的手势,需要更底层的函数。
### RootAutomator.touchDown(x, y[\, id\]) ### RootAutomator.touchDown(x, y[\, id\])
* x \<Number\> 横坐标 * x \<Number\> 横坐标
* y \<Number\> 纵坐标 * y \<Number\> 纵坐标
* id \<Number\> 多点触摸id * id \<Number\> 多点触摸id可选默认为1
模拟手指按下位置(x, y)。 模拟手指按下位置(x, y)。
### RootAutomator.touchMove(x, y[\, id\]) ### RootAutomator.touchMove(x, y[\, id\])
* x \<Number\> 横坐标 * x \<Number\> 横坐标
* y \<Number\> 纵坐标 * y \<Number\> 纵坐标
* id \<Number\> 多点触摸id * id \<Number\> 多点触摸id可选默认为1
模拟移动手指到位置(x, y)。 模拟移动手指到位置(x, y)。
### RootAutomator.touchUp([\id\]) ### RootAutomator.touchUp(\[id\])
* id \<Number\> 多点触摸id * id \<Number\> 多点触摸id可选默认为1
模拟手指弹起。 模拟手指弹起。

View File

@@ -1,27 +1,28 @@
"auto"; var ra = new RootAutomator();
ra.setScreenMetrics(1080, 1920);
setScreenMetrics(1080, 1920);
launchApp("QQ"); launchApp("QQ");
sleep(1500); sleep(1500);
//点击动态图标 //点击动态图标
Tap(891, 1851); ra.tap(891, 1851);
//点击好友动态 //点击好友动态
Tap(192, 453); ra.tap(192, 453);
//点击头像 //点击头像
Tap(155, 638); ra.tap(155, 638);
//点击留言 //点击留言
Tap(747, 775); ra.tap(747, 775);
while(true){ while(true){
if(currentPackage() == 'com.tencent.mobileqq'){ if(currentPackage() == 'com.tencent.mobileqq'){
//点击箭头图标 //点击箭头图标
Tap(1029, 433); ra.tap(1029, 433);
//点击删除 //点击删除
Tap(530, 820); ra.tap(530, 820);
//点击确定 //点击确定
Tap(331, 1122); ra.tap(331, 1122);
} }
sleep(200); sleep(200);
} }

View File

@@ -2,7 +2,7 @@ module.exports = function(__runtime__, scope){
function RootAutomator(){ function RootAutomator(){
this.__ra__ = Object.create(new com.stardust.autojs.runtime.api.RootAutomator(scope.context)); this.__ra__ = Object.create(new com.stardust.autojs.runtime.api.RootAutomator(scope.context));
var methods = ["sendEvent", "touch", "setScreenMetrics", "touchX", "touchY", "sendSync", "sendMtSync", "tap", var methods = ["sendEvent", "touch", "setScreenMetrics", "touchX", "touchY", "sendSync", "sendMtSync", "tap",
"swipe","touchDown", "touchUp", "touchMove", "getDefaultId", "setDefaultId", "exit"]; "swipe", "press", "longPress", "touchDown", "touchUp", "touchMove", "getDefaultId", "setDefaultId", "exit"];
for(var i = 0; i < methods.length; i++){ for(var i = 0; i < methods.length; i++){
var method = methods[i]; var method = methods[i];
this[method] = this.__ra__[method].bind(this.__ra__); this[method] = this.__ra__[method].bind(this.__ra__);

View File

@@ -5,18 +5,19 @@ module.exports = function(__runtime__, scope){
var engines = {}; var engines = {};
engines.execScript = function(name, script, config){ engines.execScript = function(name, script, config){
config = fillConfig(config); return rtEngines.execScript(name, script, fillConfig(config));
return rtEngines.execScript(name, script, config);
} }
engines.execScriptFile = function(path, config){ engines.execScriptFile = function(path, config){
config = fillConfig(config); return rtEngines.execScriptFile(path, fillConfig(config));
return rtEngines.execScriptFile(path, config);
} }
engines.execAutoFile = function(path, config){ engines.execAutoFile = function(path, config){
config = fillConfig(config); return rtEngines.execAutoFile(path, fillConfig(config));
return rtEngines.execAutoFile(path, config); }
engines.myEngine = function(){
return scope.__engine__;
} }
engines.stopAll = rtEngines.stopAll.bind(rtEngines); engines.stopAll = rtEngines.stopAll.bind(rtEngines);

View File

@@ -45,17 +45,17 @@ module.exports = function(__runtime__, scope){
return __runtime__.info.getLatestActivity(); return __runtime__.info.getLatestActivity();
} }
scope.waitForActivity = function(activity, delay){ scope.waitForActivity = function(activity, period){
delay = delay || 200; period = period || 200;
while(scope.currentActivity() != activity){ while(scope.currentActivity() != activity){
sleep(delay); sleep(period);
} }
} }
scope.waitForPackage = function(packageName, delay){ scope.waitForPackage = function(packageName, period){
delay = delay || 200; period = period || 200;
while(scope.currentPackage() != packageName){ while(scope.currentPackage() != packageName){
sleep(delay); sleep(period);
} }
} }

View File

@@ -245,6 +245,7 @@ public class SimpleActionAutomator {
mAccessibilityBridge.ensureServiceEnabled(); mAccessibilityBridge.ensureServiceEnabled();
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private boolean performAction(SimpleAction simpleAction) { private boolean performAction(SimpleAction simpleAction) {
ensureAccessibilityServiceEnabled(); ensureAccessibilityServiceEnabled();

View File

@@ -28,6 +28,9 @@ public abstract class JavaScriptEngine extends ScriptEngine.AbstractScriptEngine
} }
public void setRuntime(ScriptRuntime runtime) { public void setRuntime(ScriptRuntime runtime) {
if (mRuntime != null) {
throw new IllegalStateException("a runtime has been set");
}
mRuntime = runtime; mRuntime = runtime;
put("__runtime__", runtime); put("__runtime__", runtime);
} }

View File

@@ -7,7 +7,10 @@ import android.util.Log;
import com.stardust.autojs.runtime.api.AbstractShell; import com.stardust.autojs.runtime.api.AbstractShell;
import com.stardust.autojs.runtime.api.ProcessShell; import com.stardust.autojs.runtime.api.ProcessShell;
import com.stardust.autojs.core.inputevent.InputDevices; import com.stardust.autojs.core.inputevent.InputDevices;
import com.stardust.autojs.runtime.api.Shell;
import com.stardust.autojs.runtime.exception.ScriptInterruptedException;
import com.stardust.autojs.script.AutoFileSource; import com.stardust.autojs.script.AutoFileSource;
import com.stardust.concurrent.VolatileBox;
import com.stardust.pio.PFile; import com.stardust.pio.PFile;
import java.io.File; import java.io.File;
@@ -34,7 +37,6 @@ public class RootAutomatorEngine extends ScriptEngine.AbstractScriptEngine<AutoF
public RootAutomatorEngine(Context context, String deviceNameOrPath) { public RootAutomatorEngine(Context context, String deviceNameOrPath) {
mContext = context; mContext = context;
mDeviceNameOrPath = getDeviceNameOrPath(context, deviceNameOrPath); mDeviceNameOrPath = getDeviceNameOrPath(context, deviceNameOrPath);
} }
@@ -42,14 +44,14 @@ public class RootAutomatorEngine extends ScriptEngine.AbstractScriptEngine<AutoF
this(context, InputDevices.getTouchDeviceName()); this(context, InputDevices.getTouchDeviceName());
} }
public AbstractShell.Result execute(String autoFile) { public void execute(String autoFile) {
mExecutablePath = getExecutablePath(mContext); mExecutablePath = getExecutablePath(mContext);
AbstractShell.Result r = ProcessShell.execCommand(new String[]{ Log.d(LOG_TAG, "exec: " + autoFile);
AbstractShell.Result result = ProcessShell.execCommand(new String[]{
"chmod 777 " + mExecutablePath, "chmod 777 " + mExecutablePath,
mExecutablePath + " \"" + autoFile + "\" -d " + mDeviceNameOrPath mExecutablePath + " \"" + autoFile + "\" -d " + mDeviceNameOrPath
}, true); }, true);
Log.d(LOG_TAG, "exec: " + autoFile + " result:" + r); Log.d(LOG_TAG, "result = " + result);
return r;
} }
@@ -90,17 +92,24 @@ public class RootAutomatorEngine extends ScriptEngine.AbstractScriptEngine<AutoF
@Override @Override
public Object execute(AutoFileSource source) { public Object execute(AutoFileSource source) {
return execute(source.getFile().getAbsolutePath()); execute(source.getFile().getAbsolutePath());
return null;
} }
@Override @Override
public void forceStop() { public void forceStop() {
ProcessShell.exec("killall " + mExecutablePath, true);
mThread.interrupt(); mThread.interrupt();
ProcessShell.exec("killall " + mExecutablePath, true);
} }
@Override @Override
public void init() { public void init() {
mThread = Thread.currentThread(); mThread = Thread.currentThread();
} }
@Override
public synchronized void destroy() {
super.destroy();
Log.d(LOG_TAG, "Shell exit");
}
} }

View File

@@ -68,6 +68,7 @@ public class ProcessShell extends AbstractShell {
@Override @Override
public void exit() { public void exit() {
if (mProcess != null) { if (mProcess != null) {
Log.d(TAG, "exit: pid = " + ProcessUtils.getProcessPid(mProcess));
mProcess.destroy(); mProcess.destroy();
mProcess = null; mProcess = null;
} }
@@ -195,11 +196,14 @@ public class ProcessShell extends AbstractShell {
} }
os.writeBytes(COMMAND_EXIT); os.writeBytes(COMMAND_EXIT);
os.flush(); os.flush();
Log.d(TAG, "pid = " + ProcessUtils.getProcessPid(process));
commandResult.code = process.waitFor(); commandResult.code = process.waitFor();
commandResult.result = readAll(process.getInputStream()); commandResult.result = readAll(process.getInputStream());
commandResult.error = readAll(process.getErrorStream()); commandResult.error = readAll(process.getErrorStream());
Log.d(TAG, commandResult.toString()); Log.d(TAG, commandResult.toString());
} catch (Exception e) { } catch (Exception e) {
commandResult.code = -1;
commandResult.error = e.getMessage();
e.printStackTrace(); e.printStackTrace();
} finally { } finally {
try { try {

View File

@@ -3,22 +3,26 @@ package com.stardust.autojs.runtime.api;
import android.content.Context; import android.content.Context;
import android.os.SystemClock; import android.os.SystemClock;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.util.Log; import android.view.ViewConfiguration;
import android.view.InputDevice;
import com.stardust.autojs.core.inputevent.InputDevices; import com.stardust.autojs.core.inputevent.InputDevices;
import com.stardust.autojs.engine.RootAutomatorEngine; import com.stardust.autojs.engine.RootAutomatorEngine;
import com.stardust.autojs.runtime.ScriptRuntime;
import com.stardust.autojs.runtime.exception.ScriptInterruptedException; import com.stardust.autojs.runtime.exception.ScriptInterruptedException;
import com.stardust.pio.UncheckedIOException;
import com.stardust.util.ScreenMetrics; import com.stardust.util.ScreenMetrics;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import static com.stardust.autojs.core.inputevent.InputEventCodes.*; import static com.stardust.autojs.core.inputevent.InputEventCodes.ABS_MT_POSITION_X;
import static com.stardust.autojs.core.inputevent.InputEventCodes.ABS_MT_POSITION_Y;
import static com.stardust.autojs.core.inputevent.InputEventCodes.ABS_MT_TOUCH_MAJOR;
import static com.stardust.autojs.core.inputevent.InputEventCodes.ABS_MT_TRACKING_ID;
import static com.stardust.autojs.core.inputevent.InputEventCodes.BTN_TOOL_FINGER;
import static com.stardust.autojs.core.inputevent.InputEventCodes.BTN_TOUCH;
import static com.stardust.autojs.core.inputevent.InputEventCodes.EV_ABS;
import static com.stardust.autojs.core.inputevent.InputEventCodes.EV_KEY;
import static com.stardust.autojs.core.inputevent.InputEventCodes.EV_SYN;
import static com.stardust.autojs.core.inputevent.InputEventCodes.SYN_MT_REPORT;
import static com.stardust.autojs.core.inputevent.InputEventCodes.SYN_REPORT;
/** /**
* Created by Stardust on 2017/7/16. * Created by Stardust on 2017/7/16.
@@ -124,6 +128,24 @@ public class RootAutomator {
swipe(x1, y1, x2, y2, 300, mDefaultId); swipe(x1, y1, x2, y2, 300, mDefaultId);
} }
public void press(int x, int y, int duration, int id) throws IOException {
touchDown(x, y, id);
sleep(duration);
touchUp(id);
}
public void press(int x, int y, int duration) throws IOException {
press(x, y, duration, getDefaultId());
}
public void longPress(int x, int y, int id) throws IOException {
press(x, y, ViewConfiguration.getLongPressTimeout() + 200, id);
}
public void longPress(int x, int y) throws IOException {
press(x, y, ViewConfiguration.getLongPressTimeout() + 200, getDefaultId());
}
public void touchDown(int x, int y, int id) throws IOException { public void touchDown(int x, int y, int id) throws IOException {
sendEvent(EV_ABS, ABS_MT_TRACKING_ID, id); sendEvent(EV_ABS, ABS_MT_TRACKING_ID, id);
sendEvent(EV_KEY, BTN_TOUCH, 0x00000001); sendEvent(EV_KEY, BTN_TOUCH, 0x00000001);
@@ -168,10 +190,11 @@ public class RootAutomator {
mDefaultId = defaultId; mDefaultId = defaultId;
} }
private void sleep(long duration) { private void sleep(long duration) throws IOException {
try { try {
Thread.sleep(duration); Thread.sleep(duration);
} catch (InterruptedException e) { } catch (InterruptedException e) {
exit();
throw new ScriptInterruptedException(); throw new ScriptInterruptedException();
} }
} }

View File

@@ -69,6 +69,7 @@ public class Shell extends AbstractShell {
private volatile RuntimeException mInitException; private volatile RuntimeException mInitException;
private volatile boolean mInitialized = false; private volatile boolean mInitialized = false;
private volatile boolean mWaitingExit = false; private volatile boolean mWaitingExit = false;
private final boolean mShouldReadOutput;
private Callback mCallback; private Callback mCallback;
public Shell(Context context) { public Shell(Context context) {
@@ -76,7 +77,12 @@ public class Shell extends AbstractShell {
} }
public Shell(Context context, boolean root) { public Shell(Context context, boolean root) {
this(context, root, true);
}
public Shell(Context context, boolean root, boolean shouldReadOutput) {
super(context, root); super(context, root);
mShouldReadOutput = shouldReadOutput;
} }
public Shell() { public Shell() {
@@ -96,7 +102,7 @@ public class Shell extends AbstractShell {
TermSettings settings = new TermSettings(mContext.getResources(), PreferenceManager.getDefaultSharedPreferences(mContext)); TermSettings settings = new TermSettings(mContext.getResources(), PreferenceManager.getDefaultSharedPreferences(mContext));
try { try {
mTermSession = new MyShellTermSession(settings, initialCommand); mTermSession = new MyShellTermSession(settings, initialCommand);
mTermSession.initializeEmulator(40, 40); mTermSession.initializeEmulator(1024, 40);
} catch (IOException e) { } catch (IOException e) {
mInitException = new UncheckedIOException(e); mInitException = new UncheckedIOException(e);
} }
@@ -181,6 +187,9 @@ public class Shell extends AbstractShell {
} }
} }
public TermSession getTermSession() {
return mTermSession;
}
private class MyShellTermSession extends ShellTermSession { private class MyShellTermSession extends ShellTermSession {
@@ -193,7 +202,9 @@ public class Shell extends AbstractShell {
PipedInputStream pipedInputStream = new PipedInputStream(8192); PipedInputStream pipedInputStream = new PipedInputStream(8192);
mBufferedReader = new BufferedReader(new InputStreamReader(pipedInputStream)); mBufferedReader = new BufferedReader(new InputStreamReader(pipedInputStream));
mOutputStream = new PipedOutputStream(pipedInputStream); mOutputStream = new PipedOutputStream(pipedInputStream);
startReadingThread(); if (mShouldReadOutput) {
startReadingThread();
}
} }
private void startReadingThread() { private void startReadingThread() {
@@ -215,7 +226,7 @@ public class Shell extends AbstractShell {
} }
private void onNewLine(String line) { private void onNewLine(String line) {
Log.d(TAG, line); //Log.d(TAG, line);
if (!mInitialized) { if (!mInitialized) {
if (isRoot() && line.endsWith(" $ su")) { if (isRoot() && line.endsWith(" $ su")) {
notifyInitialized(); notifyInitialized();
@@ -277,6 +288,8 @@ public class Shell extends AbstractShell {
@Override @Override
public void finish() { public void finish() {
super.finish(); super.finish();
if (!mShouldReadOutput)
return;
mReadingThread.interrupt(); mReadingThread.interrupt();
try { try {
mBufferedReader.close(); mBufferedReader.close();

View File

@@ -24,7 +24,7 @@ public class ProcessUtils {
} }
private static int getProcessPid(Process process) { public static int getProcessPid(Process process) {
try { try {
Field pid = process.getClass().getDeclaredField("pid"); Field pid = process.getClass().getDeclaredField("pid");
pid.setAccessible(true); pid.setAccessible(true);