add: root_automator
This commit is contained in:
BIN
autojs/src/main/assets/binary/root_automator
Normal file
BIN
autojs/src/main/assets/binary/root_automator
Normal file
Binary file not shown.
@@ -47,4 +47,4 @@ require("__general__")(__runtime__, this);
|
||||
|
||||
__importClass__(android.view.KeyEvent);
|
||||
__importClass__(com.stardust.autojs.runtime.api.Shell);
|
||||
__importClass__(com.stardust.autojs.runtime.api.InputEventSender);
|
||||
__importClass__(com.stardust.autojs.runtime.api.RootAutomator);
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.stardust.autojs.engine.preprocess;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/8/1.
|
||||
*/
|
||||
|
||||
public class RootAutomatorEngine {
|
||||
}
|
||||
@@ -1,11 +1,13 @@
|
||||
package com.stardust.autojs.runtime;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.view.accessibility.AccessibilityInfoProvider;
|
||||
import com.stardust.view.accessibility.AccessibilityService;
|
||||
import com.stardust.view.accessibility.NotificationListener;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/4/2.
|
||||
@@ -37,6 +39,7 @@ public abstract class AccessibilityBridge {
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
public abstract AccessibilityInfoProvider getInfoProvider();
|
||||
|
||||
|
||||
@@ -44,4 +47,6 @@ public abstract class AccessibilityBridge {
|
||||
mMode = mode;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public abstract NotificationListener.Observer getNotificationObserver();
|
||||
}
|
||||
|
||||
@@ -1,25 +1,24 @@
|
||||
package com.stardust.autojs.runtime.api;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.content.Context;
|
||||
import android.graphics.Point;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.SparseArray;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
|
||||
import com.stardust.autojs.runtime.AccessibilityBridge;
|
||||
import com.stardust.autojs.runtime.ScriptException;
|
||||
import com.stardust.autojs.runtime.record.inputevent.TouchObserver;
|
||||
import com.stardust.view.accessibility.AccessibilityService;
|
||||
import com.stardust.view.accessibility.NotificationListener;
|
||||
import com.stardust.view.accessibility.OnKeyListener;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/7/18.
|
||||
*/
|
||||
|
||||
public class Events extends EventEmitter implements OnKeyListener, TouchObserver.OnTouchEventListener {
|
||||
public class Events extends EventEmitter implements OnKeyListener, TouchObserver.OnTouchEventListener, NotificationListener {
|
||||
|
||||
private static final String PREFIX_KEY_DOWN = "__key_down__#";
|
||||
private static final String PREFIX_KEY_UP = "__key_up__#";
|
||||
@@ -32,6 +31,7 @@ public class Events extends EventEmitter implements OnKeyListener, TouchObserver
|
||||
private boolean mListeningKey = false;
|
||||
private Loopers mLoopers;
|
||||
private Handler mHandler;
|
||||
private boolean mListeningNotification = false;
|
||||
|
||||
public Events(Context context, AccessibilityBridge accessibilityBridge, ScriptBridges bridges, Loopers loopers) {
|
||||
super(bridges);
|
||||
@@ -122,6 +122,25 @@ public class Events extends EventEmitter implements OnKeyListener, TouchObserver
|
||||
}
|
||||
|
||||
|
||||
public void observeNotification() {
|
||||
if (mListeningNotification)
|
||||
return;
|
||||
mListeningNotification = true;
|
||||
mAccessibilityBridge.getNotificationObserver()
|
||||
.addListener(this);
|
||||
}
|
||||
|
||||
public Events onNotification(Object listener) {
|
||||
on("notification", listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Events onToast(Object listener) {
|
||||
on("toast", listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public void recycle() {
|
||||
if (mListeningKey) {
|
||||
AccessibilityService service = mAccessibilityBridge.getService();
|
||||
@@ -133,6 +152,9 @@ public class Events extends EventEmitter implements OnKeyListener, TouchObserver
|
||||
if (mTouchObserver != null) {
|
||||
mTouchObserver.stop();
|
||||
}
|
||||
if (mListeningNotification) {
|
||||
mAccessibilityBridge.getNotificationObserver().removeListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -169,4 +191,24 @@ public class Events extends EventEmitter implements OnKeyListener, TouchObserver
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onNotification(final AccessibilityEvent event, final String[] notification) {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
emit("toast", new Object[]{notification});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNotification(final AccessibilityEvent event, final Notification notification) {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
emit("notification", notification);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
package com.stardust.autojs.runtime.api;
|
||||
|
||||
import com.stardust.util.ScreenMetrics;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/7/16.
|
||||
*/
|
||||
|
||||
public class InputEventSender {
|
||||
private DataOutputStream mDeviceFile;
|
||||
private ScreenMetrics mScreenMetrics;
|
||||
|
||||
|
||||
public InputEventSender(String devicePath) throws FileNotFoundException {
|
||||
mDeviceFile = new DataOutputStream(new FileOutputStream(devicePath));
|
||||
}
|
||||
|
||||
public InputEventSender(int i) throws FileNotFoundException {
|
||||
this("/dev/input/event" + i);
|
||||
}
|
||||
|
||||
public InputEventSender() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void sendEvent(int type, int code, int value) throws IOException {
|
||||
for (int i = 0; i < 16; i++)
|
||||
mDeviceFile.writeByte(0);
|
||||
mDeviceFile.writeShort(type);
|
||||
mDeviceFile.writeShort(code);
|
||||
mDeviceFile.writeInt(value);
|
||||
mDeviceFile.flush();
|
||||
}
|
||||
|
||||
|
||||
public void setInputDevice(int i) throws IOException {
|
||||
if (mDeviceFile != null) {
|
||||
mDeviceFile.close();
|
||||
}
|
||||
mDeviceFile = new DataOutputStream(new FileOutputStream("/dev/input/event" + i));
|
||||
}
|
||||
|
||||
public void Touch(int x, int y) throws IOException {
|
||||
TouchX(x);
|
||||
TouchY(y);
|
||||
}
|
||||
|
||||
public void setScreenMetrics(int width, int height) {
|
||||
if (mScreenMetrics == null) {
|
||||
mScreenMetrics = new ScreenMetrics();
|
||||
}
|
||||
mScreenMetrics.setScreenMetrics(width, height);
|
||||
}
|
||||
|
||||
public void TouchX(int x) throws IOException {
|
||||
sendEvent(3, 53, scaleX(x));
|
||||
}
|
||||
|
||||
private int scaleX(int x) {
|
||||
return mScreenMetrics.scaleX(x);
|
||||
}
|
||||
|
||||
public void TouchY(int y) throws IOException {
|
||||
sendEvent(3, 54, scaleY(y));
|
||||
}
|
||||
|
||||
private int scaleY(int y) {
|
||||
return mScreenMetrics.scaleY(y);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void close() throws IOException {
|
||||
mDeviceFile.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
package com.stardust.autojs.runtime.api;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.stardust.pio.PFile;
|
||||
import com.stardust.pio.UncheckedIOException;
|
||||
import com.stardust.util.ScreenMetrics;
|
||||
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/7/16.
|
||||
*/
|
||||
|
||||
public class RootAutomator {
|
||||
|
||||
|
||||
private static final int DATA_TYPE_SLEEP = 0;
|
||||
private static final int DATA_TYPE_EVENT = 1;
|
||||
|
||||
private static final String ROOT_AUTOMATOR_EXECUTABLE_ASSET = "binary/root_automator";
|
||||
private DataOutputStream mTmpFileOutputStream;
|
||||
private File mEventTmpFile;
|
||||
private ScreenMetrics mScreenMetrics;
|
||||
private String mDevicePath;
|
||||
|
||||
public RootAutomator() {
|
||||
try {
|
||||
mEventTmpFile = File.createTempFile(String.valueOf(System.currentTimeMillis()), ".auto");
|
||||
mEventTmpFile.deleteOnExit();
|
||||
mTmpFileOutputStream = new DataOutputStream(new FileOutputStream(mEventTmpFile));
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void sendEvent(int type, int code, int value) throws IOException {
|
||||
mTmpFileOutputStream.writeByte(DATA_TYPE_EVENT);
|
||||
mTmpFileOutputStream.writeShort(type);
|
||||
mTmpFileOutputStream.writeShort(code);
|
||||
mTmpFileOutputStream.writeInt(value);
|
||||
}
|
||||
|
||||
public void setInputDevice(int i) throws IOException {
|
||||
mDevicePath = "/dev/input/event" + i;
|
||||
}
|
||||
|
||||
public void touch(int x, int y) throws IOException {
|
||||
touchX(x);
|
||||
touchY(y);
|
||||
}
|
||||
|
||||
public void setScreenMetrics(int width, int height) {
|
||||
if (mScreenMetrics == null) {
|
||||
mScreenMetrics = new ScreenMetrics();
|
||||
}
|
||||
mScreenMetrics.setScreenMetrics(width, height);
|
||||
}
|
||||
|
||||
public void touchX(int x) throws IOException {
|
||||
sendEvent(3, 53, scaleX(x));
|
||||
}
|
||||
|
||||
private int scaleX(int x) {
|
||||
return mScreenMetrics.scaleX(x);
|
||||
}
|
||||
|
||||
public void touchY(int y) throws IOException {
|
||||
sendEvent(3, 54, scaleY(y));
|
||||
}
|
||||
|
||||
public void sendSync() throws IOException {
|
||||
sendEvent(0, 0, 0);
|
||||
}
|
||||
|
||||
private int scaleY(int y) {
|
||||
return mScreenMetrics.scaleY(y);
|
||||
|
||||
}
|
||||
|
||||
public void sleep(int n) throws IOException {
|
||||
mTmpFileOutputStream.writeByte(DATA_TYPE_SLEEP);
|
||||
mTmpFileOutputStream.writeInt(n);
|
||||
}
|
||||
|
||||
public AbstractShell.Result writeToDevice(Context context) {
|
||||
try {
|
||||
mTmpFileOutputStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
String executablePath = getExecutablePath(context);
|
||||
return ProcessShell.execCommand(new String[]{
|
||||
"chmod 777 " + executablePath,
|
||||
executablePath + " " + mEventTmpFile.getAbsolutePath() + " " + mDevicePath
|
||||
}, true);
|
||||
}
|
||||
|
||||
public static String getExecutablePath(Context context) {
|
||||
File tmp = new File(context.getCacheDir(), "root_automator");
|
||||
if (!tmp.exists()) {
|
||||
PFile.copyAsset(context, ROOT_AUTOMATOR_EXECUTABLE_ASSET, tmp.getAbsolutePath());
|
||||
}
|
||||
return tmp.getAbsolutePath();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.stardust.autojs.runtime.record.inputevent;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/8/1.
|
||||
*/
|
||||
|
||||
public class InputDevice {
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
package com.stardust.autojs.runtime.record.inputevent;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.stardust.util.ScreenMetrics.getDeviceScreenHeight;
|
||||
import static com.stardust.util.ScreenMetrics.getDeviceScreenWidth;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/8/1.
|
||||
*/
|
||||
|
||||
public class InputEventToRootAutomatorConverter extends InputEventConverter {
|
||||
|
||||
|
||||
private double mLastEventTime;
|
||||
private StringBuilder mCode = new StringBuilder();
|
||||
private int mTouchDevice = -1;
|
||||
private int mLastTouchX = -1;
|
||||
private int mLastTouchY = -1;
|
||||
|
||||
public InputEventToRootAutomatorConverter() {
|
||||
mCode.append("var ra = new RootAutomator();\n")
|
||||
.append("ra.setScreenMetrics(").append(getDeviceScreenWidth()).append(", ")
|
||||
.append(getDeviceScreenHeight()).append(");\n");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void convertEvent(@NonNull Event event) {
|
||||
if (mLastEventTime == 0) {
|
||||
mLastEventTime = event.time;
|
||||
} else if (event.time - mLastEventTime > 0.005) {
|
||||
mCode.append("ra.sleep(").append((long) (1000L * (event.time - mLastEventTime))).append(");\n");
|
||||
mLastEventTime = event.time;
|
||||
}
|
||||
int device = parseDeviceNumber(event.device);
|
||||
int type = (int) Long.parseLong(event.type, 16);
|
||||
int code = (int) Long.parseLong(event.code, 16);
|
||||
int value = (int) Long.parseLong(event.value, 16);
|
||||
if (type == 3) {
|
||||
if (code == 53) {
|
||||
onTouchX(device, value);
|
||||
return;
|
||||
}
|
||||
if (code == 54) {
|
||||
onTouchY(device, value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
checkLastTouch();
|
||||
if (device != mTouchDevice) {
|
||||
return;
|
||||
}
|
||||
if (type == 0 && code == 0 && value == 0) {
|
||||
mCode.append("ra.sendSync();\n");
|
||||
return;
|
||||
}
|
||||
mCode.append("ra.sendEvent(");
|
||||
mCode.append(type).append(", ")
|
||||
.append(code).append(", ")
|
||||
.append(value).append(");\n");
|
||||
}
|
||||
|
||||
private void checkLastTouch() {
|
||||
if (mLastTouchX >= 0) {
|
||||
mCode.append("ra.touchX(").append(mLastTouchX).append(");\n");
|
||||
mLastTouchX = -1;
|
||||
}
|
||||
if (mLastTouchY >= 0) {
|
||||
mCode.append("ra.touchY(").append(mLastTouchY).append(");\n");
|
||||
mLastTouchY = -1;
|
||||
}
|
||||
}
|
||||
|
||||
private void onTouchX(int device, int value) {
|
||||
if (mTouchDevice == -1) {
|
||||
setTouchDevice(device);
|
||||
}
|
||||
mLastTouchX = value;
|
||||
}
|
||||
|
||||
private void onTouchY(int device, int value) {
|
||||
if (mTouchDevice == -1) {
|
||||
setTouchDevice(device);
|
||||
}
|
||||
if (mLastTouchX >= 0) {
|
||||
mCode.append("ra.touch(")
|
||||
.append(mLastTouchX).append(", ")
|
||||
.append(value).append(");\n");
|
||||
mLastTouchX = -1;
|
||||
} else {
|
||||
mLastTouchY = value;
|
||||
}
|
||||
}
|
||||
|
||||
private void setTouchDevice(int i) {
|
||||
mCode.append("ra.setInputDevice(").append(i).append(");\n");
|
||||
mTouchDevice = i;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGetEventCommand() {
|
||||
return "getevent -t";
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return mCode.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
super.stop();
|
||||
mCode.append("log(ra.writeToDevice(context));");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import android.content.Context;
|
||||
public class TouchRecorder extends InputEventRecorder {
|
||||
|
||||
public TouchRecorder(Context context) {
|
||||
super(context, new InputEventToSendEventJsConverter());
|
||||
super(context, new InputEventToRootAutomatorConverter());
|
||||
listen();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:accessibilityEventTypes="typeAllMask"
|
||||
android:accessibilityFeedbackType="feedbackGeneric"
|
||||
android:accessibilityFeedbackType="feedbackAllMask"
|
||||
android:accessibilityFlags="flagIncludeNotImportantViews|flagReportViewIds|flagRetrieveInteractiveWindows|flagRequestEnhancedWebAccessibility|flagRequestFilterKeyEvents"
|
||||
android:canPerformGestures="true"
|
||||
android:canRequestEnhancedWebAccessibility="true"
|
||||
|
||||
Reference in New Issue
Block a user