add: root_automator
This commit is contained in:
1
.idea/dictionaries/Stardust.xml
generated
1
.idea/dictionaries/Stardust.xml
generated
@@ -3,6 +3,7 @@
|
|||||||
<words>
|
<words>
|
||||||
<w>dismissable</w>
|
<w>dismissable</w>
|
||||||
<w>interruptible</w>
|
<w>interruptible</w>
|
||||||
|
<w>loopers</w>
|
||||||
<w>prefill</w>
|
<w>prefill</w>
|
||||||
<w>scriptable</w>
|
<w>scriptable</w>
|
||||||
<w>tasker</w>
|
<w>tasker</w>
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ events.onKeyDown("menu", function(event){
|
|||||||
### events.onTouch(listener)
|
### events.onTouch(listener)
|
||||||
* listener \<Function\> 参数为Point的函数
|
* listener \<Function\> 参数为Point的函数
|
||||||
|
|
||||||
注册一个触摸监听函数。
|
注册一个触摸监听函数。相当于`on("touch", listener)`。
|
||||||
|
|
||||||
例如:
|
例如:
|
||||||
```
|
```
|
||||||
@@ -147,6 +147,28 @@ events.loop();
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### obverseNotification()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### toast事件
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 事件: 'notification'
|
||||||
|
* notification \<Notification\> 通知
|
||||||
|
|
||||||
|
```
|
||||||
|
events.observeNotification();
|
||||||
|
events.on("notification", function(notification){
|
||||||
|
log(notification.
|
||||||
|
});
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# EventEmitter
|
# EventEmitter
|
||||||
|
|
||||||
### EventEmitter.defaultMaxListeners
|
### EventEmitter.defaultMaxListeners
|
||||||
@@ -155,7 +177,7 @@ events.loop();
|
|||||||
|
|
||||||
设置 EventEmitter.defaultMaxListeners 要谨慎,因为会影响所有 EventEmitter 实例,包括之前创建的。 因而,调用 emitter.setMaxListeners(n) 优先于 EventEmitter.defaultMaxListeners。
|
设置 EventEmitter.defaultMaxListeners 要谨慎,因为会影响所有 EventEmitter 实例,包括之前创建的。 因而,调用 emitter.setMaxListeners(n) 优先于 EventEmitter.defaultMaxListeners。
|
||||||
|
|
||||||
注意,与NodeJs不同,**这是一个硬性限制**。 EventEmitter 实例不允许添加更多的监听器,监听器超过最大数量时会抛出TooManyListenersException。
|
注意,与Node.js不同,**这是一个硬性限制**。 EventEmitter 实例不允许添加更多的监听器,监听器超过最大数量时会抛出TooManyListenersException。
|
||||||
```
|
```
|
||||||
emitter.setMaxListeners(emitter.getMaxListeners() + 1);
|
emitter.setMaxListeners(emitter.getMaxListeners() + 1);
|
||||||
emitter.once('event', () => {
|
emitter.once('event', () => {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"global" : {
|
"global": {
|
||||||
"modules": [
|
"modules": [
|
||||||
"app",
|
"app",
|
||||||
"automator",
|
"automator",
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
"openConsole",
|
"openConsole",
|
||||||
"clearConsole"
|
"clearConsole"
|
||||||
],
|
],
|
||||||
"dialogs":[
|
"dialogs": [
|
||||||
"rawInput",
|
"rawInput",
|
||||||
"input",
|
"input",
|
||||||
"alert",
|
"alert",
|
||||||
@@ -211,7 +211,7 @@
|
|||||||
"error",
|
"error",
|
||||||
"assert"
|
"assert"
|
||||||
],
|
],
|
||||||
"dialogs":[
|
"dialogs": [
|
||||||
"select",
|
"select",
|
||||||
"singleChoice",
|
"singleChoice",
|
||||||
"multiChoice",
|
"multiChoice",
|
||||||
@@ -248,6 +248,8 @@
|
|||||||
"onKeyUp",
|
"onKeyUp",
|
||||||
"onceKeyDown",
|
"onceKeyDown",
|
||||||
"onceKeyUp",
|
"onceKeyUp",
|
||||||
|
"onToast",
|
||||||
|
"onNotification",
|
||||||
"removeAllKeyDownListeners",
|
"removeAllKeyDownListeners",
|
||||||
"removeAllKeyUpListeners",
|
"removeAllKeyUpListeners",
|
||||||
"onTouch",
|
"onTouch",
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.stardust.scriptdroid.autojs;
|
package com.stardust.scriptdroid.autojs;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.app.Notification;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@@ -36,6 +37,7 @@ import com.stardust.scriptdroid.tool.AccessibilityServiceTool;
|
|||||||
import com.stardust.scriptdroid.ui.console.JraskaConsole;
|
import com.stardust.scriptdroid.ui.console.JraskaConsole;
|
||||||
import com.stardust.view.accessibility.AccessibilityServiceUtils;
|
import com.stardust.view.accessibility.AccessibilityServiceUtils;
|
||||||
import com.stardust.view.accessibility.LayoutInspector;
|
import com.stardust.view.accessibility.LayoutInspector;
|
||||||
|
import com.stardust.view.accessibility.NotificationListener;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -55,6 +57,7 @@ public class AutoJs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private final AccessibilityActionRecorder mAccessibilityActionRecorder = new AccessibilityActionRecorder();
|
private final AccessibilityActionRecorder mAccessibilityActionRecorder = new AccessibilityActionRecorder();
|
||||||
|
private final NotificationListener.Observer mNotificationObserver;
|
||||||
private final LayoutInspector mLayoutInspector = new LayoutInspector();
|
private final LayoutInspector mLayoutInspector = new LayoutInspector();
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
private final UiHandler mUiHandler;
|
private final UiHandler mUiHandler;
|
||||||
@@ -68,6 +71,7 @@ public class AutoJs {
|
|||||||
mContext = context;
|
mContext = context;
|
||||||
mUiHandler = new UiHandler(context);
|
mUiHandler = new UiHandler(context);
|
||||||
mAppUtils = new AppUtils(context);
|
mAppUtils = new AppUtils(context);
|
||||||
|
mNotificationObserver = new NotificationListener.Observer(context);
|
||||||
mAccessibilityInfoProvider = new AccessibilityInfoProvider(context.getPackageManager());
|
mAccessibilityInfoProvider = new AccessibilityInfoProvider(context.getPackageManager());
|
||||||
mScriptEngineService = buildScriptEngineService();
|
mScriptEngineService = buildScriptEngineService();
|
||||||
addAccessibilityServiceDelegates();
|
addAccessibilityServiceDelegates();
|
||||||
@@ -130,6 +134,7 @@ public class AutoJs {
|
|||||||
|
|
||||||
private void addAccessibilityServiceDelegates() {
|
private void addAccessibilityServiceDelegates() {
|
||||||
AccessibilityService.addDelegate(100, mAccessibilityInfoProvider);
|
AccessibilityService.addDelegate(100, mAccessibilityInfoProvider);
|
||||||
|
AccessibilityService.addDelegate(200, mNotificationObserver);
|
||||||
AccessibilityService.addDelegate(300, mAccessibilityActionRecorder);
|
AccessibilityService.addDelegate(300, mAccessibilityActionRecorder);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,6 +203,11 @@ public class AutoJs {
|
|||||||
return mAccessibilityInfoProvider;
|
return mAccessibilityInfoProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NotificationListener.Observer getNotificationObserver() {
|
||||||
|
return mNotificationObserver;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ScreenCaptureRequesterImpl extends ScreenCaptureRequester.AbstractScreenCaptureRequester {
|
private class ScreenCaptureRequesterImpl extends ScreenCaptureRequester.AbstractScreenCaptureRequester {
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import com.stardust.scriptdroid.autojs.AutoJs;
|
|||||||
import com.stardust.view.accessibility.NodeInfo;
|
import com.stardust.view.accessibility.NodeInfo;
|
||||||
import com.stardust.scriptdroid.external.floatingwindow.menu.view.FloatingLayoutBoundsView;
|
import com.stardust.scriptdroid.external.floatingwindow.menu.view.FloatingLayoutBoundsView;
|
||||||
import com.stardust.scriptdroid.external.floatingwindow.menu.view.FloatingLayoutHierarchyView;
|
import com.stardust.scriptdroid.external.floatingwindow.menu.view.FloatingLayoutHierarchyView;
|
||||||
import com.stardust.scriptdroid.tool.AccessibilityServiceTool;
|
|
||||||
import com.stardust.theme.ThemeColorManagerCompat;
|
import com.stardust.theme.ThemeColorManagerCompat;
|
||||||
import com.stardust.util.IntentUtil;
|
import com.stardust.util.IntentUtil;
|
||||||
import com.stardust.util.MessageEvent;
|
import com.stardust.util.MessageEvent;
|
||||||
@@ -189,7 +188,6 @@ public class HoverMenuService extends Service {
|
|||||||
tryInitViews();
|
tryInitViews();
|
||||||
if (mWindowHoverMenu != null)
|
if (mWindowHoverMenu != null)
|
||||||
mWindowHoverMenu.show();
|
mWindowHoverMenu.show();
|
||||||
AccessibilityServiceTool.enableAccessibilityServiceByRootIfNeeded();
|
|
||||||
return START_STICKY;
|
return START_STICKY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,6 +198,8 @@ public class HoverMenuService extends Service {
|
|||||||
if (eventBus.isRegistered(this))
|
if (eventBus.isRegistered(this))
|
||||||
eventBus.unregister(this);
|
eventBus.unregister(this);
|
||||||
setIsRunning(false);
|
setIsRunning(false);
|
||||||
|
if (mWindowViewController == null)
|
||||||
|
return;
|
||||||
mWindowViewController.removeView(mFloatingLayoutBoundsView);
|
mWindowViewController.removeView(mFloatingLayoutBoundsView);
|
||||||
mWindowViewController.removeView(mFloatingLayoutHierarchyView);
|
mWindowViewController.removeView(mFloatingLayoutHierarchyView);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,9 +85,6 @@ public class RecordNavigatorContent implements NavigatorContent, Recorder.OnStat
|
|||||||
ButterKnife.bind(this, mView);
|
ButterKnife.bind(this, mView);
|
||||||
HoverMenuService.getEventBus().register(this);
|
HoverMenuService.getEventBus().register(this);
|
||||||
AccessibilityService.getStickOnKeyObserver().addListener(mVolumeKeyListener);
|
AccessibilityService.getStickOnKeyObserver().addListener(mVolumeKeyListener);
|
||||||
if (Pref.isRecordVolumeControlEnable()) {
|
|
||||||
AutoJs.getInstance().ensureAccessibilityServiceEnabled();
|
|
||||||
}
|
|
||||||
if (Pref.hasRecordTrigger()) {
|
if (Pref.hasRecordTrigger()) {
|
||||||
mKeyObserver = new KeyObserver(mContext);
|
mKeyObserver = new KeyObserver(mContext);
|
||||||
mKeyObserver.startListening();
|
mKeyObserver.startListening();
|
||||||
|
|||||||
@@ -14,10 +14,14 @@ public class ProgressDialog {
|
|||||||
private MaterialDialog mDialog;
|
private MaterialDialog mDialog;
|
||||||
|
|
||||||
public ProgressDialog(Context context) {
|
public ProgressDialog(Context context) {
|
||||||
|
this(context, R.string.text_on_progress);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProgressDialog(Context context, int resId) {
|
||||||
mDialog = new MaterialDialog.Builder(context)
|
mDialog = new MaterialDialog.Builder(context)
|
||||||
.progress(true, 0)
|
.progress(true, 0)
|
||||||
.cancelable(false)
|
.cancelable(false)
|
||||||
.content(R.string.text_on_progress)
|
.content(resId)
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -133,7 +133,12 @@ public class SideMenuFragment extends android.support.v4.app.Fragment {
|
|||||||
AccessibilityServiceTool.goToAccessibilitySetting();
|
AccessibilityServiceTool.goToAccessibilitySetting();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final ProgressDialog progress = new ProgressDialog(getContext());
|
enableAccessibilityServiceByRoot();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void enableAccessibilityServiceByRoot() {
|
||||||
|
final ProgressDialog progress = new ProgressDialog(getContext(), R.string.text_enable_accessibility_service_by_root_ing);
|
||||||
UnderuseExecutors.execute(new Runnable() {
|
UnderuseExecutors.execute(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -156,6 +161,9 @@ public class SideMenuFragment extends android.support.v4.app.Fragment {
|
|||||||
void setFloatingWindowEnable(CompoundButton button, boolean enable) {
|
void setFloatingWindowEnable(CompoundButton button, boolean enable) {
|
||||||
if (enable && !HoverMenuManger.isHoverMenuShowing()) {
|
if (enable && !HoverMenuManger.isHoverMenuShowing()) {
|
||||||
HoverMenuManger.showHoverMenu();
|
HoverMenuManger.showHoverMenu();
|
||||||
|
if (Pref.enableAccessibilityServiceByRoot()) {
|
||||||
|
enableAccessibilityServiceByRoot();
|
||||||
|
}
|
||||||
} else if (!enable && HoverMenuManger.isHoverMenuShowing()) {
|
} else if (!enable && HoverMenuManger.isHoverMenuShowing()) {
|
||||||
HoverMenuManger.hideHoverMenu();
|
HoverMenuManger.hideHoverMenu();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -212,6 +212,7 @@
|
|||||||
<string name="text_enable_accessibitliy_service_by_root_failed">使用root权限开启失败</string>
|
<string name="text_enable_accessibitliy_service_by_root_failed">使用root权限开启失败</string>
|
||||||
<string name="text_on_progress">处理中</string>
|
<string name="text_on_progress">处理中</string>
|
||||||
<string name="text_delete_failed">删除失败</string>
|
<string name="text_delete_failed">删除失败</string>
|
||||||
|
<string name="text_enable_accessibility_service_by_root_ing">正在使用root权限启用无障碍服务</string>
|
||||||
|
|
||||||
|
|
||||||
<string-array name="record_control_keys">
|
<string-array name="record_control_keys">
|
||||||
|
|||||||
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__(android.view.KeyEvent);
|
||||||
__importClass__(com.stardust.autojs.runtime.api.Shell);
|
__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;
|
package com.stardust.autojs.runtime;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.view.accessibility.AccessibilityNodeInfo;
|
import android.view.accessibility.AccessibilityNodeInfo;
|
||||||
|
|
||||||
import com.stardust.view.accessibility.AccessibilityInfoProvider;
|
import com.stardust.view.accessibility.AccessibilityInfoProvider;
|
||||||
import com.stardust.view.accessibility.AccessibilityService;
|
import com.stardust.view.accessibility.AccessibilityService;
|
||||||
|
import com.stardust.view.accessibility.NotificationListener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Stardust on 2017/4/2.
|
* Created by Stardust on 2017/4/2.
|
||||||
@@ -37,6 +39,7 @@ public abstract class AccessibilityBridge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@NonNull
|
||||||
public abstract AccessibilityInfoProvider getInfoProvider();
|
public abstract AccessibilityInfoProvider getInfoProvider();
|
||||||
|
|
||||||
|
|
||||||
@@ -44,4 +47,6 @@ public abstract class AccessibilityBridge {
|
|||||||
mMode = mode;
|
mMode = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public abstract NotificationListener.Observer getNotificationObserver();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,24 @@
|
|||||||
package com.stardust.autojs.runtime.api;
|
package com.stardust.autojs.runtime.api;
|
||||||
|
|
||||||
|
import android.app.Notification;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Point;
|
import android.graphics.Point;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
|
||||||
import android.util.SparseArray;
|
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
|
import android.view.accessibility.AccessibilityEvent;
|
||||||
|
|
||||||
import com.stardust.autojs.runtime.AccessibilityBridge;
|
import com.stardust.autojs.runtime.AccessibilityBridge;
|
||||||
import com.stardust.autojs.runtime.ScriptException;
|
import com.stardust.autojs.runtime.ScriptException;
|
||||||
import com.stardust.autojs.runtime.record.inputevent.TouchObserver;
|
import com.stardust.autojs.runtime.record.inputevent.TouchObserver;
|
||||||
import com.stardust.view.accessibility.AccessibilityService;
|
import com.stardust.view.accessibility.AccessibilityService;
|
||||||
|
import com.stardust.view.accessibility.NotificationListener;
|
||||||
import com.stardust.view.accessibility.OnKeyListener;
|
import com.stardust.view.accessibility.OnKeyListener;
|
||||||
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Stardust on 2017/7/18.
|
* 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_DOWN = "__key_down__#";
|
||||||
private static final String PREFIX_KEY_UP = "__key_up__#";
|
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 boolean mListeningKey = false;
|
||||||
private Loopers mLoopers;
|
private Loopers mLoopers;
|
||||||
private Handler mHandler;
|
private Handler mHandler;
|
||||||
|
private boolean mListeningNotification = false;
|
||||||
|
|
||||||
public Events(Context context, AccessibilityBridge accessibilityBridge, ScriptBridges bridges, Loopers loopers) {
|
public Events(Context context, AccessibilityBridge accessibilityBridge, ScriptBridges bridges, Loopers loopers) {
|
||||||
super(bridges);
|
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() {
|
public void recycle() {
|
||||||
if (mListeningKey) {
|
if (mListeningKey) {
|
||||||
AccessibilityService service = mAccessibilityBridge.getService();
|
AccessibilityService service = mAccessibilityBridge.getService();
|
||||||
@@ -133,6 +152,9 @@ public class Events extends EventEmitter implements OnKeyListener, TouchObserver
|
|||||||
if (mTouchObserver != null) {
|
if (mTouchObserver != null) {
|
||||||
mTouchObserver.stop();
|
mTouchObserver.stop();
|
||||||
}
|
}
|
||||||
|
if (mListeningNotification) {
|
||||||
|
mAccessibilityBridge.getNotificationObserver().removeListener(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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 class TouchRecorder extends InputEventRecorder {
|
||||||
|
|
||||||
public TouchRecorder(Context context) {
|
public TouchRecorder(Context context) {
|
||||||
super(context, new InputEventToSendEventJsConverter());
|
super(context, new InputEventToRootAutomatorConverter());
|
||||||
listen();
|
listen();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
|
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:accessibilityEventTypes="typeAllMask"
|
android:accessibilityEventTypes="typeAllMask"
|
||||||
android:accessibilityFeedbackType="feedbackGeneric"
|
android:accessibilityFeedbackType="feedbackAllMask"
|
||||||
android:accessibilityFlags="flagIncludeNotImportantViews|flagReportViewIds|flagRetrieveInteractiveWindows|flagRequestEnhancedWebAccessibility|flagRequestFilterKeyEvents"
|
android:accessibilityFlags="flagIncludeNotImportantViews|flagReportViewIds|flagRetrieveInteractiveWindows|flagRequestEnhancedWebAccessibility|flagRequestFilterKeyEvents"
|
||||||
android:canPerformGestures="true"
|
android:canPerformGestures="true"
|
||||||
android:canRequestEnhancedWebAccessibility="true"
|
android:canRequestEnhancedWebAccessibility="true"
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
package com.stardust.view.accessibility;
|
||||||
|
|
||||||
|
import android.accessibilityservice.AccessibilityService;
|
||||||
|
import android.app.Notification;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.accessibility.AccessibilityEvent;
|
||||||
|
|
||||||
|
import com.stardust.util.ArrayUtils;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Stardust on 2017/8/1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public interface NotificationListener {
|
||||||
|
|
||||||
|
void onNotification(AccessibilityEvent event, String[] notification);
|
||||||
|
|
||||||
|
void onNotification(AccessibilityEvent event, Notification notification);
|
||||||
|
|
||||||
|
class Observer implements NotificationListener, AccessibilityDelegate {
|
||||||
|
|
||||||
|
private static final Set<Integer> EVENT_TYPES = Collections.singleton(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
|
||||||
|
|
||||||
|
private static final String TAG = "NotificationObserver";
|
||||||
|
private static final String[] EMPTY = new String[0];
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
private CopyOnWriteArrayList<NotificationListener> mNotificationListeners = new CopyOnWriteArrayList<>();
|
||||||
|
|
||||||
|
public Observer(Context context) {
|
||||||
|
mContext = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNotification(AccessibilityEvent event, String[] notification) {
|
||||||
|
for (NotificationListener listener : mNotificationListeners) {
|
||||||
|
try {
|
||||||
|
listener.onNotification(event, notification);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Error onNotification: " + Arrays.toString(notification) + " Listener: " + listener, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNotification(AccessibilityEvent event, Notification notification) {
|
||||||
|
for (NotificationListener listener : mNotificationListeners) {
|
||||||
|
try {
|
||||||
|
listener.onNotification(event, notification);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Error onNotification: " + notification + " Listener: " + listener, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addListener(NotificationListener listener) {
|
||||||
|
mNotificationListeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean removeListener(NotificationListener listener) {
|
||||||
|
return mNotificationListeners.remove(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onAccessibilityEvent(AccessibilityService service, AccessibilityEvent event) {
|
||||||
|
if (event.getParcelableData() instanceof Notification) {
|
||||||
|
Notification notification = (Notification) event.getParcelableData();
|
||||||
|
Log.d(TAG, "onNotification: " + notification + "; " + event);
|
||||||
|
onNotification(event, notification);
|
||||||
|
} else {
|
||||||
|
List<CharSequence> list = event.getText();
|
||||||
|
Log.d(TAG, "onNotification: " + list + "; " + event);
|
||||||
|
if (event.getPackageName().equals(mContext.getPackageName())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (list != null) {
|
||||||
|
onNotification(event, ArrayUtils.toStringArray(list));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Set<Integer> getEventTypes() {
|
||||||
|
return EVENT_TYPES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
package com.stardust.util;
|
package com.stardust.util;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Stardust on 2017/5/8.
|
* Created by Stardust on 2017/5/8.
|
||||||
*/
|
*/
|
||||||
@@ -23,4 +25,13 @@ public class ArrayUtils {
|
|||||||
}
|
}
|
||||||
return unbox;
|
return unbox;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String[] toStringArray(List<?> list) {
|
||||||
|
int i = 0;
|
||||||
|
String[] str = new String[list.size()];
|
||||||
|
for (Object o : list) {
|
||||||
|
str[i] = o == null ? null : o.toString();
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user