Added: Record with root permission
This commit is contained in:
@@ -159,7 +159,10 @@ var Tap = function(x, y){
|
||||
return shell("input tap " + x + " " + y, true).code == 1;
|
||||
}
|
||||
|
||||
var Swipe = function(x1, y1, x2, y2){
|
||||
var Swipe = function(x1, y1, x2, y2, duration){
|
||||
if(arguments.length == 5){
|
||||
return shell("input swipe " + x1 + " " + y1 + " " + x2 + " " + y2 + " " + duration, true).code == 1;
|
||||
}
|
||||
return shell("input swipe " + x1 + " " + y1 + " " + x2 + " " + y2, true).code == 1;
|
||||
}
|
||||
|
||||
@@ -219,6 +222,8 @@ var Text = function(text){
|
||||
return shell("input text " + text, true).code == 1;
|
||||
}
|
||||
|
||||
__importClassOld__(com.stardust.scriptdroid.droid.runtime.Shell);
|
||||
|
||||
/*
|
||||
importClass("com.stardust.scriptdroid.service.AccessibilityDelegate");
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
importClass("com.afollestad.materialdialogs.MaterialDialog");
|
||||
|
||||
new ThemeColorMaterialDialogBuilder(activity)
|
||||
new MaterialDialog.Builder(activity)
|
||||
.title("简单计算器")
|
||||
.input("请输入算式", "1+1", function(dialog, input){
|
||||
eval("var ans = (" + input + ")");
|
||||
|
||||
@@ -15,9 +15,6 @@ import com.stardust.theme.ThemeColorManager;
|
||||
import com.stardust.util.CrashHandler;
|
||||
import com.stardust.util.StateObserver;
|
||||
|
||||
import org.mozilla.javascript.Context;
|
||||
import org.mozilla.javascript.Scriptable;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,7 +25,6 @@ import com.stardust.scriptdroid.droid.runtime.action.ActionFactory;
|
||||
import com.stardust.scriptdroid.droid.runtime.action.ActionPerformAccessibilityDelegate;
|
||||
import com.stardust.scriptdroid.droid.runtime.action.ActionTarget;
|
||||
import com.stardust.scriptdroid.droid.runtime.action.GetTextAction;
|
||||
import com.stardust.scriptdroid.droid.runtime.api.IDroidRuntime;
|
||||
import com.stardust.scriptdroid.file.FileUtils;
|
||||
import com.stardust.scriptdroid.service.AccessibilityDelegate;
|
||||
import com.stardust.scriptdroid.service.AccessibilityWatchDogService;
|
||||
@@ -45,7 +44,7 @@ import timber.log.Timber;
|
||||
* Created by Stardust on 2017/1/27.
|
||||
*/
|
||||
|
||||
public class DroidRuntime implements IDroidRuntime {
|
||||
public class DroidRuntime {
|
||||
|
||||
private static final String TAG = "DroidRuntime";
|
||||
private static DroidRuntime runtime = new DroidRuntime();
|
||||
@@ -61,18 +60,15 @@ public class DroidRuntime implements IDroidRuntime {
|
||||
mUIHandler = new Handler(App.getApp().getMainLooper());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void launchPackage(String packageName) {
|
||||
PackageManager packageManager = App.getApp().getPackageManager();
|
||||
App.getApp().startActivity(packageManager.getLaunchIntentForPackage(packageName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void launch(String packageName, String className) {
|
||||
App.getApp().startActivity(new Intent().setClassName(packageName, className).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void launchApp(String appName) {
|
||||
PackageManager packageManager = App.getApp().getPackageManager();
|
||||
List<ApplicationInfo> installedApplications = packageManager.getInstalledApplications(PackageManager.GET_META_DATA);
|
||||
@@ -84,22 +80,18 @@ public class DroidRuntime implements IDroidRuntime {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getPackageName(String appName) {
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionTarget text(String text, int i) {
|
||||
return new ActionTarget.TextActionTarget(text, i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionTarget bounds(int left, int top, int right, int bottom) {
|
||||
return new ActionTarget.BoundsActionTarget(new Rect(left, top, right, bottom));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionTarget editable(int i) {
|
||||
return new ActionTarget.EditableActionTarget(i);
|
||||
}
|
||||
@@ -108,32 +100,26 @@ public class DroidRuntime implements IDroidRuntime {
|
||||
return new ActionTarget.IdActionTarget(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean click(ActionTarget target) {
|
||||
return performAction(target.createAction(AccessibilityNodeInfo.ACTION_CLICK));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean longClick(ActionTarget target) {
|
||||
return performAction(target.createAction(AccessibilityNodeInfo.ACTION_LONG_CLICK));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean scrollUp(ActionTarget target) {
|
||||
return performAction(target.createAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean scrollDown(ActionTarget target) {
|
||||
return performAction(target.createAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean scrollUp(int i) {
|
||||
return performAction(ActionFactory.createScrollAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD, i));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean scrollDown(int i) {
|
||||
return performAction(ActionFactory.createScrollAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD, i));
|
||||
}
|
||||
@@ -146,17 +132,14 @@ public class DroidRuntime implements IDroidRuntime {
|
||||
return performAction(ActionFactory.createScrollMaxAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean focus(ActionTarget target) {
|
||||
return performAction(target.createAction(AccessibilityNodeInfo.ACTION_FOCUS));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean select(ActionTarget target) {
|
||||
return performAction(target.createAction(AccessibilityNodeInfo.ACTION_SELECT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setText(ActionTarget target, String text) {
|
||||
return performAction(target.createAction(AccessibilityNodeInfo.ACTION_SET_TEXT, text));
|
||||
}
|
||||
@@ -170,7 +153,6 @@ public class DroidRuntime implements IDroidRuntime {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean paste(ActionTarget target) {
|
||||
return performAction(target.createAction(AccessibilityNodeInfo.ACTION_PASTE));
|
||||
}
|
||||
@@ -230,7 +212,6 @@ public class DroidRuntime implements IDroidRuntime {
|
||||
return performAction(new GetTextAction());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toast(final String text) {
|
||||
mUIHandler.post(new Runnable() {
|
||||
@Override
|
||||
@@ -240,7 +221,6 @@ public class DroidRuntime implements IDroidRuntime {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sleep(long millis) {
|
||||
try {
|
||||
Thread.sleep(millis);
|
||||
@@ -275,12 +255,10 @@ public class DroidRuntime implements IDroidRuntime {
|
||||
return ActionPerformAccessibilityDelegate.getLatestActivity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStopped() {
|
||||
return Thread.currentThread().isInterrupted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
Thread.interrupted();
|
||||
}
|
||||
@@ -289,7 +267,6 @@ public class DroidRuntime implements IDroidRuntime {
|
||||
return FileUtils.readString(new File(Environment.getExternalStorageDirectory() + "/" + path));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThemeColorMaterialDialogBuilder dialog() {
|
||||
if (App.currentActivity() == null) {
|
||||
Toast.makeText(App.getApp(), R.string.text_cannot_create_dialog_when_app_invisible, Toast.LENGTH_SHORT).show();
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.stardust.scriptdroid.droid.runtime;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/7.
|
||||
*/
|
||||
|
||||
public class Shell extends com.stardust.scriptdroid.tool.Shell {
|
||||
|
||||
public Shell(boolean root) {
|
||||
super(root);
|
||||
}
|
||||
|
||||
public void Tap(int x, int y) {
|
||||
execute("input tap " + x + " " + y);
|
||||
}
|
||||
|
||||
public void Swipe(int x1, int y1, int x2, int y2) {
|
||||
execute("input swipe " + x1 + " " + y1 + " " + x2 + " " + y2);
|
||||
}
|
||||
|
||||
public void Swipe(int x1, int y1, int x2, int y2, long duration) {
|
||||
execute("input swipe " + x1 + " " + y1 + " " + x2 + " " + y2 + " " + duration);
|
||||
}
|
||||
|
||||
public void KeyCode(int keyCode) {
|
||||
execute("input keyevent " + keyCode);
|
||||
}
|
||||
|
||||
public void KeyCode(String keyCode) {
|
||||
execute("input keyevent " + keyCode);
|
||||
}
|
||||
|
||||
public void Home() {
|
||||
KeyCode(3);
|
||||
}
|
||||
|
||||
public void Back() {
|
||||
KeyCode(4);
|
||||
}
|
||||
|
||||
public void Power() {
|
||||
KeyCode(26);
|
||||
}
|
||||
|
||||
public void Up() {
|
||||
KeyCode(19);
|
||||
}
|
||||
|
||||
public void Down() {
|
||||
KeyCode(20);
|
||||
}
|
||||
|
||||
public void Left() {
|
||||
KeyCode(21);
|
||||
}
|
||||
|
||||
public void Right() {
|
||||
KeyCode(22);
|
||||
}
|
||||
|
||||
public void OK() {
|
||||
KeyCode(23);
|
||||
}
|
||||
|
||||
public void VolumeUp() {
|
||||
KeyCode(24);
|
||||
}
|
||||
|
||||
public void VolumeDown() {
|
||||
KeyCode(25);
|
||||
}
|
||||
|
||||
public void Menu() {
|
||||
KeyCode(1);
|
||||
}
|
||||
|
||||
public void Camera() {
|
||||
KeyCode(27);
|
||||
}
|
||||
|
||||
public void Text(String text) {
|
||||
execute("input text " + text);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package com.stardust.scriptdroid.droid.runtime.api;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.stardust.scriptdroid.droid.runtime.action.ActionTarget;
|
||||
import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/27.
|
||||
*/
|
||||
public interface IDroidRuntime {
|
||||
|
||||
void launchPackage(String packageName);
|
||||
|
||||
void launch(String packageName, String className);
|
||||
|
||||
void launchApp(String appName);
|
||||
|
||||
String[] getPackageName(String appName);
|
||||
|
||||
ActionTarget text(String text, int i);
|
||||
|
||||
ActionTarget bounds(int left, int top, int right, int bottom);
|
||||
|
||||
ActionTarget editable(int i);
|
||||
|
||||
boolean click(ActionTarget target);
|
||||
|
||||
boolean longClick(ActionTarget target);
|
||||
|
||||
boolean scrollUp(ActionTarget target);
|
||||
|
||||
boolean scrollDown(ActionTarget target);
|
||||
|
||||
boolean scrollUp(int i);
|
||||
|
||||
boolean scrollDown(int i);
|
||||
|
||||
boolean focus(ActionTarget target);
|
||||
|
||||
boolean select(ActionTarget target);
|
||||
|
||||
boolean setText(ActionTarget target, String text);
|
||||
|
||||
boolean paste(ActionTarget target);
|
||||
|
||||
void toast(String text);
|
||||
|
||||
void sleep(long millis);
|
||||
|
||||
boolean isStopped();
|
||||
|
||||
void stop();
|
||||
|
||||
ThemeColorMaterialDialogBuilder dialog();
|
||||
}
|
||||
@@ -1,19 +1,5 @@
|
||||
package com.stardust.scriptdroid.droid.script;
|
||||
|
||||
import com.efurture.script.JSTransformer;
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.droid.Droid;
|
||||
import com.stardust.scriptdroid.droid.runtime.api.IDroidRuntime;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/27.
|
||||
*/
|
||||
|
||||
@@ -2,8 +2,9 @@ package com.stardust.scriptdroid.droid.script;
|
||||
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.BuildConfig;
|
||||
import com.stardust.scriptdroid.droid.script.file.AssetScript;
|
||||
import com.stardust.scriptdroid.file.FileUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -15,10 +16,6 @@ public abstract class JavaScriptEngine {
|
||||
|
||||
Map<String, Object> mVariableMap = new HashMap<>();
|
||||
|
||||
protected String preprocess(String script) {
|
||||
return script;
|
||||
}
|
||||
|
||||
public abstract Object execute(String script);
|
||||
|
||||
public void set(String varName, Object value) {
|
||||
@@ -33,11 +30,17 @@ public abstract class JavaScriptEngine {
|
||||
private static final String INIT_SCRIPT = readInitScript();
|
||||
|
||||
private static String readInitScript() {
|
||||
return AssetScript.read(App.getApp(), "javasccript_engine_init.js");
|
||||
try {
|
||||
return FileUtils.readString(App.getApp().getAssets().open("javasccript_engine_init.js"));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return "Error: Unable to read init script.";
|
||||
}
|
||||
}
|
||||
|
||||
static String getInitScript() {
|
||||
if (BuildConfig.DEBUG) {
|
||||
// 调试时不缓存INIT_SCRIPT否则修改javasccript_engine_init.js后不会更新
|
||||
return readInitScript();
|
||||
} else {
|
||||
return INIT_SCRIPT;
|
||||
|
||||
@@ -2,8 +2,8 @@ package com.stardust.scriptdroid.droid.script;
|
||||
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.droid.Droid;
|
||||
import com.stardust.scriptdroid.droid.runtime.DroidRuntime;
|
||||
import com.stardust.scriptdroid.droid.runtime.ScriptStopException;
|
||||
import com.stardust.scriptdroid.droid.runtime.api.IDroidRuntime;
|
||||
|
||||
import org.mozilla.javascript.Context;
|
||||
import org.mozilla.javascript.ContextFactory;
|
||||
@@ -27,7 +27,7 @@ public class RhinoJavaScriptEngine extends JavaScriptEngine {
|
||||
|
||||
private final Set<Thread> mThreads = new HashSet<>();
|
||||
|
||||
public RhinoJavaScriptEngine(IDroidRuntime runtime) {
|
||||
public RhinoJavaScriptEngine(DroidRuntime runtime) {
|
||||
set("droid", runtime);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
package com.stardust.scriptdroid.droid.script.file;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import com.efurture.script.JSTransformer;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
public class AssetScript {
|
||||
|
||||
|
||||
|
||||
public static String read(Context context, String fileName){
|
||||
try {
|
||||
InputStream is = context.getAssets().open(fileName);
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
|
||||
BufferedInputStream bufferIn = new BufferedInputStream(is);
|
||||
byte[] buffer = new byte[2048];
|
||||
int length = 0;
|
||||
while ((length = bufferIn.read(buffer)) >= 0){
|
||||
output.write(buffer, 0, length);
|
||||
}
|
||||
String script = output.toString();
|
||||
Log.e("compiled ScriptEngine", script);
|
||||
return script;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static String toScript(Context context, String fileName){
|
||||
try {
|
||||
InputStream is = context.getAssets().open(fileName);
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(is));
|
||||
String script = JSTransformer.parse(br);
|
||||
Log.e("ScriptEngine", script);
|
||||
return script;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static String toScript(String fileName){
|
||||
try {
|
||||
InputStream is = new FileInputStream(fileName);
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(is));
|
||||
String script = JSTransformer.parse(br);
|
||||
Log.e("ScriptEngine", script);
|
||||
return script;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static String toScript(InputStream is){
|
||||
try {
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(is));
|
||||
String script = JSTransformer.parse(br);
|
||||
Log.e("ScriptEngine", script);
|
||||
return script;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.stardust.scriptdroid.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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package com.stardust.scriptdroid.record.inputevent;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.droid.runtime.DroidRuntime;
|
||||
import com.stardust.scriptdroid.ui.main.MainActivity;
|
||||
|
||||
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 mStarted = false;
|
||||
|
||||
public void parseAndAddEventIfFormatCorrect(String eventStr) {
|
||||
Event event = parseEventOrNull(eventStr);
|
||||
if (event != null) {
|
||||
addEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void addEvent(@NonNull Event event);
|
||||
|
||||
|
||||
public void start() {
|
||||
mStarted = true;
|
||||
}
|
||||
|
||||
public void pause() {
|
||||
mStarted = false;
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
mStarted = false;
|
||||
}
|
||||
|
||||
public abstract String getCode();
|
||||
|
||||
public Event parseEventOrNull(String eventStr) {
|
||||
try {
|
||||
return Event.parseEvent(eventStr);
|
||||
} catch (EventFormatException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void notifyRecordStopped() {
|
||||
MainActivity.onRootRecordStopped(App.getApp());
|
||||
}
|
||||
|
||||
public void notifyRecordStarted() {
|
||||
DroidRuntime.getRuntime().toast(App.getApp().getString(R.string.text_start_record));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package com.stardust.scriptdroid.record.inputevent;
|
||||
|
||||
import android.preference.PreferenceManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Pair;
|
||||
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.tool.Shell;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import jackpal.androidterm.ShellTermSession;
|
||||
import jackpal.androidterm.emulatorview.TermSession;
|
||||
import jackpal.androidterm.util.TermSettings;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/6.
|
||||
*/
|
||||
|
||||
public abstract class InputEventRecorder {
|
||||
|
||||
private Thread mRecordThread;
|
||||
private TermSession mTermSession;
|
||||
private String mGetEventCommand;
|
||||
protected InputEventConverter mInputEventConverter;
|
||||
|
||||
protected InputEventRecorder(String getEventCommand, InputEventConverter inputEventConverter) {
|
||||
mGetEventCommand = getEventCommand;
|
||||
mInputEventConverter = inputEventConverter;
|
||||
}
|
||||
|
||||
public void listen() {
|
||||
TermSettings settings = new TermSettings(App.getApp().getResources(), PreferenceManager.getDefaultSharedPreferences(App.getApp()));
|
||||
try {
|
||||
mTermSession = new ShellTermSession(settings, "su\r") {
|
||||
boolean enter = false;
|
||||
|
||||
@Override
|
||||
protected void processInput(byte[] data, int offset, int count) {
|
||||
String[] lines = new String(data, offset, count).split("\n");
|
||||
for (String line : lines) {
|
||||
System.out.println(line);
|
||||
if (!enter && line.endsWith("data # ")) {
|
||||
mTermSession.write(mGetEventCommand + "\r");
|
||||
enter = true;
|
||||
} else if (enter) {
|
||||
parseAndRecordEvent(line);
|
||||
}
|
||||
}
|
||||
appendToEmulator(data, offset, count);
|
||||
}
|
||||
};
|
||||
mTermSession.initializeEmulator(80, 40);
|
||||
mTermSession.write("su\r");
|
||||
mRecordThread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
//readOutput(mTermSession);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
mRecordThread.start();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void start() {
|
||||
mInputEventConverter.start();
|
||||
}
|
||||
|
||||
public void pause() {
|
||||
mInputEventConverter.pause();
|
||||
}
|
||||
|
||||
private void readOutput(TermSession shell) {
|
||||
boolean enter = false;
|
||||
String line;
|
||||
try {
|
||||
BufferedReader succeedReader = new BufferedReader(new InputStreamReader(mTermSession.getTermIn()));
|
||||
while ((line = succeedReader.readLine()) != null) {
|
||||
System.out.println(line);
|
||||
if (!enter && line.endsWith("data # ")) {
|
||||
mTermSession.write(mGetEventCommand + "\r");
|
||||
enter = true;
|
||||
} else if (enter) {
|
||||
parseAndRecordEvent(line);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void parseAndRecordEvent(String eventStr);
|
||||
|
||||
public abstract String getCode();
|
||||
|
||||
public void stop() {
|
||||
mRecordThread.interrupt();
|
||||
mTermSession.finish();
|
||||
mInputEventConverter.stop();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
package com.stardust.scriptdroid.record.inputevent;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import com.stardust.scriptdroid.droid.runtime.DroidRuntime;
|
||||
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<>();
|
||||
|
||||
EventHandler getHandler(String key) {
|
||||
return mEventHandlerMap.get(key);
|
||||
}
|
||||
|
||||
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 (!mStarted)
|
||||
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")
|
||||
.map();
|
||||
|
||||
@Override
|
||||
public void handle(Event event) {
|
||||
if (event.code.equals("BTN_TOUCH")) {
|
||||
mTouchDown = event.value.equals("DOWN");
|
||||
if (!mTouchDown && mSwipe) {
|
||||
if (mStarted)
|
||||
mCode.append("sh.Tap(").append(mLastTouchPoint.x).append(", ").append(mLastTouchPoint.y).append(");\n");
|
||||
mSwipe = false;
|
||||
}
|
||||
} else if (event.value.equals("UP")) {
|
||||
if (!mStarted && event.code.equals("KEY_VOLUMEUP")) {
|
||||
mStarted = true;
|
||||
notifyRecordStarted();
|
||||
} else if (mStarted && event.code.equals("KEY_VOLUMEDOWN")) {
|
||||
mStarted = false;
|
||||
notifyRecordStopped();
|
||||
} else {
|
||||
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 addEvent(@NonNull Event event) {
|
||||
mEventHandler.handle(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
super.stop();
|
||||
mCode.append("sh.exitAndWaitFor();");
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return mCode.toString();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.stardust.scriptdroid.record.inputevent;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/7.
|
||||
*/
|
||||
|
||||
public class InputEventToJsRecorder extends InputEventRecorder {
|
||||
|
||||
|
||||
public InputEventToJsRecorder() {
|
||||
super("getevent -t -l", new InputEventToJsConverter());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void parseAndRecordEvent(String eventStr) {
|
||||
mInputEventConverter.parseAndAddEventIfFormatCorrect(eventStr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return mInputEventConverter.getCode();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.stardust.scriptdroid.record.inputevent;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
||||
/**
|
||||
* 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 addEvent(@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");
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.stardust.scriptdroid.record.inputevent;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/7.
|
||||
*/
|
||||
|
||||
public class InputEventToSendEventRecorder extends InputEventRecorder {
|
||||
|
||||
private InputEventToSendEventConverter mEventConverter;
|
||||
|
||||
protected InputEventToSendEventRecorder() {
|
||||
super("getevent -t", new InputEventToSendEventConverter());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void parseAndRecordEvent(String eventStr) {
|
||||
mEventConverter.parseAndAddEventIfFormatCorrect(eventStr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return mEventConverter.getCode();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
package com.stardust.scriptdroid.record.root;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.util.Pair;
|
||||
|
||||
import com.jecelyin.common.utils.StringUtils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/6.
|
||||
*/
|
||||
|
||||
public class InputEventConverter {
|
||||
|
||||
public static Pair<Double, String> convert(String line) {
|
||||
int j = line.indexOf(']');
|
||||
double time = 0;
|
||||
if (j > 0) {
|
||||
time = Double.parseDouble(line.substring(1, j));
|
||||
line = line.substring(j + 2);
|
||||
}
|
||||
String[] str = line.split(" ", 4);
|
||||
for (int i = 1; i < 4; i++) {
|
||||
str[i] = hex2dec(str[i]);
|
||||
}
|
||||
str[0] = str[0].substring(0, str[0].length() - 1);
|
||||
return new Pair<>(time, "sendevent " + TextUtils.join(" ", str));
|
||||
}
|
||||
|
||||
private static String hex2dec(String hex) {
|
||||
return String.valueOf((int) Long.parseLong(hex, 16));
|
||||
}
|
||||
|
||||
private static class SingleEvent {
|
||||
|
||||
private static final Pattern PATTERN = Pattern.compile("^\\[([^\\]]*)\\]\\s+([^:]*):\\s+([^\\s]*)\\s+([^\\s]*)\\s+([^\\s]*)$");
|
||||
|
||||
double time;
|
||||
String device;
|
||||
String type;
|
||||
String code;
|
||||
String value;
|
||||
|
||||
|
||||
SingleEvent(String str) {
|
||||
Matcher matcher = PATTERN.matcher(str);
|
||||
matcher.matches();
|
||||
time = Double.parseDouble(matcher.group(1));
|
||||
device = matcher.group(2);
|
||||
type = matcher.group(3);
|
||||
code = matcher.group(4);
|
||||
value = matcher.group(5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SingleEvent{" +
|
||||
"time=" + time +
|
||||
", device='" + device + '\'' +
|
||||
", type='" + type + '\'' +
|
||||
", code='" + code + '\'' +
|
||||
", value='" + value + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
public String convertToCode(String events) {
|
||||
BufferedReader reader = new BufferedReader(new StringReader(events));
|
||||
String line;
|
||||
StringBuilder code = new StringBuilder();
|
||||
try {
|
||||
EventConverter converter = null;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
SingleEvent event = new SingleEvent(line);
|
||||
if (event.value.equals("DOWN") && event.type.equals("BIN_TOUCH")) {
|
||||
converter = new EventConverter();
|
||||
} else if (event.value.equals("UP") && event.type.equals("BIN_TOUCH")) {
|
||||
code.append(converter.toString());
|
||||
converter = null;
|
||||
} else if (converter != null) {
|
||||
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return code.toString();
|
||||
}
|
||||
|
||||
public static class EventConverter {
|
||||
|
||||
List<SingleEvent> mSingleEvents = new ArrayList<>();
|
||||
|
||||
public void add(SingleEvent event) {
|
||||
if (event.type.equals("ABS_MT_POSITION_X") || event.type.equals("ABS_MT_POSITION_Y")) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
package com.stardust.scriptdroid.record.root;
|
||||
|
||||
import android.util.Pair;
|
||||
|
||||
import com.stardust.scriptdroid.tool.Shell;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.CharArrayWriter;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/6.
|
||||
*/
|
||||
|
||||
public class InputEventRecorder {
|
||||
|
||||
private Thread mRecordThread;
|
||||
private Shell mShell;
|
||||
|
||||
public void record() {
|
||||
mShell = new Shell(true);
|
||||
mRecordThread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
mShell.execute("getevent -t");
|
||||
readOutput(mShell);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
mRecordThread.start();
|
||||
}
|
||||
|
||||
private void readOutput(Shell shell) {
|
||||
String line;
|
||||
try {
|
||||
BufferedReader succeedReader = shell.getSucceedReader();
|
||||
StringBuilder succeedOutput = shell.getSucceedOutput();
|
||||
double time = 0;
|
||||
DecimalFormat df = new DecimalFormat("#.###");
|
||||
while ((line = succeedReader.readLine()) != null) {
|
||||
if (line.startsWith("[")) {
|
||||
Pair<Double, String> c = InputEventConverter.convert(line);
|
||||
if (time == 0) {
|
||||
time = c.first;
|
||||
} else if (c.first - time > 0.1f) {
|
||||
succeedOutput.append("sleep ").append(df.format(c.first - time)).append("\n");
|
||||
time = c.first;
|
||||
}
|
||||
succeedOutput.append(c.second).append("\n");
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public String stop() {
|
||||
mRecordThread.interrupt();
|
||||
mShell.destroy();
|
||||
return mShell.getSucceedOutput().toString();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,14 +1,29 @@
|
||||
package com.stardust.scriptdroid.tool;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.res.AssetFileDescriptor;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
|
||||
import com.stardust.scriptdroid.record.root.InputEventConverter;
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stericson.RootShell.RootShell;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
import jackpal.androidterm.ShellTermSession;
|
||||
import jackpal.androidterm.Term;
|
||||
import jackpal.androidterm.emulatorview.TermSession;
|
||||
import jackpal.androidterm.util.TermSettings;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/20.
|
||||
* <p>
|
||||
@@ -33,13 +48,56 @@ public class Shell {
|
||||
private StringBuilder mSucceedOutput = new StringBuilder();
|
||||
private StringBuilder mErrorOutput = new StringBuilder();
|
||||
|
||||
public static String bytesToString(byte[] data, int base, int length) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
|
||||
for(int i = 0; i < length; ++i) {
|
||||
byte b = data[base + i];
|
||||
if(b >= 32 && b <= 126) {
|
||||
buf.append((char)b);
|
||||
} else {
|
||||
buf.append(String.format("\\x%02x", new Object[]{Byte.valueOf(b)}));
|
||||
}
|
||||
}
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
|
||||
public static void test(final Activity activity) {
|
||||
TermSettings settings = new TermSettings(App.getApp().getResources(), PreferenceManager.getDefaultSharedPreferences(App.getApp()));
|
||||
try {
|
||||
final ShellTermSession termSession = new ShellTermSession(settings, "");
|
||||
termSession.initializeEmulator(80, 40);
|
||||
termSession.write("su\r");
|
||||
termSession.write("getevent\r");
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(termSession.getTermIn()));
|
||||
try {
|
||||
while (reader.ready()){
|
||||
String line = reader.readLine();
|
||||
System.out.println(line);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public Shell() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
public Shell(boolean root) {
|
||||
try {
|
||||
mProcess = Runtime.getRuntime().exec(root ? COMMAND_SU : COMMAND_SH);
|
||||
mProcess = new ProcessBuilder(root ? COMMAND_SU : COMMAND_SH).redirectErrorStream(true).start();
|
||||
mCommandOutputStream = new DataOutputStream(mProcess.getOutputStream());
|
||||
mSucceedReader = new BufferedReader(new InputStreamReader(mProcess.getInputStream()));
|
||||
mErrorReader = new BufferedReader(new InputStreamReader(mProcess.getErrorStream()));
|
||||
@@ -49,6 +107,7 @@ public class Shell {
|
||||
}
|
||||
|
||||
public Shell execute(String command) {
|
||||
|
||||
try {
|
||||
mCommandOutputStream.writeBytes(command);
|
||||
if (!command.endsWith(COMMAND_LINE_END)) {
|
||||
@@ -76,9 +135,9 @@ public class Shell {
|
||||
}
|
||||
|
||||
public Shell readSucceedOutput() {
|
||||
String line;
|
||||
try {
|
||||
while ((line = mSucceedReader.readLine()) != null) {
|
||||
while (mSucceedReader.ready()) {
|
||||
String line = mSucceedReader.readLine();
|
||||
mSucceedOutput.append(line).append("\n");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
@@ -129,6 +188,14 @@ public class Shell {
|
||||
return mErrorReader;
|
||||
}
|
||||
|
||||
public int waitFor() {
|
||||
try {
|
||||
return mProcess.waitFor();
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Command执行结果
|
||||
*
|
||||
|
||||
@@ -29,20 +29,25 @@ import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.afollestad.materialdialogs.folderselector.FileChooserDialog;
|
||||
import com.stardust.app.NotRemindAgainDialog;
|
||||
import com.stardust.app.OnActivityResultDelegate;
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.BuildConfig;
|
||||
import com.stardust.scriptdroid.Pref;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.droid.runtime.DroidRuntime;
|
||||
import com.stardust.scriptdroid.droid.script.file.ScriptFile;
|
||||
import com.stardust.scriptdroid.droid.script.file.ScriptFileList;
|
||||
import com.stardust.scriptdroid.droid.script.file.SharedPrefScriptFileList;
|
||||
import com.stardust.scriptdroid.external.notification.record.ActionRecordSwitchNotification;
|
||||
import com.stardust.scriptdroid.file.FileUtils;
|
||||
import com.stardust.scriptdroid.file.SampleFileManager;
|
||||
import com.stardust.scriptdroid.record.root.InputEventRecorder;
|
||||
import com.stardust.scriptdroid.record.inputevent.InputEventRecorder;
|
||||
import com.stardust.scriptdroid.record.inputevent.InputEventToJsConverter;
|
||||
import com.stardust.scriptdroid.record.inputevent.InputEventToJsRecorder;
|
||||
import com.stardust.scriptdroid.service.AccessibilityWatchDogService;
|
||||
import com.stardust.scriptdroid.tool.AccessibilityServiceTool;
|
||||
import com.stardust.scriptdroid.tool.BackPressedHandler;
|
||||
import com.stardust.scriptdroid.tool.ImageSelector;
|
||||
import com.stardust.scriptdroid.tool.Shell;
|
||||
import com.stardust.scriptdroid.ui.BaseActivity;
|
||||
import com.stardust.scriptdroid.ui.main.operation.ScriptFileOperation;
|
||||
import com.stardust.scriptdroid.ui.settings.SettingsActivity;
|
||||
@@ -64,6 +69,7 @@ public class MainActivity extends BaseActivity implements FileChooserDialog.File
|
||||
public static final String ACTION_NOTIFY_SCRIPT_LIST_CHANGE = "ACTION_NOTIFY_SCRIPT_LIST_CHANGE";
|
||||
private static final String ACTION_ON_ACTION_RECORD_STOPPED = "ACTION_ON_ACTION_RECORD_STOPPED";
|
||||
private static final String ARGUMENT_SCRIPT = "ARGUMENT_SCRIPT";
|
||||
private static final String ACTION_ON_ROOT_RECORD_STOPPED = "ACTION_ON_ROOT_RECORD_STOPPED";
|
||||
|
||||
private SlidingUpPanel mAddFilePanel;
|
||||
private ScriptListRecyclerView mScriptListRecyclerView;
|
||||
@@ -79,6 +85,7 @@ public class MainActivity extends BaseActivity implements FileChooserDialog.File
|
||||
checkPermissions();
|
||||
registerReceivers();
|
||||
handleIntent(getIntent());
|
||||
//Shell.test(this);
|
||||
}
|
||||
|
||||
private void registerReceivers() {
|
||||
@@ -226,6 +233,17 @@ public class MainActivity extends BaseActivity implements FileChooserDialog.File
|
||||
Snackbar.make(mDrawerLayout, R.string.hint_start_record, Snackbar.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
private InputEventRecorder mInputEventRecorder;
|
||||
|
||||
@ViewBinding.Click(R.id.root_record)
|
||||
private void startRootRecord() {
|
||||
if (mInputEventRecorder == null) {
|
||||
mInputEventRecorder = new InputEventToJsRecorder();
|
||||
mInputEventRecorder.listen();
|
||||
}
|
||||
Snackbar.make(mDrawerLayout, R.string.hint_start_root_record, Snackbar.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@ViewBinding.Click(R.id.setting)
|
||||
private void startSettingActivity() {
|
||||
startActivity(new Intent(this, SettingsActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
@@ -275,6 +293,13 @@ public class MainActivity extends BaseActivity implements FileChooserDialog.File
|
||||
case ACTION_ON_ACTION_RECORD_STOPPED:
|
||||
handleRecordedScript(intent.getStringExtra(ARGUMENT_SCRIPT));
|
||||
break;
|
||||
case ACTION_ON_ROOT_RECORD_STOPPED:
|
||||
if (mInputEventRecorder != null) {
|
||||
mInputEventRecorder.stop();
|
||||
handleRecordedScript(mInputEventRecorder.getCode());
|
||||
mInputEventRecorder = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,6 +319,14 @@ public class MainActivity extends BaseActivity implements FileChooserDialog.File
|
||||
}
|
||||
}
|
||||
})
|
||||
.negativeText(R.string.text_cancel)
|
||||
.onNegative(new MaterialDialog.SingleButtonCallback() {
|
||||
@Override
|
||||
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
})
|
||||
.canceledOnTouchOutside(false)
|
||||
.show();
|
||||
|
||||
}
|
||||
@@ -331,6 +364,14 @@ public class MainActivity extends BaseActivity implements FileChooserDialog.File
|
||||
}
|
||||
|
||||
|
||||
public static void onRootRecordStopped(Context context) {
|
||||
Intent intent = new Intent(context, MainActivity.class)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
.putExtra(EXTRA_ACTION, ACTION_ON_ROOT_RECORD_STOPPED);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
|
||||
private class Receiver extends BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
|
||||
BIN
app/src/main/jniLibs/armeabi/libjackpal-androidterm5.so
Normal file
BIN
app/src/main/jniLibs/armeabi/libjackpal-androidterm5.so
Normal file
Binary file not shown.
BIN
app/src/main/jniLibs/armeabi/libjackpal-termexec2.so
Normal file
BIN
app/src/main/jniLibs/armeabi/libjackpal-termexec2.so
Normal file
Binary file not shown.
BIN
app/src/main/jniLibs/mips/libjackpal-androidterm5.so
Normal file
BIN
app/src/main/jniLibs/mips/libjackpal-androidterm5.so
Normal file
Binary file not shown.
BIN
app/src/main/jniLibs/mips/libjackpal-termexec2.so
Normal file
BIN
app/src/main/jniLibs/mips/libjackpal-termexec2.so
Normal file
Binary file not shown.
BIN
app/src/main/jniLibs/x86/libjackpal-androidterm5.so
Normal file
BIN
app/src/main/jniLibs/x86/libjackpal-androidterm5.so
Normal file
Binary file not shown.
BIN
app/src/main/jniLibs/x86/libjackpal-termexec2.so
Normal file
BIN
app/src/main/jniLibs/x86/libjackpal-termexec2.so
Normal file
Binary file not shown.
@@ -133,6 +133,31 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/root_record"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.stardust.theme.widget.ThemeColorImageView
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:padding="10dp"
|
||||
android:src="@drawable/ic_video_record"/>
|
||||
|
||||
<com.stardust.theme.widget.ThemeColorTextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="@string/text_root_script_record"
|
||||
android:textColor="@color/colorPrimary"
|
||||
android:textSize="16sp"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.stardust.widget.SlidingUpPanel>
|
||||
|
||||
@@ -135,4 +135,6 @@
|
||||
<string name="text_theme_color">主题色</string>
|
||||
<string name="text_select_image">选择图片</string>
|
||||
<string name="text_help">帮助</string>
|
||||
<string name="text_root_script_record">录制脚本(root)</string>
|
||||
<string name="hint_start_root_record">使用音量上键,音量下键结束录制</string>
|
||||
</resources>
|
||||
|
||||
@@ -1,28 +1,9 @@
|
||||
package com.stardust.scriptdroid;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.util.Pair;
|
||||
import com.stardust.scriptdroid.record.inputevent.InputEventToJsConverter;
|
||||
import com.stardust.scriptdroid.record.inputevent.InputEventToSendEventConverter;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.stardust.scriptdroid.record.root.InputEventConverter;
|
||||
import com.stardust.scriptdroid.ui.help.HelpCatalogueActivity;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import org.junit.Test;
|
||||
import org.mozilla.javascript.Context;
|
||||
import org.mozilla.javascript.ContextFactory;
|
||||
import org.mozilla.javascript.ImporterTopLevel;
|
||||
import org.mozilla.javascript.Scriptable;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
@@ -38,6 +19,8 @@ public class ExampleUnitTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
System.out.println(new SingleEvent("[ 109722.085815] /dev/input/event1: EV_SYN SYN_REPORT 00000000"));
|
||||
InputEventToJsConverter converter = new InputEventToJsConverter();
|
||||
converter.parseAndAddEventIfFormatCorrect("[ 140123.672100] /dev/input/event3: EV_ABS ABS_MT_POSITION_X 0000005f");
|
||||
System.out.println(converter.getCode());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user