add: root_automator

This commit is contained in:
hyb1996
2017-08-01 21:42:32 +08:00
parent 8734ae3992
commit 6a3392cfe6
22 changed files with 474 additions and 112 deletions

Binary file not shown.

View File

@@ -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);

View File

@@ -0,0 +1,8 @@
package com.stardust.autojs.engine.preprocess;
/**
* Created by Stardust on 2017/8/1.
*/
public class RootAutomatorEngine {
}

View File

@@ -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();
}

View File

@@ -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);
}
});
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -0,0 +1,8 @@
package com.stardust.autojs.runtime.record.inputevent;
/**
* Created by Stardust on 2017/8/1.
*/
public class InputDevice {
}

View File

@@ -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));");
}
}

View File

@@ -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();
}

View File

@@ -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"