fix(autojs): root automator not working on some device
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
module.exports = function(__runtime__, scope){
|
module.exports = function(__runtime__, scope){
|
||||||
function RootAutomator(){
|
function RootAutomator(nonBlockingForReady){
|
||||||
this.__ra__ = Object.create(new com.stardust.autojs.core.inputevent.RootAutomator(scope.context));
|
this.__ra__ = Object.create(new com.stardust.autojs.core.inputevent.RootAutomator(scope.context, !nonBlockingForReady));
|
||||||
var methods = ["sendEvent", "touch", "setScreenMetrics", "touchX", "touchY", "sendSync", "sendMtSync", "tap",
|
var methods = ["sendEvent", "touch", "setScreenMetrics", "touchX", "touchY", "sendSync", "sendMtSync", "tap",
|
||||||
"swipe", "press", "longPress", "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++){
|
||||||
|
|||||||
@@ -1,20 +1,31 @@
|
|||||||
package com.stardust.autojs.core.inputevent;
|
package com.stardust.autojs.core.inputevent;
|
||||||
|
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.InputDevice;
|
import android.view.InputDevice;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Stardust on 2017/8/1.
|
* Created by Stardust on 2017/8/1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class InputDevices {
|
public class InputDevices {
|
||||||
|
|
||||||
|
private static final String LOG_TAG = "InputDevices";
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static String getTouchDeviceName() {
|
public static String getTouchDeviceName() {
|
||||||
|
InputDevice device = getTouchDevice();
|
||||||
|
return device == null ? null : device.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static InputDevice getTouchDevice() {
|
||||||
for (int id : InputDevice.getDeviceIds()) {
|
for (int id : InputDevice.getDeviceIds()) {
|
||||||
InputDevice device = InputDevice.getDevice(id);
|
InputDevice device = InputDevice.getDevice(id);
|
||||||
|
Log.d(LOG_TAG, "device: " + device);
|
||||||
if (supportSource(device, InputDevice.SOURCE_TOUCHSCREEN) || supportSource(device, InputDevice.SOURCE_TOUCHPAD)) {
|
if (supportSource(device, InputDevice.SOURCE_TOUCHSCREEN) || supportSource(device, InputDevice.SOURCE_TOUCHPAD)) {
|
||||||
return device.getName();
|
return device;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -1,37 +1,27 @@
|
|||||||
package com.stardust.autojs.core.inputevent;
|
package com.stardust.autojs.core.inputevent;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Build;
|
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.util.SparseIntArray;
|
||||||
import android.view.ViewConfiguration;
|
import android.view.ViewConfiguration;
|
||||||
|
|
||||||
import com.stardust.autojs.core.inputevent.InputDevices;
|
import com.stardust.autojs.core.util.Shell;
|
||||||
import com.stardust.autojs.core.util.ProcessShell;
|
|
||||||
import com.stardust.autojs.engine.RootAutomatorEngine;
|
import com.stardust.autojs.engine.RootAutomatorEngine;
|
||||||
import com.stardust.autojs.runtime.api.AbstractShell;
|
|
||||||
import com.stardust.autojs.runtime.exception.ScriptInterruptedException;
|
import com.stardust.autojs.runtime.exception.ScriptInterruptedException;
|
||||||
import com.stardust.util.ScreenMetrics;
|
import com.stardust.util.ScreenMetrics;
|
||||||
|
|
||||||
import java.io.IOException;
|
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.*;
|
||||||
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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class RootAutomator {
|
public class RootAutomator implements Shell.Callback {
|
||||||
|
|
||||||
private static final String LOG_TAG = "RootAutomator";
|
private static final String LOG_TAG = "RootAutomator";
|
||||||
|
|
||||||
@@ -43,22 +33,50 @@ public class RootAutomator {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private ScreenMetrics mScreenMetrics;
|
private ScreenMetrics mScreenMetrics;
|
||||||
private AbstractShell mShell;
|
private Shell mShell;
|
||||||
private int mDefaultId = 1;
|
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) {
|
public RootAutomator(Context context, boolean waitForReady) throws IOException {
|
||||||
mShell = new ProcessShell(true);
|
mContext = context;
|
||||||
String path = RootAutomatorEngine.getExecutablePath(context);
|
mShell = new Shell(true);
|
||||||
String deviceNameOrPath = RootAutomatorEngine.getDeviceNameOrPath(context, InputDevices.getTouchDeviceName());
|
mShell.setCallback(this);
|
||||||
mShell.exec("chmod 777 " + path);
|
if(waitForReady){
|
||||||
mShell.exec(path + " -d " + deviceNameOrPath);
|
waitForReady();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void sendEvent(int type, int code, int value) throws IOException {
|
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);
|
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 {
|
public void touch(int x, int y) throws IOException {
|
||||||
touchX(x);
|
touchX(x);
|
||||||
touchY(y);
|
touchY(y);
|
||||||
@@ -150,11 +168,28 @@ public class RootAutomator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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);
|
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_TOUCH, 0x00000001);
|
||||||
sendEvent(EV_KEY, BTN_TOOL_FINGER, 0x00000001);
|
sendEvent(EV_KEY, BTN_TOOL_FINGER, 0x00000001);
|
||||||
sendEvent(EV_ABS, ABS_MT_POSITION_X, scaleX(x));
|
sendEvent(EV_ABS, ABS_MT_POSITION_X, scaleX(x));
|
||||||
sendEvent(EV_ABS, ABS_MT_POSITION_Y, scaleY(y));
|
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_ABS, ABS_MT_TOUCH_MAJOR, 5);
|
||||||
sendEvent(EV_SYN, SYN_REPORT, 0x00000000);
|
sendEvent(EV_SYN, SYN_REPORT, 0x00000000);
|
||||||
}
|
}
|
||||||
@@ -164,9 +199,20 @@ public class RootAutomator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void touchUp(int id) throws IOException {
|
public void touchUp(int id) throws IOException {
|
||||||
sendEvent(EV_ABS, ABS_MT_TRACKING_ID, id);
|
int slotId ;
|
||||||
sendEvent(EV_KEY, BTN_TOUCH, 0x00000000);
|
int i = mSlotIdMap.indexOfKey(id);
|
||||||
sendEvent(EV_KEY, BTN_TOOL_FINGER, 0x00000000);
|
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);
|
sendEvent(EV_SYN, SYN_REPORT, 0x00000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,7 +221,9 @@ public class RootAutomator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void touchMove(int x, int y, int id) throws IOException {
|
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_X, scaleX(x));
|
||||||
sendEvent(EV_ABS, ABS_MT_POSITION_Y, scaleY(y));
|
sendEvent(EV_ABS, ABS_MT_POSITION_Y, scaleY(y));
|
||||||
sendEvent(EV_SYN, SYN_REPORT, 0x00000000);
|
sendEvent(EV_SYN, SYN_REPORT, 0x00000000);
|
||||||
@@ -207,7 +255,8 @@ public class RootAutomator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void exit() throws IOException {
|
public void exit() throws IOException {
|
||||||
sendEvent(0xffff, 0xffff, 0xefefefef);
|
sleep(1);
|
||||||
|
sendEventInternal(0xffff, 0xffff, 0xefefefef);
|
||||||
mShell.exec("exit");
|
mShell.exec("exit");
|
||||||
mShell.exec("exit");
|
mShell.exec("exit");
|
||||||
mShell.exec("exit");
|
mShell.exec("exit");
|
||||||
@@ -217,5 +266,33 @@ public class RootAutomator {
|
|||||||
mShell.exit();
|
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) {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ public class Shell extends AbstractShell {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final boolean DEBUG = true;
|
||||||
private static final String TAG = "Shell";
|
private static final String TAG = "Shell";
|
||||||
|
|
||||||
private volatile TermSession mTermSession;
|
private volatile TermSession mTermSession;
|
||||||
@@ -97,16 +98,13 @@ public class Shell extends AbstractShell {
|
|||||||
@Override
|
@Override
|
||||||
protected void init(final String initialCommand) {
|
protected void init(final String initialCommand) {
|
||||||
Handler uiHandler = new Handler(mContext.getMainLooper());
|
Handler uiHandler = new Handler(mContext.getMainLooper());
|
||||||
uiHandler.post(new Runnable() {
|
uiHandler.post(() -> {
|
||||||
@Override
|
TermSettings settings = new TermSettings(mContext.getResources(), PreferenceManager.getDefaultSharedPreferences(mContext));
|
||||||
public void run() {
|
try {
|
||||||
TermSettings settings = new TermSettings(mContext.getResources(), PreferenceManager.getDefaultSharedPreferences(mContext));
|
mTermSession = new MyShellTermSession(settings, initialCommand);
|
||||||
try {
|
mTermSession.initializeEmulator(1024, 40);
|
||||||
mTermSession = new MyShellTermSession(settings, initialCommand);
|
} catch (IOException e) {
|
||||||
mTermSession.initializeEmulator(1024, 40);
|
mInitException = new UncheckedIOException(e);
|
||||||
} catch (IOException e) {
|
|
||||||
mInitException = new UncheckedIOException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -126,12 +124,21 @@ public class Shell extends AbstractShell {
|
|||||||
|
|
||||||
private void ensureInitialized() {
|
private void ensureInitialized() {
|
||||||
if (mTermSession == null) {
|
if (mTermSession == null) {
|
||||||
|
logDebug("ensureInitialized: not init");
|
||||||
checkInitException();
|
checkInitException();
|
||||||
waitInitialization();
|
waitInitialization();
|
||||||
if (mTermSession == null) {
|
if (mTermSession == null) {
|
||||||
checkInitException();
|
checkInitException();
|
||||||
throw new IllegalStateException();
|
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() {
|
private void waitInitialization() {
|
||||||
if (mInitialized)
|
|
||||||
throw new IllegalStateException("already initialized");
|
|
||||||
synchronized (mInitLock) {
|
synchronized (mInitLock) {
|
||||||
|
if(mInitialized){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
logDebug("waitInitialization: enter");
|
||||||
try {
|
try {
|
||||||
mInitLock.wait();
|
mInitLock.wait();
|
||||||
|
logDebug("waitInitialization: exit");
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
onInterrupted(e);
|
onInterrupted(e);
|
||||||
}
|
}
|
||||||
@@ -209,33 +219,25 @@ public class Shell extends AbstractShell {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void startReadingThread() {
|
private void startReadingThread() {
|
||||||
mReadingThread = new ThreadCompat(new Runnable() {
|
mReadingThread = new ThreadCompat(() -> {
|
||||||
@Override
|
String line;
|
||||||
public void run() {
|
try {
|
||||||
String line;
|
while (!Thread.currentThread().isInterrupted()
|
||||||
try {
|
&& (line = mBufferedReader.readLine()) != null) {
|
||||||
while (!Thread.currentThread().isInterrupted()
|
onNewLine(line);
|
||||||
&& (line = mBufferedReader.readLine()) != null) {
|
|
||||||
onNewLine(line);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mReadingThread.start();
|
mReadingThread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onNewLine(String line) {
|
private void onNewLine(String line) {
|
||||||
//Log.d(TAG, line);
|
logDebug("onNewLine: " + line);
|
||||||
if (!mInitialized) {
|
if (!mInitialized) {
|
||||||
if (isRoot() && line.endsWith(" $ su")) {
|
|
||||||
notifyInitialized();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!isRoot() && line.endsWith(" $ sh")) {
|
if (!isRoot() && line.endsWith(" $ sh")) {
|
||||||
notifyInitialized();
|
notifyInitialized();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mCallback != null) {
|
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
|
@Override
|
||||||
protected void processInput(byte[] data, int offset, int count) {
|
protected void processInput(byte[] data, int offset, int count) {
|
||||||
try {
|
try {
|
||||||
if (mCallback != null) {
|
onOutput(new String(data, offset, count));
|
||||||
mCallback.onOutput(new String(data, offset, count));
|
|
||||||
}
|
|
||||||
mOutputStream.write(data, offset, count);
|
mOutputStream.write(data, offset, count);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@@ -268,6 +280,7 @@ public class Shell extends AbstractShell {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void notifyInitialized() {
|
private void notifyInitialized() {
|
||||||
|
logDebug("notifyInitialized");
|
||||||
mInitialized = true;
|
mInitialized = true;
|
||||||
synchronized (mInitLock) {
|
synchronized (mInitLock) {
|
||||||
mInitLock.notifyAll();
|
mInitLock.notifyAll();
|
||||||
|
|||||||
Reference in New Issue
Block a user