add events module, including EventEmiiter, KeyEvent, TouchEvent
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
### sleep(n)
|
||||
### sleep(\[n\])
|
||||
* n \<Number\> 毫秒数
|
||||
|
||||
暂停运行n**毫秒**的时间。1秒等于1000毫秒。
|
||||
如果不加参数n,则会一直暂停,通常用于有事件监听的脚本中使用。
|
||||
|
||||
### launchPackage(packageName)
|
||||
* packageName \<String\> 应用包名。参见《Shell命令:应用包名》章节。
|
||||
|
||||
20
app/src/main/assets/help/documentation/事件与按键监听.md
Normal file
20
app/src/main/assets/help/documentation/事件与按键监听.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# events
|
||||
|
||||
events也是一个\[EventEmitter\],这里只介绍其自身的函数。
|
||||
|
||||
### events.emitter()
|
||||
|
||||
返回一个新的EventEmitter。
|
||||
|
||||
### events.observeKey()
|
||||
|
||||
启用按键监听,例如音量键、Home键。
|
||||
|
||||
在安卓4.3以上才能使用。
|
||||
|
||||
### events.onKeyDown(keyName, listener)
|
||||
|
||||
* keyName \<String\> 要监听的按键名称
|
||||
* listener \<Function\> 参数为一个\[KeyEvent\]
|
||||
|
||||
注册一个按键监听函数,。按键名称包括
|
||||
@@ -62,7 +62,7 @@ function isImage(item){
|
||||
function notLiked(likeIcon){
|
||||
var x = likeIcon.bounds().centerX();
|
||||
var y = likeIcon.bounds().centerY();
|
||||
return images.detectsColor(capture, x, y, 0x767886);
|
||||
return images.detectsColor(capture, 0x767886, x, y);
|
||||
}
|
||||
|
||||
toast("请打开QQ空间并慢慢下滑");
|
||||
|
||||
@@ -5,6 +5,7 @@ import android.app.Application;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Bundle;
|
||||
import android.support.multidex.MultiDexApplication;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
import com.squareup.leakcanary.LeakCanary;
|
||||
import com.stardust.app.SimpleActivityLifecycleCallbacks;
|
||||
@@ -19,6 +20,8 @@ import com.stardust.theme.ThemeColor;
|
||||
import com.stardust.theme.ThemeColorManager;
|
||||
import com.stardust.util.ScreenMetrics;
|
||||
import com.stardust.util.UiHandler;
|
||||
import com.stardust.view.accessibility.AccessibilityService;
|
||||
import com.stardust.view.accessibility.OnKeyListener;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
@@ -71,7 +74,7 @@ public class App extends MultiDexApplication {
|
||||
}
|
||||
|
||||
private void initVolumeChangeObserver() {
|
||||
registerReceiver(mVolumeChangeObserver, new IntentFilter(VolumeChangeObserver.ACTION_VOLUME_CHANGE));
|
||||
//registerReceiver(mVolumeChangeObserver, new IntentFilter(VolumeChangeObserver.ACTION_VOLUME_CHANGE));
|
||||
mVolumeChangeObserver.addOnVolumeChangeListener(new VolumeChangeObserver.OnVolumeChangeListener() {
|
||||
@Override
|
||||
public void onVolumeChange() {
|
||||
@@ -80,6 +83,14 @@ public class App extends MultiDexApplication {
|
||||
}
|
||||
}
|
||||
});
|
||||
AccessibilityService.getStickOnKeyObserver().addListener(new OnKeyListener() {
|
||||
@Override
|
||||
public void onKeyEvent(int keyCode, KeyEvent event) {
|
||||
if (keyCode == KeyEvent.KEYCODE_VOLUME_UP && Pref.isRunningVolumeControlEnabled()) {
|
||||
AutoJs.getInstance().getScriptEngineService().stopAllAndToast();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -32,12 +32,12 @@ import com.stardust.util.ScreenMetrics;
|
||||
import com.stardust.util.Supplier;
|
||||
import com.stardust.util.UiHandler;
|
||||
import com.stardust.view.accessibility.AccessibilityInfoProvider;
|
||||
import com.stardust.scriptdroid.external.floatingwindow.menu.layout_inspector.LayoutInspector;
|
||||
import com.stardust.scriptdroid.external.floatingwindow.menu.record.accessibility.AccessibilityActionRecorder;
|
||||
import com.stardust.autojs.runtime.record.accessibility.AccessibilityActionRecorder;
|
||||
import com.stardust.view.accessibility.AccessibilityService;
|
||||
import com.stardust.scriptdroid.tool.AccessibilityServiceTool;
|
||||
import com.stardust.scriptdroid.ui.console.JraskaConsole;
|
||||
import com.stardust.view.accessibility.AccessibilityServiceUtils;
|
||||
import com.stardust.view.accessibility.LayoutInspector;
|
||||
|
||||
|
||||
/**
|
||||
@@ -177,7 +177,7 @@ public class AutoJs implements AccessibilityBridge {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public android.accessibilityservice.AccessibilityService getService() {
|
||||
public AccessibilityService getService() {
|
||||
return AccessibilityService.getInstance();
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ import com.stardust.hover.SimpleHoverMenuTransitionListener;
|
||||
import com.stardust.hover.WindowHoverMenu;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.autojs.AutoJs;
|
||||
import com.stardust.scriptdroid.external.floatingwindow.menu.layout_inspector.NodeInfo;
|
||||
import com.stardust.view.accessibility.NodeInfo;
|
||||
import com.stardust.scriptdroid.external.floatingwindow.menu.view.FloatingLayoutBoundsView;
|
||||
import com.stardust.scriptdroid.external.floatingwindow.menu.view.FloatingLayoutHierarchyView;
|
||||
import com.stardust.scriptdroid.tool.AccessibilityServiceTool;
|
||||
|
||||
@@ -12,12 +12,12 @@ import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.autojs.AutoJs;
|
||||
import com.stardust.scriptdroid.external.floatingwindow.menu.HoverMenuService;
|
||||
import com.stardust.scriptdroid.external.floatingwindow.menu.layout_inspector.LayoutInspector;
|
||||
import com.stardust.scriptdroid.tool.AccessibilityServiceTool;
|
||||
import com.stardust.scriptdroid.ui.main.MainActivity_;
|
||||
import com.stardust.util.ClipboardUtil;
|
||||
import com.stardust.util.MessageEvent;
|
||||
import com.stardust.view.accessibility.AccessibilityService;
|
||||
import com.stardust.view.accessibility.LayoutInspector;
|
||||
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
|
||||
|
||||
@@ -10,16 +10,16 @@ import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.stardust.app.VolumeChangeObserver;
|
||||
import com.stardust.autojs.runtime.record.Recorder;
|
||||
import com.stardust.autojs.runtime.record.accessibility.AccessibilityActionRecorder;
|
||||
import com.stardust.autojs.runtime.record.inputevent.KeyObserver;
|
||||
import com.stardust.autojs.runtime.record.inputevent.TouchRecorder;
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.Pref;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.accessibility.AccessibilityEventHelper;
|
||||
import com.stardust.scriptdroid.autojs.AutoJs;
|
||||
import com.stardust.scriptdroid.external.floatingwindow.menu.HoverMenuService;
|
||||
import com.stardust.scriptdroid.external.floatingwindow.menu.record.Recorder;
|
||||
import com.stardust.scriptdroid.external.floatingwindow.menu.record.accessibility.AccessibilityActionRecorder;
|
||||
import com.stardust.scriptdroid.external.floatingwindow.menu.record.inputevent.KeyObserver;
|
||||
import com.stardust.scriptdroid.external.floatingwindow.menu.record.inputevent.TouchRecorder;
|
||||
import com.stardust.scriptdroid.ui.main.MainActivity;
|
||||
import com.stardust.util.MessageEvent;
|
||||
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
package com.stardust.scriptdroid.external.floatingwindow.menu.layout_inspector;
|
||||
|
||||
import android.os.Build;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.util.Log;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.view.accessibility.AccessibilityService;
|
||||
import com.stardust.util.UnderuseExecutors;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/10.
|
||||
*/
|
||||
|
||||
public class LayoutInspector {
|
||||
|
||||
private static final String LOG_TAG = LayoutInspector.class.getSimpleName();
|
||||
private volatile NodeInfo mCapture;
|
||||
private volatile boolean mDumping = false;
|
||||
private Executor mExecutor = Executors.newSingleThreadExecutor();
|
||||
|
||||
public void captureCurrentWindow() {
|
||||
AccessibilityService service = AccessibilityService.getInstance();
|
||||
if (service == null) {
|
||||
Log.d(LOG_TAG, "captureCurrentWindow: service = null");
|
||||
mCapture = null;
|
||||
} else {
|
||||
final AccessibilityNodeInfo root = service.getRootInActiveWindow();
|
||||
if (root == null) {
|
||||
Log.d(LOG_TAG, "captureCurrentWindow: root = null");
|
||||
mCapture = null;
|
||||
} else {
|
||||
mExecutor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mDumping = true;
|
||||
mCapture = NodeInfo.capture(root);
|
||||
mDumping = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
|
||||
private void refreshChildList(AccessibilityNodeInfo root) {
|
||||
if (root == null)
|
||||
return;
|
||||
root.refresh();
|
||||
int childCount = root.getChildCount();
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
refreshChildList(root.getChild(i));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isDumping() {
|
||||
return mDumping;
|
||||
}
|
||||
|
||||
public void clearCapture() {
|
||||
mCapture = null;
|
||||
}
|
||||
|
||||
public NodeInfo getCapture() {
|
||||
return mCapture;
|
||||
}
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
package com.stardust.scriptdroid.external.floatingwindow.menu.layout_inspector;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.support.annotation.Keep;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.automator.UiObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/10.
|
||||
*/
|
||||
@Keep
|
||||
public class NodeInfo {
|
||||
|
||||
private List<NodeInfo> children = new ArrayList<>();
|
||||
private Rect mBoundsInScreen;
|
||||
|
||||
public String id;
|
||||
public CharSequence desc;
|
||||
public CharSequence className;
|
||||
public CharSequence packageName;
|
||||
public CharSequence text;
|
||||
public int drawingOrder;
|
||||
public boolean accessibilityFocused;
|
||||
public boolean checked;
|
||||
public boolean clickable;
|
||||
public boolean contextClickable;
|
||||
public boolean dismissable;
|
||||
public boolean editable;
|
||||
public boolean enabled;
|
||||
public boolean focusable;
|
||||
public boolean longClickable;
|
||||
public boolean selected;
|
||||
public boolean scrollable;
|
||||
public String bounds;
|
||||
|
||||
|
||||
public NodeInfo(AccessibilityNodeInfoCompat node) {
|
||||
id = simplifyId(node.getViewIdResourceName());
|
||||
desc = node.getContentDescription();
|
||||
className = node.getClassName();
|
||||
packageName = node.getPackageName();
|
||||
text = node.getText();
|
||||
|
||||
drawingOrder = node.getDrawingOrder();
|
||||
|
||||
accessibilityFocused = node.isAccessibilityFocused();
|
||||
checked = node.isChecked();
|
||||
clickable = node.isClickable();
|
||||
contextClickable = node.isContextClickable();
|
||||
dismissable = node.isDismissable();
|
||||
enabled = node.isEnabled();
|
||||
editable = node.isEditable();
|
||||
focusable = node.isFocusable();
|
||||
longClickable = node.isLongClickable();
|
||||
selected = node.isSelected();
|
||||
scrollable = node.isScrollable();
|
||||
mBoundsInScreen = new Rect();
|
||||
node.getBoundsInScreen(mBoundsInScreen);
|
||||
bounds = boundsToString(mBoundsInScreen);
|
||||
}
|
||||
|
||||
private String simplifyId(String idResourceName) {
|
||||
if (idResourceName == null)
|
||||
return null;
|
||||
int i = idResourceName.indexOf('/');
|
||||
return idResourceName.substring(i + 1);
|
||||
}
|
||||
|
||||
public Rect getBoundsInScreen() {
|
||||
return mBoundsInScreen;
|
||||
}
|
||||
|
||||
public static String boundsToString(Rect rect) {
|
||||
return rect.toString().replace('-', ',').replace(" ", "").substring(4);
|
||||
}
|
||||
|
||||
public NodeInfo(AccessibilityNodeInfo node) {
|
||||
this(new AccessibilityNodeInfoCompat(node));
|
||||
}
|
||||
|
||||
|
||||
public static NodeInfo capture(@NonNull UiObject root) {
|
||||
NodeInfo nodeInfo = new NodeInfo(root);
|
||||
int childCount = root.getChildCount();
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
UiObject child = root.child(i);
|
||||
if (child != null) {
|
||||
nodeInfo.children.add(capture(child));
|
||||
}
|
||||
}
|
||||
return nodeInfo;
|
||||
}
|
||||
|
||||
public static NodeInfo capture(@NonNull AccessibilityNodeInfo root) {
|
||||
UiObject r = UiObject.createRoot(root);
|
||||
return capture(r);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public List<NodeInfo> getChildren() {
|
||||
return children;
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import com.stardust.scriptdroid.external.floatingwindow.menu.layout_inspector.NodeInfo;
|
||||
import com.stardust.view.accessibility.NodeInfo;
|
||||
import com.stardust.util.ViewUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -14,7 +14,7 @@ import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.external.floatingwindow.menu.layout_inspector.NodeInfo;
|
||||
import com.stardust.view.accessibility.NodeInfo;
|
||||
import com.stardust.util.ViewUtil;
|
||||
import com.stardust.widget.LevelBeamView;
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.external.floatingwindow.menu.layout_inspector.NodeInfo;
|
||||
import com.stardust.view.accessibility.NodeInfo;
|
||||
import com.stardust.util.ClipboardUtil;
|
||||
import com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration;
|
||||
|
||||
@@ -22,7 +22,6 @@ import java.util.Arrays;
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.OnClick;
|
||||
import butterknife.OnLongClick;
|
||||
import butterknife.Optional;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.stardust.scriptdroid.external.floatingwindow.menu.layout_inspector.view;
|
||||
|
||||
import com.stardust.scriptdroid.external.floatingwindow.menu.layout_inspector.NodeInfo;
|
||||
import com.stardust.view.accessibility.NodeInfo;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/10.
|
||||
|
||||
@@ -1,175 +0,0 @@
|
||||
package com.stardust.scriptdroid.external.floatingwindow.menu.record;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/16.
|
||||
*/
|
||||
|
||||
public interface Recorder {
|
||||
|
||||
interface OnStateChangedListener {
|
||||
|
||||
void onStart();
|
||||
|
||||
void onStop();
|
||||
|
||||
void onPause();
|
||||
|
||||
void onResume();
|
||||
|
||||
}
|
||||
|
||||
class StateChangeEvent {
|
||||
|
||||
private int mOldState;
|
||||
private int mCurrentState;
|
||||
|
||||
public StateChangeEvent(int oldState, int currentState) {
|
||||
mOldState = oldState;
|
||||
mCurrentState = currentState;
|
||||
}
|
||||
|
||||
public int getOldState() {
|
||||
return mOldState;
|
||||
}
|
||||
|
||||
public int getCurrentState() {
|
||||
return mCurrentState;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int STATE_NOT_START = 0;
|
||||
int STATE_RECORDING = 1;
|
||||
int STATE_PAUSED = 2;
|
||||
int STATE_STOPPED = 3;
|
||||
|
||||
void start();
|
||||
|
||||
void stop();
|
||||
|
||||
void pause();
|
||||
|
||||
void resume();
|
||||
|
||||
String getCode();
|
||||
|
||||
int getState();
|
||||
|
||||
void setOnStateChangedListener(OnStateChangedListener onStateChangedListener);
|
||||
|
||||
abstract class AbstractRecorder implements Recorder {
|
||||
|
||||
private static final OnStateChangedListener NO_OPERATION_LISTENER = new OnStateChangedListener() {
|
||||
@Override
|
||||
public void onStart() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
private OnStateChangedListener mOnStateChangedListener = NO_OPERATION_LISTENER;
|
||||
|
||||
private final boolean mSync;
|
||||
private int mState = STATE_NOT_START;
|
||||
|
||||
public AbstractRecorder(boolean syncOfState) {
|
||||
mSync = syncOfState;
|
||||
}
|
||||
|
||||
public AbstractRecorder() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
public void start() {
|
||||
ensureIsStateOf(STATE_NOT_START);
|
||||
setState(STATE_RECORDING);
|
||||
startImpl();
|
||||
mOnStateChangedListener.onStart();
|
||||
}
|
||||
|
||||
|
||||
private void ensureIsStateOf(int... expectedStates) {
|
||||
for (int expectedState : expectedStates) {
|
||||
if (mState == expectedState)
|
||||
return;
|
||||
}
|
||||
throw new IllegalStateException("expected=" + Arrays.toString(expectedStates) + " state=" + mState);
|
||||
}
|
||||
|
||||
|
||||
protected abstract void startImpl();
|
||||
|
||||
public void stop() {
|
||||
ensureIsStateOf(STATE_RECORDING, STATE_PAUSED);
|
||||
setState(STATE_STOPPED);
|
||||
stopImpl();
|
||||
mOnStateChangedListener.onStop();
|
||||
}
|
||||
|
||||
protected abstract void stopImpl();
|
||||
|
||||
public void pause() {
|
||||
ensureIsStateOf(STATE_RECORDING);
|
||||
setState(STATE_PAUSED);
|
||||
pauseImpl();
|
||||
mOnStateChangedListener.onPause();
|
||||
}
|
||||
|
||||
protected synchronized void setState(int state) {
|
||||
if (mSync) {
|
||||
synchronized (this) {
|
||||
mState = state;
|
||||
}
|
||||
} else {
|
||||
mState = state;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized int getState() {
|
||||
if (mSync) {
|
||||
synchronized (this) {
|
||||
return mState;
|
||||
}
|
||||
} else {
|
||||
return mState;
|
||||
}
|
||||
}
|
||||
|
||||
protected void pauseImpl() {
|
||||
|
||||
}
|
||||
|
||||
public void resume() {
|
||||
ensureIsStateOf(STATE_PAUSED);
|
||||
setState(STATE_RECORDING);
|
||||
resumeImpl();
|
||||
mOnStateChangedListener.onResume();
|
||||
}
|
||||
|
||||
protected void resumeImpl() {
|
||||
|
||||
}
|
||||
|
||||
public void setOnStateChangedListener(OnStateChangedListener onStateChangedListener) {
|
||||
mOnStateChangedListener = onStateChangedListener == null ? NO_OPERATION_LISTENER : onStateChangedListener;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
package com.stardust.scriptdroid.external.floatingwindow.menu.record.accessibility;
|
||||
|
||||
import android.accessibilityservice.AccessibilityService;
|
||||
import android.os.Build;
|
||||
import android.util.SparseArray;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.automator.UiObject;
|
||||
import com.stardust.automator.simple_action.FilterAction;
|
||||
import com.stardust.scriptdroid.external.floatingwindow.menu.layout_inspector.NodeInfo;
|
||||
import com.stardust.util.SparseArrayEntries;
|
||||
import com.stardust.view.accessibility.AccessibilityNodeInfoHelper;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/2/14.
|
||||
*/
|
||||
|
||||
public class AccessibilityActionConverter {
|
||||
|
||||
private static final SparseArray<EventToScriptConverter> CONVERTER_MAP = new SparseArrayEntries<EventToScriptConverter>()
|
||||
.entry(AccessibilityEvent.TYPE_VIEW_CLICKED, new DoUtilSucceedConverter("click"))
|
||||
.entry(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED, new DoUtilSucceedConverter("longClick"))
|
||||
.entry(AccessibilityEvent.TYPE_VIEW_SCROLLED, new DoOnceConverter("//scroll???"))
|
||||
.entry(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED, new SetTextEventConverter())
|
||||
.sparseArray();
|
||||
|
||||
static {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
CONVERTER_MAP.put(AccessibilityEvent.TYPE_VIEW_CONTEXT_CLICKED, new DoOnceConverter("contextClick"));
|
||||
}
|
||||
}
|
||||
|
||||
private StringBuilder mScript = new StringBuilder();
|
||||
private boolean mFirstAction = true;
|
||||
|
||||
public AccessibilityActionConverter(boolean shouldIgnoreFirstAction) {
|
||||
mShouldIgnoreFirstAction = shouldIgnoreFirstAction;
|
||||
}
|
||||
|
||||
private boolean mShouldIgnoreFirstAction = false;
|
||||
|
||||
public void record(AccessibilityService service, AccessibilityEvent event) {
|
||||
EventToScriptConverter converter = CONVERTER_MAP.get(event.getEventType());
|
||||
if (converter != null) {
|
||||
if (mFirstAction && mShouldIgnoreFirstAction) {
|
||||
mFirstAction = false;
|
||||
return;
|
||||
}
|
||||
converter.onAccessibilityEvent(service, event, mScript);
|
||||
mScript.append("\n");
|
||||
EventBus.getDefault().post(new AccessibilityActionRecorder.AccessibilityActionRecordEvent(event));
|
||||
}
|
||||
}
|
||||
|
||||
public String getScript() {
|
||||
return mScript.toString();
|
||||
}
|
||||
|
||||
public void onResume() {
|
||||
mFirstAction = true;
|
||||
}
|
||||
|
||||
interface EventToScriptConverter {
|
||||
|
||||
void onAccessibilityEvent(AccessibilityService service, AccessibilityEvent event, StringBuilder sb);
|
||||
}
|
||||
|
||||
private static abstract class BoundsEventConverter implements EventToScriptConverter {
|
||||
|
||||
@Override
|
||||
public void onAccessibilityEvent(AccessibilityService service, AccessibilityEvent event, StringBuilder sb) {
|
||||
AccessibilityNodeInfo source = event.getSource();
|
||||
if (source == null)
|
||||
return;
|
||||
String bounds = NodeInfo.boundsToString(AccessibilityNodeInfoHelper.getBoundsInScreen(source));
|
||||
source.recycle();
|
||||
onAccessibilityEvent(event, bounds, sb);
|
||||
}
|
||||
|
||||
protected abstract void onAccessibilityEvent(AccessibilityEvent event, String bounds, StringBuilder sb);
|
||||
|
||||
}
|
||||
|
||||
private static class DoOnceConverter extends BoundsEventConverter {
|
||||
|
||||
private String mActionFunction;
|
||||
|
||||
DoOnceConverter(String actionFunction) {
|
||||
mActionFunction = actionFunction;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAccessibilityEvent(AccessibilityEvent event, String bounds, StringBuilder sb) {
|
||||
sb.append(mActionFunction).append(bounds).append(";");
|
||||
}
|
||||
}
|
||||
|
||||
private static class DoUtilSucceedConverter extends BoundsEventConverter {
|
||||
|
||||
private String mActionFunction;
|
||||
|
||||
DoUtilSucceedConverter(String actionFunction) {
|
||||
mActionFunction = actionFunction;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAccessibilityEvent(AccessibilityEvent event, String bounds, StringBuilder sb) {
|
||||
sb.append("while(!").append(mActionFunction).append(bounds).append(");");
|
||||
}
|
||||
}
|
||||
|
||||
private static class SetTextEventConverter implements EventToScriptConverter {
|
||||
|
||||
@Override
|
||||
public void onAccessibilityEvent(AccessibilityService service, AccessibilityEvent event, StringBuilder sb) {
|
||||
AccessibilityNodeInfo source = event.getSource();
|
||||
if (source == null)
|
||||
return;
|
||||
UiObject uiObject = UiObject.createRoot(service.getRootInActiveWindow());
|
||||
List<UiObject> editableList = FilterAction.EditableFilter.findEditable(uiObject);
|
||||
int i = findInEditableList(editableList, source);
|
||||
sb.append("while(!input(").append(i).append(", \"").append(source.getText()).append("\"));");
|
||||
source.recycle();
|
||||
}
|
||||
|
||||
private static int findInEditableList(List<UiObject> editableList, AccessibilityNodeInfo editable) {
|
||||
int i = 0;
|
||||
for (UiObject nodeInfo : editableList) {
|
||||
if (AccessibilityNodeInfoHelper.getBoundsInScreen(nodeInfo).equals(AccessibilityNodeInfoHelper.getBoundsInScreen(editable))) {
|
||||
return i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
package com.stardust.scriptdroid.external.floatingwindow.menu.record.accessibility;
|
||||
|
||||
import android.accessibilityservice.AccessibilityService;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
|
||||
import com.stardust.scriptdroid.external.floatingwindow.menu.record.Recorder;
|
||||
import com.stardust.view.accessibility.AccessibilityDelegate;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/2/14.
|
||||
*/
|
||||
|
||||
public class AccessibilityActionRecorder extends Recorder.AbstractRecorder implements AccessibilityDelegate {
|
||||
|
||||
public static class AccessibilityActionRecordEvent {
|
||||
|
||||
private final AccessibilityEvent mAccessibilityEvent;
|
||||
|
||||
public AccessibilityActionRecordEvent(AccessibilityEvent event) {
|
||||
mAccessibilityEvent = event;
|
||||
}
|
||||
|
||||
public AccessibilityEvent getAccessibilityEvent() {
|
||||
return mAccessibilityEvent;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Set<Integer> EVENT_TYPES = new HashSet<>(Arrays.asList(AccessibilityEvent.TYPE_VIEW_CLICKED, AccessibilityEvent.TYPE_VIEW_LONG_CLICKED, AccessibilityEvent.TYPE_VIEW_SCROLLED, AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED));
|
||||
|
||||
private static final long RECORD_TIME_OUT = 10 * 60 * 1000;
|
||||
|
||||
private boolean mShouldIgnoreFirstAction = false;
|
||||
|
||||
|
||||
private AccessibilityActionConverter mConverter;
|
||||
private long mRecordStartMillis;
|
||||
|
||||
public AccessibilityActionRecorder() {
|
||||
super(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startImpl() {
|
||||
mConverter = new AccessibilityActionConverter(mShouldIgnoreFirstAction);
|
||||
mRecordStartMillis = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void stopImpl() {
|
||||
setState(STATE_NOT_START);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void resumeImpl() {
|
||||
mConverter.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onAccessibilityEvent(AccessibilityService service, AccessibilityEvent event) {
|
||||
if (getState() == STATE_RECORDING) {
|
||||
mConverter.record(service, event);
|
||||
checkTimeOut();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Integer> getEventTypes() {
|
||||
return EVENT_TYPES;
|
||||
}
|
||||
|
||||
private void checkTimeOut() {
|
||||
if (System.currentTimeMillis() - mRecordStartMillis > RECORD_TIME_OUT) {
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return mConverter.getScript();
|
||||
}
|
||||
|
||||
public void setShouldIgnoreFirstAction(boolean shouldIgnoreFirstAction) {
|
||||
mShouldIgnoreFirstAction = shouldIgnoreFirstAction;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package com.stardust.scriptdroid.external.floatingwindow.menu.record.inputevent;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/7.
|
||||
*/
|
||||
|
||||
public class EventFormatException extends RuntimeException {
|
||||
|
||||
|
||||
public static EventFormatException forEventStr(String eventStr, NumberFormatException e) {
|
||||
return new EventFormatException(eventStr, e);
|
||||
}
|
||||
|
||||
public EventFormatException(Exception e) {
|
||||
super(e);
|
||||
}
|
||||
|
||||
public EventFormatException(String eventStr, Exception e) {
|
||||
super("eventStr=" + eventStr, e);
|
||||
}
|
||||
|
||||
public EventFormatException(String eventStr) {
|
||||
super("eventStr=" + eventStr);
|
||||
}
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
package com.stardust.scriptdroid.external.floatingwindow.menu.record.inputevent;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.text.TextUtils;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.flurry.android.FlurryAgent;
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.external.floatingwindow.menu.record.Recorder;
|
||||
import com.stardust.util.MapEntries;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/7.
|
||||
*/
|
||||
|
||||
public abstract class InputEventConverter {
|
||||
|
||||
static class Event {
|
||||
|
||||
static final Pattern PATTERN = Pattern.compile("^\\[([^\\]]*)\\]\\s+([^:]*):\\s+([^\\s]*)\\s+([^\\s]*)\\s+([^\\s]*)\\s*$");
|
||||
|
||||
static Event parseEvent(String eventStr) {
|
||||
Matcher matcher = Event.PATTERN.matcher(eventStr);
|
||||
if (!matcher.matches()) {
|
||||
throw new EventFormatException(eventStr);
|
||||
}
|
||||
double time;
|
||||
try {
|
||||
time = Double.parseDouble(matcher.group(1));
|
||||
} catch (NumberFormatException e) {
|
||||
throw new EventFormatException(eventStr, e);
|
||||
}
|
||||
return new Event(time, matcher.group(2), matcher.group(3), matcher.group(4), matcher.group(5));
|
||||
}
|
||||
|
||||
|
||||
double time;
|
||||
String device;
|
||||
String type;
|
||||
String code;
|
||||
String value;
|
||||
|
||||
public Event(double time, String device, String type, String code, String value) {
|
||||
this.time = time;
|
||||
this.device = device;
|
||||
this.type = type;
|
||||
this.code = code;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Event{" +
|
||||
"time=" + time +
|
||||
", device='" + device + '\'' +
|
||||
", type='" + type + '\'' +
|
||||
", code='" + code + '\'' +
|
||||
", value='" + value + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected boolean mConverting = false;
|
||||
private int mState = Recorder.STATE_NOT_START;
|
||||
|
||||
public void convertEventIfFormatCorrect(String eventStr) {
|
||||
if (!mConverting)
|
||||
return;
|
||||
if (TextUtils.isEmpty(eventStr) || !eventStr.startsWith("["))
|
||||
return;
|
||||
Event event = parseEventOrNull(eventStr);
|
||||
if (event != null) {
|
||||
convertEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void convertEvent(@NonNull Event event);
|
||||
|
||||
public String getGetEventCommand() {
|
||||
return "getevent -t -l";
|
||||
}
|
||||
|
||||
|
||||
public void start() {
|
||||
mConverting = true;
|
||||
mState = Recorder.STATE_RECORDING;
|
||||
}
|
||||
|
||||
public void resume() {
|
||||
mConverting = true;
|
||||
mState = Recorder.STATE_RECORDING;
|
||||
}
|
||||
|
||||
public void pause() {
|
||||
mConverting = false;
|
||||
mState = Recorder.STATE_PAUSED;
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
mConverting = false;
|
||||
mState = Recorder.STATE_STOPPED;
|
||||
}
|
||||
|
||||
public abstract String getCode();
|
||||
|
||||
private boolean mFirstEventFormatError = true;
|
||||
|
||||
public Event parseEventOrNull(String eventStr) {
|
||||
try {
|
||||
return Event.parseEvent(eventStr);
|
||||
} catch (EventFormatException e) {
|
||||
e.printStackTrace();
|
||||
if (mFirstEventFormatError) {
|
||||
Toast.makeText(App.getApp(), R.string.text_record_format_error, Toast.LENGTH_SHORT).show();
|
||||
mFirstEventFormatError = false;
|
||||
FlurryAgent.logEvent("EventFormatException", new MapEntries<String, String>()
|
||||
.entry("message", e.getMessage())
|
||||
.map());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
package com.stardust.scriptdroid.external.floatingwindow.menu.record.inputevent;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.stardust.autojs.runtime.api.Shell;
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.external.floatingwindow.menu.record.Recorder;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/6.
|
||||
*/
|
||||
|
||||
public class InputEventRecorder extends Recorder.AbstractRecorder {
|
||||
|
||||
private static final String TAG = "InputEventRecorder";
|
||||
private String mGetEventCommand;
|
||||
private Shell mShell;
|
||||
protected InputEventConverter mInputEventConverter;
|
||||
private Context mContext;
|
||||
|
||||
|
||||
protected InputEventRecorder(Context context, InputEventConverter inputEventConverter) {
|
||||
mGetEventCommand = inputEventConverter.getGetEventCommand();
|
||||
mInputEventConverter = inputEventConverter;
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
public void listen() {
|
||||
mShell = new Shell(mContext, true);
|
||||
mShell.setCallback(new Shell.SimpleCallback() {
|
||||
@Override
|
||||
public void onNewLine(String str) {
|
||||
if (mShell.isInitialized()) {
|
||||
convertEvent(str);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitialized() {
|
||||
mShell.exec(mGetEventCommand);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInterrupted(InterruptedException e) {
|
||||
stop();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startImpl() {
|
||||
mInputEventConverter.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void pauseImpl() {
|
||||
mInputEventConverter.pause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void resumeImpl() {
|
||||
mInputEventConverter.resume();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void stopImpl() {
|
||||
mShell.exit();
|
||||
mInputEventConverter.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return mInputEventConverter.getCode();
|
||||
}
|
||||
|
||||
protected void convertEvent(String eventStr) {
|
||||
mInputEventConverter.convertEventIfFormatCorrect(eventStr);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
package com.stardust.scriptdroid.external.floatingwindow.menu.record.inputevent;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import com.stardust.util.MapEntries;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/7.
|
||||
*/
|
||||
|
||||
public class InputEventToJsConverter extends InputEventConverter {
|
||||
|
||||
interface EventHandler {
|
||||
void handle(Event event);
|
||||
}
|
||||
|
||||
abstract static class Router implements EventHandler {
|
||||
|
||||
private Map<String, EventHandler> mEventHandlerMap = new HashMap<>();
|
||||
|
||||
Router put(String key, EventHandler handler) {
|
||||
mEventHandlerMap.put(key, handler);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Event event) {
|
||||
EventHandler handler = mEventHandlerMap.get(getKey(event));
|
||||
if (handler != null) {
|
||||
handler.handle(event);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract String getKey(Event event);
|
||||
}
|
||||
|
||||
private class TypeRouter extends Router {
|
||||
|
||||
TypeRouter() {
|
||||
put("EV_ABS", new AbsHandler());
|
||||
put("EV_SYN", new SyncHandler());
|
||||
put("EV_KEY", new KeyHandler());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getKey(Event event) {
|
||||
return event.type;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Point {
|
||||
int x, y;
|
||||
}
|
||||
|
||||
private class AbsHandler implements EventHandler {
|
||||
|
||||
@Override
|
||||
public void handle(Event event) {
|
||||
if (event.code.equals("ABS_MT_POSITION_X")) {
|
||||
mTouchPoint.x = Integer.parseInt(event.value, 16);
|
||||
mTouchTime = event.time;
|
||||
} else if (event.code.equals("ABS_MT_POSITION_Y")) {
|
||||
mTouchPoint.y = Integer.parseInt(event.value, 16);
|
||||
mTouchTime = event.time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class SyncHandler implements EventHandler {
|
||||
|
||||
@Override
|
||||
public void handle(Event event) {
|
||||
if (mTouchDown) {
|
||||
if (mSwipe) {
|
||||
appendCodeIfNotStopped(event);
|
||||
mSwipe = false;
|
||||
} else {
|
||||
mLastTouchPoint.x = mTouchPoint.x;
|
||||
mLastTouchPoint.y = mTouchPoint.y;
|
||||
mSwipe = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void appendCodeIfNotStopped(Event event) {
|
||||
if (!mConverting)
|
||||
return;
|
||||
long interval = (long) (1000 * (event.time - mTouchTime));
|
||||
mCode.append("sh.Swipe(")
|
||||
.append(mLastTouchPoint.x).append(", ").append(mLastTouchPoint.y).append(", ")
|
||||
.append(mTouchPoint.x).append(", ").append(mTouchPoint.y);
|
||||
if (interval >= 1) {
|
||||
mCode.append(", ").append(interval);
|
||||
}
|
||||
mCode.append(");\n");
|
||||
}
|
||||
}
|
||||
|
||||
private class KeyHandler implements EventHandler {
|
||||
|
||||
private Map<String, String> mKeyPressCodeMap = new MapEntries<String, String>()
|
||||
.entry("KEY_HOME", "Home")
|
||||
.entry("KEY_MENU", "Menu")
|
||||
.entry("KEY_VOLUMEDOWN", "VolumeDown")
|
||||
.entry("KEY_VOLUMEUP", "VolumeUp")
|
||||
.entry("KEY_BACK", "Back")
|
||||
.entry("KEY_CAMERA", "Camera")
|
||||
.map();
|
||||
|
||||
@Override
|
||||
public void handle(Event event) {
|
||||
if (event.code.equals("BTN_TOUCH")) {
|
||||
mTouchDown = event.value.equals("DOWN");
|
||||
if (!mTouchDown && mSwipe) {
|
||||
if (mConverting)
|
||||
mCode.append("sh.Tap(").append(mLastTouchPoint.x).append(", ").append(mLastTouchPoint.y).append(");\n");
|
||||
mSwipe = false;
|
||||
}
|
||||
} else if (event.value.equals("UP")) {
|
||||
appendKeyPressCode(event);
|
||||
}
|
||||
}
|
||||
|
||||
private void appendKeyPressCode(Event event) {
|
||||
String code = mKeyPressCodeMap.get(event.code);
|
||||
if (code != null) {
|
||||
mCode.append("sh.").append(code).append("();\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private EventHandler mEventHandler = new TypeRouter();
|
||||
private StringBuilder mCode = new StringBuilder().append("var sh = new Shell(true);\n");
|
||||
private Point mTouchPoint = new Point(), mLastTouchPoint = new Point();
|
||||
private boolean mTouchDown = false, mSwipe = false;
|
||||
private double mTouchTime;
|
||||
|
||||
|
||||
@Override
|
||||
public void convertEvent(@NonNull Event event) {
|
||||
mEventHandler.handle(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
super.stop();
|
||||
mCode.append("sh.exitAndWaitFor();");
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return mCode.toString();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package com.stardust.scriptdroid.external.floatingwindow.menu.record.inputevent;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/7.
|
||||
*/
|
||||
|
||||
public class InputEventToSendEventConverter extends InputEventConverter {
|
||||
|
||||
private static final DecimalFormat DELAY_FORMAT = new DecimalFormat("#.###");
|
||||
|
||||
private double mLastEventTime;
|
||||
private StringBuilder mSendEventCommands = new StringBuilder();
|
||||
|
||||
@Override
|
||||
public void convertEvent(@NonNull Event event) {
|
||||
if (mLastEventTime == 0) {
|
||||
mLastEventTime = event.time;
|
||||
} else if (event.time - mLastEventTime > 0.1) {
|
||||
mSendEventCommands.append("sleep ").append(DELAY_FORMAT.format(event.time - mLastEventTime)).append("\n");
|
||||
mLastEventTime = event.time;
|
||||
}
|
||||
mSendEventCommands.append("sendevent ")
|
||||
.append(event.device).append(" ")
|
||||
.append(hex2dec(event.type)).append(" ")
|
||||
.append(hex2dec(event.code)).append(" ")
|
||||
.append(hex2dec(event.value)).append("\n");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGetEventCommand() {
|
||||
return "getevent -t";
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return mSendEventCommands.toString();
|
||||
}
|
||||
|
||||
private static String hex2dec(String hex) {
|
||||
try {
|
||||
return String.valueOf((int) Long.parseLong(hex, 16));
|
||||
} catch (NumberFormatException e) {
|
||||
throw new EventFormatException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
package com.stardust.scriptdroid.external.floatingwindow.menu.record.inputevent;
|
||||
|
||||
import android.media.Image;
|
||||
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/5/3.
|
||||
*/
|
||||
|
||||
public class InputEventToSendEventJsConverter extends InputEventConverter {
|
||||
|
||||
private final static Pattern LAST_INT_PATTERN = Pattern.compile("[^0-9]+([0-9]+)$");
|
||||
private double mLastEventTime;
|
||||
private StringBuilder mCode = new StringBuilder();
|
||||
private int mTouchDevice = -1;
|
||||
private int mLastTouchX = -1;
|
||||
private int mLastTouchY = -1;
|
||||
|
||||
public InputEventToSendEventJsConverter() {
|
||||
mCode.append("var sh = new Shell(true);\n")
|
||||
.append("sh.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.03) {
|
||||
mCode.append("sh.usleep(").append((long) (1000000 * (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();
|
||||
mCode.append("sh.SendEvent(");
|
||||
if (device != mTouchDevice) {
|
||||
mCode.append(device).append(", ");
|
||||
}
|
||||
mCode.append(type).append(", ")
|
||||
.append(code).append(", ")
|
||||
.append(value).append(");\n");
|
||||
}
|
||||
|
||||
private void checkLastTouch() {
|
||||
if (mLastTouchX >= 0) {
|
||||
mCode.append("sh.TouchX(").append(mLastTouchX).append(");\n");
|
||||
mLastTouchX = -1;
|
||||
}
|
||||
if (mLastTouchY >= 0) {
|
||||
mCode.append("sh.TouchY(").append(mLastTouchY).append(");\n");
|
||||
mLastTouchY = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private int parseDeviceNumber(String device) {
|
||||
Matcher matcher = LAST_INT_PATTERN.matcher(device);
|
||||
if (matcher.find()) {
|
||||
String someNumberStr = matcher.group(1);
|
||||
return Integer.parseInt(someNumberStr);
|
||||
}
|
||||
return -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("sh.Touch(")
|
||||
.append(mLastTouchX).append(", ")
|
||||
.append(value).append(");\n");
|
||||
mLastTouchX = -1;
|
||||
} else {
|
||||
mLastTouchY = value;
|
||||
}
|
||||
}
|
||||
|
||||
private void setTouchDevice(int i) {
|
||||
mCode.append("sh.SetTouchDevice(").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("sh.exitAndWaitFor();");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
package com.stardust.scriptdroid.external.floatingwindow.menu.record.inputevent;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/5/4.
|
||||
*/
|
||||
|
||||
public class KeyObserver {
|
||||
|
||||
public interface KeyListener {
|
||||
|
||||
void onKeyDown(String keyName);
|
||||
|
||||
void onKeyUp(String keyName);
|
||||
|
||||
}
|
||||
|
||||
private InputEventRecorder mObserver;
|
||||
private KeyListener mKeyListener;
|
||||
|
||||
public KeyObserver(Context context) {
|
||||
mObserver = new InputEventRecorder(context, new InputEventConverter() {
|
||||
@Override
|
||||
public void convertEvent(@NonNull Event event) {
|
||||
if (event.value.equalsIgnoreCase("UP")) {
|
||||
notifyKeyUp(event.code);
|
||||
}
|
||||
if (event.value.equalsIgnoreCase("DOWN")) {
|
||||
notifyKeyDown(event.code);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setKeyListener(KeyListener keyListener) {
|
||||
mKeyListener = keyListener;
|
||||
}
|
||||
|
||||
public void startListening() {
|
||||
mObserver.listen();
|
||||
mObserver.start();
|
||||
}
|
||||
|
||||
public void stopListening() {
|
||||
mObserver.stopImpl();
|
||||
}
|
||||
|
||||
private void notifyKeyDown(String keyName) {
|
||||
if (mKeyListener != null) {
|
||||
mKeyListener.onKeyDown(keyName);
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyKeyUp(String keyName) {
|
||||
if (mKeyListener != null) {
|
||||
mKeyListener.onKeyUp(keyName);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package com.stardust.scriptdroid.external.floatingwindow.menu.record.inputevent;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/16.
|
||||
*/
|
||||
|
||||
public class TouchRecorder extends InputEventRecorder {
|
||||
|
||||
public TouchRecorder(Context context) {
|
||||
super(context, new InputEventToSendEventJsConverter());
|
||||
listen();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
super.stop();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.afollestad.materialdialogs.Theme;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.external.floatingwindow.menu.HoverMenuService;
|
||||
import com.stardust.scriptdroid.external.floatingwindow.menu.layout_inspector.NodeInfo;
|
||||
import com.stardust.view.accessibility.NodeInfo;
|
||||
import com.stardust.scriptdroid.external.floatingwindow.menu.layout_inspector.view.LayoutBoundsView;
|
||||
import com.stardust.scriptdroid.external.floatingwindow.menu.layout_inspector.view.NodeInfoView;
|
||||
import com.stardust.scriptdroid.external.floatingwindow.menu.layout_inspector.view.OnNodeInfoSelectListener;
|
||||
|
||||
@@ -11,7 +11,7 @@ import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.afollestad.materialdialogs.Theme;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.external.floatingwindow.menu.HoverMenuService;
|
||||
import com.stardust.scriptdroid.external.floatingwindow.menu.layout_inspector.NodeInfo;
|
||||
import com.stardust.view.accessibility.NodeInfo;
|
||||
import com.stardust.scriptdroid.external.floatingwindow.menu.layout_inspector.view.LayoutHierarchyView;
|
||||
import com.stardust.scriptdroid.external.floatingwindow.menu.layout_inspector.view.NodeInfoView;
|
||||
import com.stardust.util.MessageIntent;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.stardust.scriptdroid.ui.main.task;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.ThemeColorRecyclerView;
|
||||
@@ -11,6 +12,8 @@ import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import android.workground.WrapContentLinearLayoutManager;
|
||||
|
||||
import com.afollestad.materialdialogs.DialogAction;
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.stardust.autojs.ScriptEngineService;
|
||||
import com.stardust.autojs.execution.ScriptExecution;
|
||||
import com.stardust.autojs.execution.ScriptExecutionListener;
|
||||
@@ -43,9 +46,19 @@ public class TaskListRecyclerView extends ThemeColorRecyclerView implements Abst
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int position = getChildViewHolder((View) v.getParent()).getAdapterPosition();
|
||||
if(position >= 0){
|
||||
mScriptEngines.get(position).forceStop();
|
||||
}else {
|
||||
if (position >= 0) {
|
||||
final ScriptEngine engine = mScriptEngines.get(position);
|
||||
engine.forceStop();
|
||||
|
||||
postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!engine.isDestroyed()) {
|
||||
onScriptANR(engine);
|
||||
}
|
||||
}
|
||||
}, 3000);
|
||||
} else {
|
||||
updateEngineList();
|
||||
}
|
||||
}
|
||||
@@ -128,6 +141,10 @@ public class TaskListRecyclerView extends ThemeColorRecyclerView implements Abst
|
||||
AutoJs.getInstance().getScriptEngineService().unregisterGlobalScriptExecutionListener(mScriptExecutionListener);
|
||||
}
|
||||
|
||||
private void onScriptANR(final ScriptEngine engine) {
|
||||
// TODO: 2017/7/19 强制停止
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEngineCreate(final ScriptEngine engine) {
|
||||
synchronized (mScriptEngines) {
|
||||
|
||||
@@ -208,6 +208,8 @@
|
||||
<string name="text_accessibility_settings">打开无障碍服务</string>
|
||||
<string name="text_discard_record">放弃录制</string>
|
||||
<string name="text_inspect_failed">布局抓取失败,请关闭悬浮窗后动一下页面重试</string>
|
||||
<string name="script_anr">没有相应,要强制停止吗</string>
|
||||
|
||||
|
||||
<string-array name="record_control_keys">
|
||||
<item>无</item>
|
||||
|
||||
Reference in New Issue
Block a user