add sublime text plugin support

This commit is contained in:
hyb1996
2017-05-11 17:06:37 +08:00
parent 4f25582ce5
commit b12e26b797
51 changed files with 490 additions and 100 deletions

View File

@@ -6,18 +6,12 @@ import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.os.Handler;
import android.support.annotation.IntDef;
import android.view.Gravity;
import android.view.View;
import android.view.WindowManager;
import com.stardust.enhancedfloaty.FloatyService;
import com.stardust.enhancedfloaty.FloatyWindow;
import com.stardust.scriptdroid.App;
import com.stardust.scriptdroid.autojs.api.VolatileBox;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
/**
* Created by Stardust on 2017/5/9.

View File

@@ -20,7 +20,6 @@ import com.stardust.scriptdroid.autojs.AutoJs;
import com.stardust.scriptdroid.external.floating_window.FloatingWindowManger;
import com.stardust.scriptdroid.external.floating_window.menu.view.FloatingLayoutBoundsView;
import com.stardust.scriptdroid.external.floating_window.menu.view.FloatingLayoutHierarchyView;
import com.stardust.scriptdroid.layout_inspector.NodeInfo;
import com.stardust.scriptdroid.tool.AccessibilityServiceTool;
import com.stardust.theme.ThemeColorManagerCompat;
import com.stardust.util.MessageEvent;

View File

@@ -12,7 +12,7 @@ import com.stardust.scriptdroid.App;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.autojs.AutoJs;
import com.stardust.scriptdroid.external.floating_window.menu.HoverMenuService;
import com.stardust.scriptdroid.layout_inspector.LayoutInspector;
import com.stardust.scriptdroid.external.floating_window.menu.layout_inspector.LayoutInspector;
import com.stardust.util.ClipboardUtil;
import com.stardust.scriptdroid.ui.main.MainActivity;
import com.stardust.util.MessageEvent;

View File

@@ -15,17 +15,15 @@ import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.accessibility.AccessibilityEventHelper;
import com.stardust.scriptdroid.autojs.AutoJs;
import com.stardust.scriptdroid.external.floating_window.menu.HoverMenuService;
import com.stardust.scriptdroid.record.Recorder;
import com.stardust.scriptdroid.record.accessibility.AccessibilityActionRecorder;
import com.stardust.scriptdroid.record.inputevent.InputEventConverter;
import com.stardust.scriptdroid.record.inputevent.KeyObserver;
import com.stardust.scriptdroid.record.inputevent.TouchRecorder;
import com.stardust.scriptdroid.external.floating_window.menu.record.Recorder;
import com.stardust.scriptdroid.external.floating_window.menu.record.accessibility.AccessibilityActionRecorder;
import com.stardust.scriptdroid.external.floating_window.menu.record.inputevent.KeyObserver;
import com.stardust.scriptdroid.external.floating_window.menu.record.inputevent.TouchRecorder;
import com.stardust.scriptdroid.ui.main.MainActivity;
import com.stardust.util.MessageEvent;
import com.stardust.view.ViewBinder;
import com.stardust.view.ViewBinding;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import io.mattcarroll.hover.Navigator;

View File

@@ -0,0 +1,56 @@
package com.stardust.scriptdroid.external.floating_window.menu.layout_inspector;
import android.accessibilityservice.AccessibilityService;
import android.view.accessibility.AccessibilityNodeInfo;
import com.stardust.scriptdroid.service.AccessibilityWatchDogService;
import com.stardust.util.UnderuseExecutors;
import java.util.concurrent.Executor;
/**
* Created by Stardust on 2017/3/10.
*
*/
// TODO: 2017/5/8
public class LayoutInspector {
private volatile NodeInfo mCapture;
private volatile boolean mDumping = false;
private Executor mExecutor = UnderuseExecutors.getExecutor();
public void captureCurrentWindow() {
AccessibilityService service = AccessibilityWatchDogService.getInstance();
if (service == null) {
mCapture = null;
} else {
final AccessibilityNodeInfo root = service.getRootInActiveWindow();
if (root == null) {
mCapture = null;
} else {
mExecutor.execute(new Runnable() {
@Override
public void run() {
mDumping = true;
mCapture = NodeInfo.capture(root);
mDumping = false;
}
});
}
}
}
public boolean isDumping() {
return mDumping;
}
public void clearCapture() {
mCapture = null;
}
public NodeInfo getCapture() {
return mCapture;
}
}

View File

@@ -0,0 +1,98 @@
package com.stardust.scriptdroid.external.floating_window.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<>();
public String id;
public CharSequence contentDesc, className, packageName, text;
public int drawingOrder;
public boolean accessibilityFocused, checked, clickable, contextClickable, dismissable, editable, enabled,
focusable, longClickable, selected, scrollable, visibleToUser;
public String bounds;
private Rect mBoundsInScreen;
public NodeInfo(AccessibilityNodeInfoCompat node) {
id = simplifyId(node.getViewIdResourceName());
contentDesc = 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();
visibleToUser = node.isVisibleToUser();
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);
}
public List<NodeInfo> getChildren() {
return children;
}
}

View File

@@ -0,0 +1,129 @@
package com.stardust.scriptdroid.external.floating_window.menu.layout_inspector.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Build;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import com.stardust.scriptdroid.external.floating_window.menu.layout_inspector.NodeInfo;
import com.stardust.util.ViewUtil;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Stardust on 2017/3/10.
*/
public class LayoutBoundsView extends View {
private NodeInfo mRootNode;
private Paint mPaint;
private int mStatusBarHeight;
private OnNodeInfoSelectListener mOnNodeInfoSelectListener;
public LayoutBoundsView(Context context) {
super(context);
init();
}
public LayoutBoundsView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public LayoutBoundsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public LayoutBoundsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
public void setOnNodeInfoSelectListener(OnNodeInfoSelectListener onNodeInfoSelectListener) {
mOnNodeInfoSelectListener = onNodeInfoSelectListener;
}
public void setRootNode(NodeInfo rootNode) {
mRootNode = rootNode;
}
private void init() {
mPaint = new Paint();
mPaint.setColor(Color.GREEN);
mPaint.setStyle(Paint.Style.STROKE);
mStatusBarHeight = ViewUtil.getStatusBarHeight(getContext());
setWillNotDraw(false);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
draw(canvas, mRootNode);
}
public Paint getPaint() {
return mPaint;
}
private void draw(Canvas canvas, NodeInfo node) {
if (node == null)
return;
drawRect(canvas, node.getBoundsInScreen(), mStatusBarHeight, mPaint);
for (NodeInfo child : node.getChildren()) {
draw(canvas, child);
}
}
static void drawRect(Canvas canvas, Rect rect, int statusBarHeight, Paint paint) {
Rect offsetRect = new Rect(rect);
offsetRect.offset(0, -statusBarHeight);
canvas.drawRect(offsetRect, paint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN && mRootNode != null) {
ArrayList<NodeInfo> list = new ArrayList<>();
findNodeAt(mRootNode, (int) event.getRawX(), (int) event.getRawY(), list);
showNodeInfoList(list);
}
return super.onTouchEvent(event);
}
private void showNodeInfoList(ArrayList<NodeInfo> list) {
onNodeInfoClick(list.get(list.size() - 1));
}
private void onNodeInfoClick(NodeInfo nodeInfo) {
if (mOnNodeInfoSelectListener != null) {
mOnNodeInfoSelectListener.onNodeSelect(nodeInfo);
}
}
private void findNodeAt(NodeInfo node, int x, int y, List<NodeInfo> list) {
for (NodeInfo child : node.getChildren()) {
if (child != null && child.getBoundsInScreen().contains(x, y)) {
list.add(child);
findNodeAt(child, x, y, list);
}
}
}
}

View File

@@ -0,0 +1,230 @@
package com.stardust.scriptdroid.external.floating_window.menu.layout_inspector.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.external.floating_window.menu.layout_inspector.NodeInfo;
import com.stardust.util.ViewUtil;
import com.stardust.widget.LevelBeamView;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import pl.openrnd.multilevellistview.ItemInfo;
import pl.openrnd.multilevellistview.MultiLevelListAdapter;
import pl.openrnd.multilevellistview.MultiLevelListView;
import pl.openrnd.multilevellistview.NestType;
import pl.openrnd.multilevellistview.OnItemClickListener;
/**
* Created by Stardust on 2017/3/10.
*/
public class LayoutHierarchyView extends MultiLevelListView {
private Adapter mAdapter;
private OnNodeInfoSelectListener mOnNodeInfoSelectListener;
private AdapterView.OnItemLongClickListener mOnItemLongClickListenerProxy = new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
if (mOnNodeInfoSelectListener != null) {
mOnNodeInfoSelectListener.onNodeSelect(((ViewHolder) view.getTag()).nodeInfo);
return true;
}
return false;
}
};
private Paint mPaint;
private int mStatusBarHeight;
private NodeInfo mClickedNodeInfo;
private View mClickedView;
private Drawable mOriginalBackground;
private boolean mShowClickedNodeBounds;
private int mClickedColor = 0x77c4c4c4;
public LayoutHierarchyView(Context context) {
super(context);
init();
}
public LayoutHierarchyView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public LayoutHierarchyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public void setShowClickedNodeBounds(boolean showClickedNodeBounds) {
mShowClickedNodeBounds = showClickedNodeBounds;
}
public void setClickedColor(int clickedColor) {
mClickedColor = clickedColor;
}
private void init() {
mAdapter = new Adapter();
setAdapter(mAdapter);
setNestType(NestType.MULTIPLE);
((ListView) getChildAt(0)).setOnItemLongClickListener(mOnItemLongClickListenerProxy);
setWillNotDraw(false);
initPaint();
setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClicked(MultiLevelListView parent, View view, Object item, ItemInfo itemInfo) {
setClickedItem(view, (NodeInfo) item);
}
@Override
public void onGroupItemClicked(MultiLevelListView parent, View view, Object item, ItemInfo itemInfo) {
setClickedItem(view, (NodeInfo) item);
}
});
}
private void setClickedItem(View view, NodeInfo item) {
mClickedNodeInfo = item;
if (mClickedView == null) {
mOriginalBackground = view.getBackground();
} else {
mClickedView.setBackground(mOriginalBackground);
}
view.setBackgroundColor(mClickedColor);
mClickedView = view;
invalidate();
}
private void initPaint() {
mPaint = new Paint();
mPaint.setColor(Color.DKGRAY);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setAntiAlias(true);
mPaint.setStrokeWidth(3);
mStatusBarHeight = ViewUtil.getStatusBarHeight(getContext());
}
public Paint getBoundsPaint() {
return mPaint;
}
public void setRootNode(NodeInfo rootNodeInfo) {
mAdapter.setDataItems(Collections.singletonList(rootNodeInfo));
mClickedNodeInfo = null;
}
public void setOnNodeInfoLongClickListener(final OnNodeInfoSelectListener onNodeInfoSelectListener) {
mOnNodeInfoSelectListener = onNodeInfoSelectListener;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mShowClickedNodeBounds && mClickedNodeInfo != null) {
LayoutBoundsView.drawRect(canvas, mClickedNodeInfo.getBoundsInScreen(), mStatusBarHeight, mPaint);
}
}
private class ViewHolder {
TextView nameView;
TextView infoView;
ImageView arrowView;
LevelBeamView levelBeamView;
NodeInfo nodeInfo;
ViewHolder(View view) {
infoView = (TextView) view.findViewById(R.id.dataItemInfo);
nameView = (TextView) view.findViewById(R.id.dataItemName);
arrowView = (ImageView) view.findViewById(R.id.dataItemArrow);
levelBeamView = (LevelBeamView) view.findViewById(R.id.dataItemLevelBeam);
}
}
private class Adapter extends MultiLevelListAdapter {
@Override
public List<?> getSubObjects(Object object) {
return ((NodeInfo) object).getChildren();
}
@Override
public boolean isExpandable(Object object) {
return !((NodeInfo) object).getChildren().isEmpty();
}
@Override
public View getViewForObject(Object object, View convertView, ItemInfo itemInfo) {
NodeInfo nodeInfo = (NodeInfo) object;
ViewHolder viewHolder;
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.layout_hierarchy_view_item, LayoutHierarchyView.this, false);
viewHolder = new ViewHolder(convertView);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.nameView.setText(simplifyClassName(nodeInfo.className));
viewHolder.nodeInfo = nodeInfo;
if (viewHolder.infoView.getVisibility() == VISIBLE)
viewHolder.infoView.setText(getItemInfoDsc(itemInfo));
if (itemInfo.isExpandable() && !isAlwaysExpanded()) {
viewHolder.arrowView.setVisibility(View.VISIBLE);
viewHolder.arrowView.setImageResource(itemInfo.isExpanded() ?
R.drawable.arrow_up : R.drawable.arrow_down);
} else {
viewHolder.arrowView.setVisibility(View.GONE);
}
viewHolder.levelBeamView.setLevel(itemInfo.getLevel());
return convertView;
}
private String simplifyClassName(CharSequence className) {
if (className == null)
return null;
String s = className.toString();
if (s.startsWith("android.widget.")) {
s = s.substring(15);
}
return s;
}
private String getItemInfoDsc(ItemInfo itemInfo) {
StringBuilder builder = new StringBuilder();
builder.append(String.format(Locale.getDefault(), "level[%d], idx in level[%d/%d]",
itemInfo.getLevel() + 1, /*Indexing starts from 0*/
itemInfo.getIdxInLevel() + 1 /*Indexing starts from 0*/,
itemInfo.getLevelSize()));
if (itemInfo.isExpandable()) {
builder.append(String.format(", expanded[%b]", itemInfo.isExpanded()));
}
return builder.toString();
}
}
}

View File

@@ -0,0 +1,86 @@
package com.stardust.scriptdroid.external.floating_window.menu.layout_inspector.view;
import android.content.Context;
import android.os.Build;
import android.support.annotation.AttrRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.support.annotation.StyleRes;
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ViewSwitcher;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.external.floating_window.menu.layout_inspector.NodeInfo;
/**
* Created by Stardust on 2017/3/10.
*/
public class LayoutInspectView extends FrameLayout {
private ViewSwitcher mViewSwitcher;
private NodeInfoView mNodeInfoView;
private LayoutHierarchyView mLayoutBoundsView;
private View mCurrentView;
public LayoutInspectView(@NonNull Context context) {
super(context);
init();
}
public LayoutInspectView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public LayoutInspectView(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public LayoutInspectView(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init() {
inflate(getContext(), R.layout.floating_window_expand, this);
mNodeInfoView = (NodeInfoView) findViewById(R.id.node_info);
mLayoutBoundsView = (LayoutHierarchyView) findViewById(R.id.bounds_view);
mViewSwitcher = (ViewSwitcher) findViewById(R.id.view_switcher);
mCurrentView = mNodeInfoView;
mLayoutBoundsView.setOnNodeInfoLongClickListener(new OnNodeInfoSelectListener() {
@Override
public void onNodeSelect(NodeInfo info) {
mNodeInfoView.setNodeInfo(info);
showNodeInfoView();
}
});
}
public void showNodeInfoView() {
if (mCurrentView != mNodeInfoView) {
mViewSwitcher.showPrevious();
mCurrentView = mNodeInfoView;
}
}
public boolean isLayoutBoundsViewShowing() {
return mCurrentView == mLayoutBoundsView;
}
public boolean isNodeInfoViewShowing() {
return mCurrentView == mNodeInfoView;
}
public void backToLayoutBoundsView() {
if (mCurrentView != mLayoutBoundsView) {
mViewSwitcher.showNext();
mCurrentView = mLayoutBoundsView;
}
}
}

View File

@@ -0,0 +1,112 @@
package com.stardust.scriptdroid.external.floating_window.menu.layout_inspector.view;
import android.content.Context;
import android.graphics.Color;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.external.floating_window.menu.layout_inspector.NodeInfo;
import com.stardust.util.ClipboardUtil;
import java.lang.reflect.Field;
import de.codecrafters.tableview.TableDataAdapter;
import de.codecrafters.tableview.TableView;
import de.codecrafters.tableview.model.TableColumnWeightModel;
import de.codecrafters.tableview.toolkit.SimpleTableDataAdapter;
import de.codecrafters.tableview.toolkit.TableDataRowBackgroundProviders;
/**
* Created by Stardust on 2017/3/10.
*/
public class NodeInfoView extends TableView {
private static final Field[] fields = NodeInfo.class.getFields();
private String[][] mData = new String[fields.length][2];
public NodeInfoView(Context context) {
super(context);
init();
}
public NodeInfoView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public NodeInfoView(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public void setNodeInfo(NodeInfo nodeInfo) {
for (int i = 0; i < fields.length; i++) {
try {
Object value = fields[i].get(nodeInfo);
mData[i][1] = value == null ? "null" : value.toString();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
getDataAdapter().notifyDataSetChanged();
}
private void init() {
initData();
setUpTableConfig();
setAdapter();
setUpStyle();
}
private void setAdapter() {
setDataAdapter(new TableDataAdapter<String[]>(getContext(), mData) {
SimpleTableDataAdapter mSimpleTableDataAdapter = new SimpleTableDataAdapter(getContext(), mData);
@Override
public View getCellView(int rowIndex, int columnIndex, ViewGroup parentView) {
final TextView textView = (TextView) mSimpleTableDataAdapter.getCellView(rowIndex, columnIndex, parentView);
textView.setSingleLine(false);
textView.setMaxLines(3);
textView.setTextColor(0xcc000000);
textView.setTextIsSelectable(true);
textView.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
ClipboardUtil.setClip(getContext(), textView.getText());
Toast.makeText(getContext(), R.string.text_already_copy_to_clip, Toast.LENGTH_SHORT).show();
return true;
}
});
return textView;
}
});
}
private void setUpTableConfig() {
setColumnCount(2);
setColumnModel(new TableColumnWeightModel(2));
}
private void initData() {
for (int i = 0; i < mData.length; i++) {
mData[i][0] = fields[i].getName();
mData[i][1] = "";
}
}
private void setUpStyle() {
int colorEvenRows = Color.WHITE;
int colorOddRows = 0xffe7e7e7;
setDataRowBackgroundProvider(TableDataRowBackgroundProviders.alternatingRowColors(colorEvenRows, colorOddRows));
getChildAt(0).setVisibility(GONE);
}
}

View File

@@ -0,0 +1,12 @@
package com.stardust.scriptdroid.external.floating_window.menu.layout_inspector.view;
import com.stardust.scriptdroid.external.floating_window.menu.layout_inspector.NodeInfo;
/**
* Created by Stardust on 2017/3/10.
*/
public interface OnNodeInfoSelectListener {
void onNodeSelect(NodeInfo info);
}

View File

@@ -0,0 +1,175 @@
package com.stardust.scriptdroid.external.floating_window.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;
}
}
}

View File

@@ -0,0 +1,144 @@
package com.stardust.scriptdroid.external.floating_window.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.floating_window.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;
}
}
}

View File

@@ -0,0 +1,92 @@
package com.stardust.scriptdroid.external.floating_window.menu.record.accessibility;
import android.accessibilityservice.AccessibilityService;
import android.view.accessibility.AccessibilityEvent;
import com.stardust.scriptdroid.external.floating_window.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;
}
}

View File

@@ -0,0 +1,25 @@
package com.stardust.scriptdroid.external.floating_window.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);
}
}

View File

@@ -0,0 +1,130 @@
package com.stardust.scriptdroid.external.floating_window.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.floating_window.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;
}
}
}

View File

@@ -0,0 +1,75 @@
package com.stardust.scriptdroid.external.floating_window.menu.record.inputevent;
import com.stardust.scriptdroid.autojs.api.Shell;
import com.stardust.scriptdroid.external.floating_window.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;
protected InputEventRecorder(InputEventConverter inputEventConverter) {
mGetEventCommand = inputEventConverter.getGetEventCommand();
mInputEventConverter = inputEventConverter;
}
public void listen() {
mShell = new Shell(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);
}
}

View File

@@ -0,0 +1,158 @@
package com.stardust.scriptdroid.external.floating_window.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<>(new HashMap<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();
}
}

View File

@@ -0,0 +1,52 @@
package com.stardust.scriptdroid.external.floating_window.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);
}
}
}

View File

@@ -0,0 +1,132 @@
package com.stardust.scriptdroid.external.floating_window.menu.record.inputevent;
import android.support.annotation.NonNull;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static com.stardust.util.ScreenMetrics.getScreenHeight;
import static com.stardust.util.ScreenMetrics.getScreenWidth;
/**
* 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(getScreenWidth()).append(", ")
.append(getScreenHeight()).append(");\n");
}
@Override
public void convertEvent(@NonNull Event event) {
if (mLastEventTime == 0) {
mLastEventTime = event.time;
} else if (event.time - mLastEventTime > 0.03) {
mCode.append("sleep(").append((long) (1000 * (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();");
}
private static String hex2dec(String hex) {
try {
return String.valueOf((int) Long.parseLong(hex, 16));
} catch (NumberFormatException e) {
throw new EventFormatException(e);
}
}
}

View File

@@ -0,0 +1,66 @@
package com.stardust.scriptdroid.external.floating_window.menu.record.inputevent;
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(){
mObserver = new InputEventRecorder(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);
}
}
}

View File

@@ -0,0 +1,20 @@
package com.stardust.scriptdroid.external.floating_window.menu.record.inputevent;
/**
* Created by Stardust on 2017/3/16.
*/
public class TouchRecorder extends InputEventRecorder {
public TouchRecorder() {
super(new InputEventToSendEventJsConverter());
listen();
}
@Override
public void stop() {
super.stop();
}
}

View File

@@ -7,10 +7,10 @@ import android.view.WindowManager;
import com.afollestad.materialdialogs.MaterialDialog;
import com.afollestad.materialdialogs.Theme;
import com.stardust.scriptdroid.external.floating_window.menu.HoverMenuService;
import com.stardust.scriptdroid.layout_inspector.NodeInfo;
import com.stardust.scriptdroid.layout_inspector.view.LayoutBoundsView;
import com.stardust.scriptdroid.layout_inspector.view.NodeInfoView;
import com.stardust.scriptdroid.layout_inspector.view.OnNodeInfoSelectListener;
import com.stardust.scriptdroid.external.floating_window.menu.layout_inspector.NodeInfo;
import com.stardust.scriptdroid.external.floating_window.menu.layout_inspector.view.LayoutBoundsView;
import com.stardust.scriptdroid.external.floating_window.menu.layout_inspector.view.NodeInfoView;
import com.stardust.scriptdroid.external.floating_window.menu.layout_inspector.view.OnNodeInfoSelectListener;
import com.stardust.util.MessageEvent;
/**

View File

@@ -7,10 +7,10 @@ import android.view.WindowManager;
import com.afollestad.materialdialogs.MaterialDialog;
import com.afollestad.materialdialogs.Theme;
import com.stardust.scriptdroid.external.floating_window.menu.HoverMenuService;
import com.stardust.scriptdroid.layout_inspector.NodeInfo;
import com.stardust.scriptdroid.layout_inspector.view.LayoutHierarchyView;
import com.stardust.scriptdroid.layout_inspector.view.NodeInfoView;
import com.stardust.scriptdroid.layout_inspector.view.OnNodeInfoSelectListener;
import com.stardust.scriptdroid.external.floating_window.menu.layout_inspector.NodeInfo;
import com.stardust.scriptdroid.external.floating_window.menu.layout_inspector.view.LayoutHierarchyView;
import com.stardust.scriptdroid.external.floating_window.menu.layout_inspector.view.NodeInfoView;
import com.stardust.scriptdroid.external.floating_window.menu.layout_inspector.view.OnNodeInfoSelectListener;
import com.stardust.util.MessageEvent;
/**

View File

@@ -40,8 +40,4 @@ public class ImportIntentActivity extends BaseActivity {
finish();
}
private void startMainActivity() {
finish();
}
}

View File

@@ -44,7 +44,11 @@ public class RunIntentActivity extends Activity {
source = new StringScriptSource(script);
} else if (path != null && new PathChecker(this).checkAndToastError(path)) {
ScriptSource fileScriptSource = new FileScriptSource(path);
source = new SequenceScriptSource(fileScriptSource.getName(), new StringScriptSource(script), fileScriptSource);
if (script != null) {
source = new SequenceScriptSource(fileScriptSource.getName(), new StringScriptSource(script), fileScriptSource);
} else {
source = fileScriptSource;
}
directoryPath = new File(path).getParent();
}
if (source != null) {