fix(autojs): root automator not working on some device

This commit is contained in:
hyb1996 2018-09-15 21:19:15 +08:00
parent a3ae309742
commit b2b2362f71
4 changed files with 166 additions and 65 deletions

View File

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

View File

@ -1,20 +1,31 @@
package com.stardust.autojs.core.inputevent;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.InputDevice;
/**
* Created by Stardust on 2017/8/1.
*/
public class InputDevices {
private static final String LOG_TAG = "InputDevices";
@Nullable
public static String getTouchDeviceName() {
InputDevice device = getTouchDevice();
return device == null ? null : device.getName();
}
@Nullable
public static InputDevice getTouchDevice() {
for (int id : InputDevice.getDeviceIds()) {
InputDevice device = InputDevice.getDevice(id);
Log.d(LOG_TAG, "device: " + device);
if (supportSource(device, InputDevice.SOURCE_TOUCHSCREEN) || supportSource(device, InputDevice.SOURCE_TOUCHPAD)) {
return device.getName();
return device;
}
}
return null;

View File

@ -1,37 +1,27 @@
package com.stardust.autojs.core.inputevent;
import android.content.Context;
import android.os.Build;
import android.os.SystemClock;
import android.support.annotation.Nullable;
import android.util.Log;
import android.util.SparseIntArray;
import android.view.ViewConfiguration;
import com.stardust.autojs.core.inputevent.InputDevices;
import com.stardust.autojs.core.util.ProcessShell;
import com.stardust.autojs.core.util.Shell;
import com.stardust.autojs.engine.RootAutomatorEngine;
import com.stardust.autojs.runtime.api.AbstractShell;
import com.stardust.autojs.runtime.exception.ScriptInterruptedException;
import com.stardust.util.ScreenMetrics;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;
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;
import static com.stardust.autojs.core.inputevent.InputEventCodes.*;
/**
* Created by Stardust on 2017/7/16.
*/
public class RootAutomator {
public class RootAutomator implements Shell.Callback {
private static final String LOG_TAG = "RootAutomator";
@ -43,22 +33,50 @@ public class RootAutomator {
@Nullable
private ScreenMetrics mScreenMetrics;
private AbstractShell mShell;
private int mDefaultId = 1;
private Shell mShell;
private int mDefaultId = 0;
private AtomicInteger mTracingId = new AtomicInteger(1);
private SparseIntArray mSlotIdMap = new SparseIntArray();
private final Object mReadyLock = new Object();
private volatile boolean mReady = false;
private final Context mContext;
public RootAutomator(Context context) {
mShell = new ProcessShell(true);
String path = RootAutomatorEngine.getExecutablePath(context);
String deviceNameOrPath = RootAutomatorEngine.getDeviceNameOrPath(context, InputDevices.getTouchDeviceName());
mShell.exec("chmod 777 " + path);
mShell.exec(path + " -d " + deviceNameOrPath);
public RootAutomator(Context context, boolean waitForReady) throws IOException {
mContext = context;
mShell = new Shell(true);
mShell.setCallback(this);
if(waitForReady){
waitForReady();
}
}
public void sendEvent(int type, int code, int value) throws IOException {
waitForReady();
sendEventInternal(type, code, value);
}
private void sendEventInternal(int type, int code, int value) {
mShell.exec(type + " " + code + " " + value);
}
private void waitForReady() throws IOException {
if(mReady){
return;
}
synchronized (mReadyLock){
if(mReady){
return;
}
try {
mReadyLock.wait();
} catch (InterruptedException e) {
exit();
throw new ScriptInterruptedException();
}
}
}
public void touch(int x, int y) throws IOException {
touchX(x);
touchY(y);
@ -150,11 +168,28 @@ public class RootAutomator {
}
public void touchDown(int x, int y, int id) throws IOException {
sendEvent(EV_ABS, ABS_MT_TRACKING_ID, id);
if(mSlotIdMap.size() == 0){
touchDown0(x, y, id);
return;
}
int slotId = mSlotIdMap.size();
mSlotIdMap.put(id, slotId);
sendEvent(EV_ABS, ABS_MT_SLOT, slotId);
sendEvent(EV_ABS, ABS_MT_TRACKING_ID, mTracingId.getAndIncrement());
sendEvent(EV_ABS, ABS_MT_POSITION_X, scaleX(x));
sendEvent(EV_ABS, ABS_MT_POSITION_Y, scaleY(y));
sendEvent(EV_ABS, ABS_MT_TOUCH_MAJOR, 5);
sendEvent(EV_SYN, SYN_REPORT, 0x00000000);
}
private void touchDown0(int x, int y, int id) throws IOException {
mSlotIdMap.put(id, 0);
sendEvent(EV_ABS, ABS_MT_TRACKING_ID, mTracingId.getAndIncrement());
sendEvent(EV_KEY, BTN_TOUCH, 0x00000001);
sendEvent(EV_KEY, BTN_TOOL_FINGER, 0x00000001);
sendEvent(EV_ABS, ABS_MT_POSITION_X, scaleX(x));
sendEvent(EV_ABS, ABS_MT_POSITION_Y, scaleY(y));
//sendEvent(EV_ABS, ABS_MT_PRESSURE, 200);
sendEvent(EV_ABS, ABS_MT_TOUCH_MAJOR, 5);
sendEvent(EV_SYN, SYN_REPORT, 0x00000000);
}
@ -164,9 +199,20 @@ public class RootAutomator {
}
public void touchUp(int id) throws IOException {
sendEvent(EV_ABS, ABS_MT_TRACKING_ID, id);
sendEvent(EV_KEY, BTN_TOUCH, 0x00000000);
sendEvent(EV_KEY, BTN_TOOL_FINGER, 0x00000000);
int slotId ;
int i = mSlotIdMap.indexOfKey(id);
if( i < 0){
slotId = 0;
}else {
slotId = mSlotIdMap.valueAt(i);
mSlotIdMap.removeAt(i);
}
sendEvent(EV_ABS, ABS_MT_SLOT, slotId);
sendEvent(EV_ABS, ABS_MT_TRACKING_ID, 0xffffffff);
if(mSlotIdMap.size() == 0){
sendEvent(EV_KEY, BTN_TOUCH, 0x00000000);
sendEvent(EV_KEY, BTN_TOOL_FINGER, 0x00000000);
}
sendEvent(EV_SYN, SYN_REPORT, 0x00000000);
}
@ -175,7 +221,9 @@ public class RootAutomator {
}
public void touchMove(int x, int y, int id) throws IOException {
sendEvent(EV_ABS, ABS_MT_TRACKING_ID, id);
int slotId = mSlotIdMap.get(id, 0);
sendEvent(EV_ABS, ABS_MT_SLOT, slotId);
sendEvent(EV_ABS, ABS_MT_TOUCH_MAJOR, 5);
sendEvent(EV_ABS, ABS_MT_POSITION_X, scaleX(x));
sendEvent(EV_ABS, ABS_MT_POSITION_Y, scaleY(y));
sendEvent(EV_SYN, SYN_REPORT, 0x00000000);
@ -207,7 +255,8 @@ public class RootAutomator {
}
public void exit() throws IOException {
sendEvent(0xffff, 0xffff, 0xefefefef);
sleep(1);
sendEventInternal(0xffff, 0xffff, 0xefefefef);
mShell.exec("exit");
mShell.exec("exit");
mShell.exec("exit");
@ -217,5 +266,33 @@ public class RootAutomator {
mShell.exit();
}
@Override
public void onOutput(String str) {
}
@Override
public void onNewLine(String line) {
}
@Override
public void onInitialized() {
String path = RootAutomatorEngine.getExecutablePath(mContext);
String deviceNameOrPath = RootAutomatorEngine.getDeviceNameOrPath(mContext, InputDevices.getTouchDeviceName());
Log.d(LOG_TAG, "deviceNameOrPath: " + deviceNameOrPath);
mShell.exec("chmod 777 " + path);
String command = path + " -d " + deviceNameOrPath;
mShell.exec(command);
synchronized (mReadyLock){
Log.d(LOG_TAG, "notify ready");
mReady = true;
mReadyLock.notifyAll();
}
}
@Override
public void onInterrupted(InterruptedException e) {
}
}

View File

@ -62,6 +62,7 @@ public class Shell extends AbstractShell {
}
}
private static final boolean DEBUG = true;
private static final String TAG = "Shell";
private volatile TermSession mTermSession;
@ -97,16 +98,13 @@ public class Shell extends AbstractShell {
@Override
protected void init(final String initialCommand) {
Handler uiHandler = new Handler(mContext.getMainLooper());
uiHandler.post(new Runnable() {
@Override
public void run() {
TermSettings settings = new TermSettings(mContext.getResources(), PreferenceManager.getDefaultSharedPreferences(mContext));
try {
mTermSession = new MyShellTermSession(settings, initialCommand);
mTermSession.initializeEmulator(1024, 40);
} catch (IOException e) {
mInitException = new UncheckedIOException(e);
}
uiHandler.post(() -> {
TermSettings settings = new TermSettings(mContext.getResources(), PreferenceManager.getDefaultSharedPreferences(mContext));
try {
mTermSession = new MyShellTermSession(settings, initialCommand);
mTermSession.initializeEmulator(1024, 40);
} catch (IOException e) {
mInitException = new UncheckedIOException(e);
}
});
}
@ -126,12 +124,21 @@ public class Shell extends AbstractShell {
private void ensureInitialized() {
if (mTermSession == null) {
logDebug("ensureInitialized: not init");
checkInitException();
waitInitialization();
if (mTermSession == null) {
checkInitException();
throw new IllegalStateException();
}
}else {
logDebug("ensureInitialized: init");
}
}
private void logDebug(String log){
if(DEBUG){
Log.d(TAG, log);
}
}
@ -142,11 +149,14 @@ public class Shell extends AbstractShell {
}
private void waitInitialization() {
if (mInitialized)
throw new IllegalStateException("already initialized");
synchronized (mInitLock) {
if(mInitialized){
return;
}
logDebug("waitInitialization: enter");
try {
mInitLock.wait();
logDebug("waitInitialization: exit");
} catch (InterruptedException e) {
onInterrupted(e);
}
@ -209,33 +219,25 @@ public class Shell extends AbstractShell {
}
private void startReadingThread() {
mReadingThread = new ThreadCompat(new Runnable() {
@Override
public void run() {
String line;
try {
while (!Thread.currentThread().isInterrupted()
&& (line = mBufferedReader.readLine()) != null) {
onNewLine(line);
}
} catch (IOException e) {
e.printStackTrace();
mReadingThread = new ThreadCompat(() -> {
String line;
try {
while (!Thread.currentThread().isInterrupted()
&& (line = mBufferedReader.readLine()) != null) {
onNewLine(line);
}
} catch (IOException e) {
e.printStackTrace();
}
});
mReadingThread.start();
}
private void onNewLine(String line) {
//Log.d(TAG, line);
logDebug("onNewLine: " + line);
if (!mInitialized) {
if (isRoot() && line.endsWith(" $ su")) {
notifyInitialized();
return;
}
if (!isRoot() && line.endsWith(" $ sh")) {
notifyInitialized();
return;
}
}
if (mCallback != null) {
@ -246,13 +248,23 @@ public class Shell extends AbstractShell {
}
}
private void onOutput(String str){
logDebug("onOutput: " + str);
if (!mInitialized) {
if (isRoot() && str.endsWith(":/ # ")) {
notifyInitialized();
}
}
if (mCallback != null) {
mCallback.onOutput(str);
}
}
@Override
protected void processInput(byte[] data, int offset, int count) {
try {
if (mCallback != null) {
mCallback.onOutput(new String(data, offset, count));
}
onOutput(new String(data, offset, count));
mOutputStream.write(data, offset, count);
} catch (IOException e) {
e.printStackTrace();
@ -268,6 +280,7 @@ public class Shell extends AbstractShell {
}
private void notifyInitialized() {
logDebug("notifyInitialized");
mInitialized = true;
synchronized (mInitLock) {
mInitLock.notifyAll();