Release 2.0.1Beta
This commit is contained in:
@@ -16,16 +16,16 @@ public interface OnActivityResultDelegate {
|
||||
void onActivityResult(int requestCode, int resultCode, Intent data);
|
||||
|
||||
interface DelegateHost {
|
||||
Manager getDelegateManger();
|
||||
Intermediary getDelegateManger();
|
||||
}
|
||||
|
||||
class Manager implements OnActivityResultDelegate {
|
||||
class Intermediary implements OnActivityResultDelegate {
|
||||
|
||||
private SparseArray<OnActivityResultDelegate> specialDelegate = new SparseArray<>();
|
||||
private SparseArray<OnActivityResultDelegate> mSpecialDelegate = new SparseArray<>();
|
||||
private List<OnActivityResultDelegate> mDelegates = new ArrayList<>();
|
||||
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
OnActivityResultDelegate delegate = specialDelegate.get(requestCode);
|
||||
OnActivityResultDelegate delegate = mSpecialDelegate.get(requestCode);
|
||||
if (delegate != null) {
|
||||
delegate.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
@@ -39,7 +39,14 @@ public interface OnActivityResultDelegate {
|
||||
}
|
||||
|
||||
public void addDelegate(int requestCode, OnActivityResultDelegate delegate) {
|
||||
specialDelegate.put(requestCode, delegate);
|
||||
mSpecialDelegate.put(requestCode, delegate);
|
||||
}
|
||||
|
||||
public void removeDelegate(OnActivityResultDelegate delegate) {
|
||||
if (mDelegates.remove(delegate)) {
|
||||
// TODO: 2017/3/16 优化
|
||||
mSpecialDelegate.removeAt(mSpecialDelegate.indexOfValue(delegate));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -183,7 +183,6 @@ public class HoverMenuView extends RelativeLayout {
|
||||
MagnetPositioner magnetPositioner = new MagnetPositioner(getResources().getDisplayMetrics(), mSidePullerPositioner, new MagnetPositioner.OnCompletionListener() {
|
||||
@Override
|
||||
public void onPullToSideCompleted() {
|
||||
// TODO: this collapsed logic is duplicated
|
||||
mVisualState = COLLAPSED;
|
||||
enableDragging();
|
||||
mTransitionListener.onCollapsed();
|
||||
@@ -257,7 +256,6 @@ public class HoverMenuView extends RelativeLayout {
|
||||
removeAllTabs();
|
||||
addAllTabs();
|
||||
|
||||
// TODO: need null check in case selected tab is gone.
|
||||
Log.d(TAG, "Content change. Active id: " + mActiveTabId);
|
||||
Log.d(TAG, "Active tab view: " + findViewById(mActiveTabId.hashCode()));
|
||||
mActiveTab = findViewById(mActiveTabId.hashCode());
|
||||
@@ -270,7 +268,7 @@ public class HoverMenuView extends RelativeLayout {
|
||||
super(context);
|
||||
mWindowDragWatcher = windowDragWatcher;
|
||||
mMenuAnchor = new CollapsedMenuAnchor(getResources().getDisplayMetrics(), 10);
|
||||
mMenuAnchor.setAnchorAt((int) savedAnchor.x, savedAnchor.y); // TODO: savedAnchor isn't really a position, its a tuple of values (side, y-pos)
|
||||
mMenuAnchor.setAnchorAt((int) savedAnchor.x, savedAnchor.y);
|
||||
mNavigator = null == navigator ? new DefaultNavigator(context) : navigator;
|
||||
init();
|
||||
}
|
||||
@@ -335,7 +333,6 @@ public class HoverMenuView extends RelativeLayout {
|
||||
mExitRequestListener = null == exitRequestListener ? new NoOpHoverMenuExitRequestListener() : exitRequestListener;
|
||||
}
|
||||
|
||||
// TODO: create custom object to hold anchor state
|
||||
public PointF getAnchorState() {
|
||||
return new PointF(mMenuAnchor.getAnchorSide(), mMenuAnchor.getAnchorNormalizedY());
|
||||
}
|
||||
@@ -493,7 +490,6 @@ public class HoverMenuView extends RelativeLayout {
|
||||
Log.d(TAG, "Enabling dragging - x: " + anchorPosition.x + ", y: " + anchorPosition.y);
|
||||
Log.d(TAG, "Drag width: " + mTabSizeInPx + ", height: " + mTabSizeInPx);
|
||||
|
||||
// TODO: should create a method specifically for placing the drag bounds.
|
||||
mWindowDragWatcher.deactivate();
|
||||
mWindowDragWatcher.activate(mDragListener, new Rect(
|
||||
anchorPosition.x,
|
||||
@@ -548,7 +544,6 @@ public class HoverMenuView extends RelativeLayout {
|
||||
// Select the first tab.
|
||||
setActiveTab(mTabIds.get(0));
|
||||
|
||||
// TODO: we might set an adapter while expanded - track down the need for this and change it.
|
||||
// We force a collapse because at this point we're in a weird initial state.
|
||||
doCollapse(true);
|
||||
}
|
||||
@@ -605,7 +600,6 @@ public class HoverMenuView extends RelativeLayout {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: how can we avoid this null check?
|
||||
if (null != mActiveTab) {
|
||||
Log.d(TAG, "Adjusting tab position due to layout change.");
|
||||
getCollapsedMenuViewController().onDragTo(new Point(
|
||||
|
||||
@@ -2,30 +2,27 @@ package com.stardust.scriptdroid;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Application;
|
||||
import android.graphics.Paint;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.text.TextPaint;
|
||||
import android.util.Log;
|
||||
|
||||
import com.stardust.automator.AccessibilityEventCommandHost;
|
||||
import com.stardust.scriptdroid.accessibility.AccessibilityInfoProvider;
|
||||
import com.stardust.scriptdroid.droid.runtime.DroidRuntime;
|
||||
import com.stardust.scriptdroid.droid.script.JavaScriptEngine;
|
||||
import com.stardust.scriptdroid.droid.script.RhinoJavaScriptEngine;
|
||||
import com.stardust.scriptdroid.droid.script.file.ScriptFileList;
|
||||
import com.stardust.scriptdroid.droid.script.file.SharedPrefScriptFileList;
|
||||
import com.stardust.scriptdroid.layout_inspector.LayoutInspector;
|
||||
import com.stardust.scriptdroid.record.AccessibilityRecorderDelegate;
|
||||
import com.stardust.scriptdroid.record.accessibility.AccessibilityActionRecorder;
|
||||
import com.stardust.scriptdroid.service.AccessibilityWatchDogService;
|
||||
import com.squareup.leakcanary.LeakCanary;
|
||||
import com.stardust.scriptdroid.droid.runtime.action.ActionPerformAccessibilityDelegate;
|
||||
import com.stardust.scriptdroid.tool.ViewTool;
|
||||
import com.stardust.scriptdroid.ui.error.ErrorReportActivity;
|
||||
import com.stardust.theme.ThemeColor;
|
||||
import com.stardust.theme.ThemeColorManager;
|
||||
import com.stardust.util.CrashHandler;
|
||||
import com.stardust.util.StateObserver;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/27.
|
||||
*/
|
||||
@@ -34,12 +31,12 @@ public class App extends Application {
|
||||
|
||||
private static final String TAG = "App";
|
||||
|
||||
private static WeakReference<App> instance;
|
||||
private static App instance;
|
||||
private static StateObserver stateObserver;
|
||||
private static WeakReference<Activity> currentActivity;
|
||||
private static Activity currentActivity;
|
||||
|
||||
public static App getApp() {
|
||||
return instance.get();
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static StateObserver getStateObserver() {
|
||||
@@ -49,26 +46,40 @@ public class App extends Application {
|
||||
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
ThemeColorManager.setDefaultThemeColor(new ThemeColor(getResources().getColor(R.color.colorPrimary), getResources().getColor(R.color.colorPrimaryDark), getResources().getColor(R.color.colorAccent)));
|
||||
ThemeColorManager.init(this);
|
||||
setUpDebugEnvironment();
|
||||
init();
|
||||
configApp();
|
||||
registerActivityLifecycleCallback();
|
||||
initAccessibilityServiceDelegates();
|
||||
}
|
||||
|
||||
private void setUpDebugEnvironment() {
|
||||
if (LeakCanary.isInAnalyzerProcess(this)) {
|
||||
return;
|
||||
}
|
||||
LeakCanary.install(this);
|
||||
if (!BuildConfig.DEBUG)
|
||||
Thread.setDefaultUncaughtExceptionHandler(new CrashHandler(ErrorReportActivity.class));
|
||||
instance = new WeakReference<>(this);
|
||||
}
|
||||
|
||||
private void init() {
|
||||
ThemeColorManager.setDefaultThemeColor(new ThemeColor(getResources().getColor(R.color.colorPrimary), getResources().getColor(R.color.colorPrimaryDark), getResources().getColor(R.color.colorAccent)));
|
||||
ThemeColorManager.init(this);
|
||||
instance = this;
|
||||
stateObserver = new StateObserver(PreferenceManager.getDefaultSharedPreferences(this));
|
||||
registerActivityLifecycleCallback();
|
||||
initAccessibilityServiceDelegates();
|
||||
}
|
||||
|
||||
private void configApp() {
|
||||
ScriptFileList.setImpl(SharedPrefScriptFileList.getInstance());
|
||||
JavaScriptEngine.setDefault(new RhinoJavaScriptEngine(DroidRuntime.getRuntime()));
|
||||
}
|
||||
|
||||
|
||||
private void initAccessibilityServiceDelegates() {
|
||||
AccessibilityWatchDogService.addDelegateIfNeeded(100, ActionPerformAccessibilityDelegate.class);
|
||||
AccessibilityWatchDogService.addDelegateIfNeeded(200, AccessibilityRecorderDelegate.getInstance());
|
||||
AccessibilityWatchDogService.addDelegateIfNeeded(300, AccessibilityEventCommandHost.instance);
|
||||
AccessibilityWatchDogService.addDelegateIfNeeded(400, AccessibilityInfoProvider.instance);
|
||||
AccessibilityWatchDogService.addDelegateIfNeeded(200, AccessibilityActionRecorder.getInstance());
|
||||
AccessibilityWatchDogService.addDelegateIfNeeded(300, AccessibilityEventCommandHost.getInstance());
|
||||
AccessibilityWatchDogService.addDelegateIfNeeded(400, AccessibilityInfoProvider.getInstance());
|
||||
AccessibilityWatchDogService.addDelegateIfNeeded(500, LayoutInspector.getInstance());
|
||||
|
||||
}
|
||||
@@ -77,7 +88,7 @@ public class App extends Application {
|
||||
registerActivityLifecycleCallbacks(new SimpleActivityLifecycleCallbacks() {
|
||||
@Override
|
||||
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
|
||||
currentActivity = new WeakReference<>(activity);
|
||||
currentActivity = activity;
|
||||
}
|
||||
|
||||
|
||||
@@ -88,14 +99,19 @@ public class App extends Application {
|
||||
|
||||
@Override
|
||||
public void onActivityResumed(Activity activity) {
|
||||
currentActivity = new WeakReference<>(activity);
|
||||
currentActivity = activity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityStopped(Activity activity) {
|
||||
currentActivity = null;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
public static Activity currentActivity() {
|
||||
return currentActivity.get();
|
||||
return currentActivity;
|
||||
}
|
||||
|
||||
public static String getResString(int id) {
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.stardust.scriptdroid.accessibility;
|
||||
|
||||
import android.util.SparseArray;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.util.SparseArrayEntries;
|
||||
|
||||
import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_CLICKED;
|
||||
import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_LONG_CLICKED;
|
||||
import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_SCROLLED;
|
||||
import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED;
|
||||
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD;
|
||||
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_SCROLL_FORWARD;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/16.
|
||||
*/
|
||||
|
||||
public class AccessibilityEventHelper {
|
||||
|
||||
private static final SparseArray<Integer> EVENT_ACTION_RES_ID_MAP = new SparseArrayEntries<Integer>()
|
||||
.entry(TYPE_VIEW_CLICKED, R.string.text_clicked)
|
||||
.entry(TYPE_VIEW_LONG_CLICKED, R.string.text_long_clicked)
|
||||
.entry(TYPE_VIEW_SCROLLED, R.string.text_scrolled)
|
||||
.entry(TYPE_VIEW_TEXT_CHANGED, R.string.text_text_changed)
|
||||
.sparseArray();
|
||||
|
||||
public static int getEventTypeNameResId(AccessibilityEvent event) {
|
||||
return EVENT_ACTION_RES_ID_MAP.get(event.getEventType());
|
||||
}
|
||||
}
|
||||
@@ -15,11 +15,15 @@ import com.stardust.view.accessibility.AccessibilityDelegate;
|
||||
|
||||
public class AccessibilityInfoProvider implements AccessibilityDelegate {
|
||||
|
||||
public static AccessibilityInfoProvider instance = new AccessibilityInfoProvider();
|
||||
private static AccessibilityInfoProvider instance = new AccessibilityInfoProvider();
|
||||
|
||||
private String mLatestPackage = "";
|
||||
private String mLatestActivity = "";
|
||||
|
||||
public static AccessibilityInfoProvider getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public synchronized String getLatestPackage() {
|
||||
return mLatestPackage;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.stardust.scriptdroid.droid;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import com.jraska.console.timber.ConsoleTree;
|
||||
import com.stardust.scriptdroid.App;
|
||||
@@ -15,6 +16,9 @@ import com.stardust.scriptdroid.tool.FileUtils;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.Serializable;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
@@ -26,12 +30,6 @@ public class Droid {
|
||||
|
||||
public static final java.lang.String STAY = "\"stay\";";
|
||||
|
||||
static {
|
||||
Timber.plant(new ConsoleTree.Builder()
|
||||
.infoColor(0xcc000000)
|
||||
.build());
|
||||
}
|
||||
|
||||
public static final String UI = "\"ui\";";
|
||||
|
||||
public interface OnRunFinishedListener extends Serializable {
|
||||
@@ -54,13 +52,13 @@ public class Droid {
|
||||
}
|
||||
|
||||
private static final DroidRuntime RUNTIME = DroidRuntime.getRuntime();
|
||||
public static final JavaScriptEngine JAVA_SCRIPT_ENGINE = new RhinoJavaScriptEngine(RUNTIME);
|
||||
public static final JavaScriptEngine JAVA_SCRIPT_ENGINE = JavaScriptEngine.getDefault();
|
||||
private static final OnRunFinishedListener DEFAULT_LISTENER = new SimpleOnRunFinishedListener() {
|
||||
@Override
|
||||
public void onException(@NonNull Exception e) {
|
||||
if (!(e instanceof ScriptStopException)) {
|
||||
if (!causedByInterruptedException(e)) {
|
||||
RUNTIME.toast(App.getApp().getString(R.string.text_error) + ": " + e.getMessage());
|
||||
Timber.e(e, App.getApp().getString(R.string.text_error));
|
||||
Timber.e(e.getMessage());
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -73,12 +71,22 @@ public class Droid {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static boolean causedByInterruptedException(Throwable e) {
|
||||
while (e != null) {
|
||||
if (e instanceof InterruptedException) {
|
||||
return true;
|
||||
}
|
||||
e = e.getCause();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void runScriptFile(File file) {
|
||||
runScriptFile(file, null);
|
||||
}
|
||||
|
||||
public void runScriptFile(File file, OnRunFinishedListener listener) {
|
||||
Timber.v("开始运行脚本文件: " + file);
|
||||
Timber.v(DateFormat.getTimeInstance().format(new Date()) + "/" + App.getResString(R.string.text_start_running) + file);
|
||||
listener = listener == null ? DEFAULT_LISTENER : listener;
|
||||
try {
|
||||
checkFile(file);
|
||||
|
||||
@@ -6,15 +6,23 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.SpannableString;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.Spanned;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import android.util.Log;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.jraska.console.timber.ConsoleTree;
|
||||
import com.stardust.scriptdroid.Pref;
|
||||
import com.stardust.scriptdroid.accessibility.AccessibilityInfoProvider;
|
||||
import com.stardust.scriptdroid.droid.runtime.action.ActionTarget;
|
||||
import com.stardust.scriptdroid.tool.AccessibilityServiceTool;
|
||||
import com.stardust.scriptdroid.service.AccessibilityWatchDogService;
|
||||
@@ -43,6 +51,18 @@ import timber.log.Timber;
|
||||
|
||||
public class DroidRuntime {
|
||||
|
||||
static {
|
||||
Timber.plant(new ConsoleTree.Builder()
|
||||
.minPriority(Log.VERBOSE)
|
||||
.verboseColor(0xff909090)
|
||||
.debugColor(0xffc88b48)
|
||||
.infoColor(0xffc9c9c9)
|
||||
.warnColor(0xffa97db6)
|
||||
.errorColor(0xffff534e)
|
||||
.assertColor(0xffff5540)
|
||||
.build());
|
||||
}
|
||||
|
||||
private static final String TAG = "DroidRuntime";
|
||||
private static DroidRuntime runtime = new DroidRuntime();
|
||||
|
||||
@@ -154,8 +174,11 @@ public class DroidRuntime {
|
||||
return performAction(target.createAction(AccessibilityNodeInfo.ACTION_PASTE));
|
||||
}
|
||||
|
||||
public void log(@Nullable Object str) {
|
||||
Timber.i("" + str);
|
||||
public void log(@Nullable Object o) {
|
||||
String str = o + "";
|
||||
SpannableString spannableString = new SpannableString(str);
|
||||
spannableString.setSpan(new ForegroundColorSpan(Color.BLACK), 0, str.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
Console.writeLine(spannableString);
|
||||
}
|
||||
|
||||
public void err(@Nullable Object o) {
|
||||
@@ -184,7 +207,7 @@ public class DroidRuntime {
|
||||
return (T) action.getResult();
|
||||
}
|
||||
|
||||
private void ensureAccessibilityServiceEnable() {
|
||||
public void ensureAccessibilityServiceEnable() {
|
||||
if (AccessibilityWatchDogService.getInstance() == null) {
|
||||
String errorMessage = null;
|
||||
if (AccessibilityServiceUtils.isAccessibilityServiceEnabled(App.getApp(), AccessibilityWatchDogService.class)) {
|
||||
@@ -232,14 +255,14 @@ public class DroidRuntime {
|
||||
return Shell.execCommand(cmd, root != 0);
|
||||
}
|
||||
|
||||
public String getPackageName() {
|
||||
public String currentPackage() {
|
||||
ensureAccessibilityServiceEnable();
|
||||
return ActionPerformAccessibilityDelegate.getLatestPackage();
|
||||
return AccessibilityInfoProvider.getInstance().getLatestPackage();
|
||||
}
|
||||
|
||||
public String getActivityName() {
|
||||
public String currentActivity() {
|
||||
ensureAccessibilityServiceEnable();
|
||||
return ActionPerformAccessibilityDelegate.getLatestActivity();
|
||||
return AccessibilityInfoProvider.getInstance().getLatestActivity();
|
||||
}
|
||||
|
||||
public UiSelector selector() {
|
||||
|
||||
@@ -69,8 +69,9 @@ public class UiSelector extends UiGlobalSelector {
|
||||
private static final String TAG = "UiSelector";
|
||||
|
||||
public UiObjectCollection find() {
|
||||
DroidRuntime.getRuntime().ensureAccessibilityServiceEnable();
|
||||
FindCommand command = new FindCommand();
|
||||
AccessibilityEventCommandHost.instance.executeAndWaitForEvent(command);
|
||||
AccessibilityEventCommandHost.getInstance().executeAndWaitForEvent(command);
|
||||
return command.result;
|
||||
}
|
||||
|
||||
@@ -85,11 +86,7 @@ public class UiSelector extends UiGlobalSelector {
|
||||
}
|
||||
|
||||
public UiObject findOne() {
|
||||
UiObjectCollection collection = find();
|
||||
if (collection == null || collection.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
return new UiObject(collection.get(0).getInfo());
|
||||
return untilFindOne();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -103,7 +100,7 @@ public class UiSelector extends UiGlobalSelector {
|
||||
addFilter(new DfsFilter() {
|
||||
@Override
|
||||
protected boolean isIncluded(AccessibilityNodeInfo nodeInfo) {
|
||||
String fullId = AccessibilityInfoProvider.instance.getLatestPackage() + ":id/" + id;
|
||||
String fullId = AccessibilityInfoProvider.getInstance().getLatestPackage() + ":id/" + id;
|
||||
return fullId.equals(nodeInfo.getViewIdResourceName());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -23,28 +23,19 @@ public class ActionPerformAccessibilityDelegate implements AccessibilityDelegate
|
||||
|
||||
public static final Action NO_ACTION = null;
|
||||
|
||||
private static final Object ACTION_LOCK = new Object();
|
||||
|
||||
private static Action action;
|
||||
private static String latestPackage, latestActivity;
|
||||
|
||||
|
||||
public static void setAction(Action action) {
|
||||
synchronized (ActionPerformAccessibilityDelegate.class) {
|
||||
synchronized (ACTION_LOCK) {
|
||||
ActionPerformAccessibilityDelegate.action = action;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized static String getLatestPackage() {
|
||||
return latestPackage;
|
||||
}
|
||||
|
||||
public synchronized static String getLatestActivity() {
|
||||
return latestActivity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onAccessibilityEvent(AccessibilityService service, AccessibilityEvent event) {
|
||||
synchronized (ActionPerformAccessibilityDelegate.class) {
|
||||
setLatestComponent(event.getPackageName(), event.getClassName());
|
||||
synchronized (ACTION_LOCK) {
|
||||
if (action == NO_ACTION)
|
||||
return false;
|
||||
AccessibilityNodeInfo root = service.getRootInActiveWindow();
|
||||
@@ -66,26 +57,12 @@ public class ActionPerformAccessibilityDelegate implements AccessibilityDelegate
|
||||
|
||||
|
||||
private void onActionPerformed() {
|
||||
synchronized (ActionPerformAccessibilityDelegate.class) {
|
||||
synchronized (ACTION_LOCK) {
|
||||
action = NO_ACTION;
|
||||
DroidRuntime.getRuntime().notifyActionPerformed();
|
||||
}
|
||||
}
|
||||
|
||||
private static void setLatestComponent(CharSequence latestPackage, CharSequence latestClass) {
|
||||
if (latestPackage == null)
|
||||
return;
|
||||
ActionPerformAccessibilityDelegate.latestPackage = latestPackage.toString();
|
||||
if (latestClass == null)
|
||||
return;
|
||||
try {
|
||||
ComponentName componentName = new ComponentName(latestPackage.toString(), latestClass.toString());
|
||||
ActivityInfo activityInfo = App.getApp().getPackageManager().getActivityInfo(componentName, 0);
|
||||
ActionPerformAccessibilityDelegate.latestActivity = activityInfo.name;
|
||||
} catch (PackageManager.NameNotFoundException ignored) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,16 @@ import java.util.Map;
|
||||
|
||||
public abstract class JavaScriptEngine {
|
||||
|
||||
private static JavaScriptEngine defaultEngine;
|
||||
|
||||
public static JavaScriptEngine getDefault() {
|
||||
return defaultEngine;
|
||||
}
|
||||
|
||||
public static void setDefault(JavaScriptEngine engine) {
|
||||
defaultEngine = engine;
|
||||
}
|
||||
|
||||
Map<String, Object> mVariableMap = new HashMap<>();
|
||||
|
||||
public abstract Object execute(String script);
|
||||
@@ -26,6 +36,8 @@ public abstract class JavaScriptEngine {
|
||||
|
||||
public abstract int stopAll();
|
||||
|
||||
public abstract String[] getGlobalFunctions();
|
||||
|
||||
static class Init {
|
||||
private static final String INIT_SCRIPT = readInitScript();
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ public class RhinoJavaScriptEngine extends JavaScriptEngine {
|
||||
}
|
||||
|
||||
private final Set<Thread> mThreads = new HashSet<>();
|
||||
private String[] mFunctions;
|
||||
|
||||
public RhinoJavaScriptEngine(DroidRuntime runtime) {
|
||||
set("droid", runtime);
|
||||
@@ -51,6 +52,7 @@ public class RhinoJavaScriptEngine extends JavaScriptEngine {
|
||||
private Context createContext() {
|
||||
Context context = Context.enter();
|
||||
context.setOptimizationLevel(-1);
|
||||
context.setLanguageVersion(Context.VERSION_1_7);
|
||||
context.setInstructionObserverThreshold(10000);
|
||||
return context;
|
||||
}
|
||||
@@ -80,6 +82,24 @@ public class RhinoJavaScriptEngine extends JavaScriptEngine {
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String[] getGlobalFunctions() {
|
||||
if (mFunctions == null)
|
||||
mFunctions = getGlobalFunctionsInner();
|
||||
return mFunctions;
|
||||
}
|
||||
|
||||
private String[] getGlobalFunctionsInner() {
|
||||
Scriptable scriptable = (Scriptable) execute("this");
|
||||
Object[] ids = scriptable.getIds();
|
||||
String[] functions = new String[ids.length];
|
||||
for (int i = 0; i < ids.length; i++) {
|
||||
functions[i] = ids[i].toString();
|
||||
}
|
||||
return functions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAndDestroy() {
|
||||
synchronized (mThreads) {
|
||||
@@ -87,6 +107,7 @@ public class RhinoJavaScriptEngine extends JavaScriptEngine {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class InterruptibleContextFactory extends ContextFactory {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -8,6 +8,16 @@ import java.io.File;
|
||||
|
||||
public abstract class ScriptFileList {
|
||||
|
||||
private static ScriptFileList impl;
|
||||
|
||||
public static void setImpl(ScriptFileList list) {
|
||||
impl = list;
|
||||
}
|
||||
|
||||
public static ScriptFileList getImpl() {
|
||||
return impl;
|
||||
}
|
||||
|
||||
public abstract void add(ScriptFile scriptFile);
|
||||
|
||||
public abstract ScriptFile get(int i);
|
||||
@@ -24,6 +34,6 @@ public abstract class ScriptFileList {
|
||||
return file.delete();
|
||||
}
|
||||
|
||||
|
||||
public abstract boolean containsPath(String path);
|
||||
|
||||
}
|
||||
|
||||
@@ -33,9 +33,11 @@ public class FloatingWindowManger {
|
||||
Intent intent;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
|
||||
Uri.parse("package:" + packageName));
|
||||
Uri.parse("package:" + packageName))
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
} else {
|
||||
intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:" + packageName));
|
||||
intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:" + packageName))
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
}
|
||||
App.getApp().startActivity(intent);
|
||||
}
|
||||
|
||||
@@ -37,11 +37,9 @@ import io.mattcarroll.hover.NavigatorContent;
|
||||
public class HoverMenuAdapter implements io.mattcarroll.hover.HoverMenuAdapter {
|
||||
|
||||
|
||||
public static final String ID_MAIN = "intro";
|
||||
public static final String ID_MAIN = "main";
|
||||
public static final String ID_RECORD = "record";
|
||||
public static final String ID_SCRIPT_LIST = "script_list";
|
||||
public static final String MENU_ID = "menu";
|
||||
public static final String PLACEHOLDER_ID = "placeholder";
|
||||
|
||||
private final Context mContext;
|
||||
private final List<String> mTabIds;
|
||||
|
||||
@@ -7,6 +7,7 @@ import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.IBinder;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.Toast;
|
||||
@@ -50,8 +51,10 @@ public class HoverMenuService extends Service {
|
||||
public static final String MESSAGE_SHOW_LAYOUT_BOUNDS = "MESSAGE_SHOW_LAYOUT_BOUNDS";
|
||||
public static final String MESSAGE_COLLAPSE_MENU = "MESSAGE_COLLAPSE_MENU";
|
||||
public static final String MESSAGE_MENU_COLLAPSING = "MESSAGE_MENU_COLLAPSING";
|
||||
public static final String MESSAGE_MENU_EXPANDING = "MESSAGE_MENU_EXPANDING";
|
||||
public static final String MESSAGE_MENU_EXIT = "MESSAGE_MENU_EXIT";
|
||||
|
||||
private static WeakReference<HoverMenuService> service = new WeakReference<>(null);
|
||||
private static HoverMenuService service = null;
|
||||
private static boolean sIsRunning;
|
||||
|
||||
public static void startService(Context context) {
|
||||
@@ -64,8 +67,8 @@ public class HoverMenuService extends Service {
|
||||
}
|
||||
|
||||
public static void stopService() {
|
||||
if (isServiceRunning() && service.get() != null) {
|
||||
service.get().stopSelf();
|
||||
if (isServiceRunning() && service != null) {
|
||||
service.stopSelf();
|
||||
setIsRunning(false);
|
||||
}
|
||||
}
|
||||
@@ -92,6 +95,7 @@ public class HoverMenuService extends Service {
|
||||
private HoverMenu.OnExitListener mWindowHoverMenuMenuExitListener = new HoverMenu.OnExitListener() {
|
||||
@Override
|
||||
public void onExitByUserRequest() {
|
||||
EventBus.getDefault().post(new MessageEvent(MESSAGE_MENU_EXIT));
|
||||
savePreferredLocation();
|
||||
mWindowHoverMenu.hide();
|
||||
stopSelf();
|
||||
@@ -101,11 +105,11 @@ public class HoverMenuService extends Service {
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
if (service.get() != null) {
|
||||
if (service != null) {
|
||||
stopSelf();
|
||||
return;
|
||||
}
|
||||
service = new WeakReference<>(this);
|
||||
service = this;
|
||||
EventBus.getDefault().register(this);
|
||||
mPrefs = getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE);
|
||||
try {
|
||||
@@ -127,7 +131,7 @@ public class HoverMenuService extends Service {
|
||||
}
|
||||
|
||||
private void initWindowMenu() {
|
||||
mWindowHoverMenu = (WindowHoverMenu) new HoverMenuBuilder(this)
|
||||
mWindowHoverMenu = (WindowHoverMenu) new HoverMenuBuilder(new ContextThemeWrapper(this, R.style.AppTheme))
|
||||
.displayWithinWindow()
|
||||
.useAdapter(new HoverMenuAdapter(this))
|
||||
.restoreVisualState(loadPreferredLocation())
|
||||
@@ -138,6 +142,7 @@ public class HoverMenuService extends Service {
|
||||
mWindowHoverMenu.setHoverMenuTransitionListener(new SimpleHoverMenuTransitionListener() {
|
||||
@Override
|
||||
public void onExpanding() {
|
||||
EventBus.getDefault().post(new MessageEvent(MESSAGE_MENU_EXPANDING));
|
||||
captureCurrentWindow();
|
||||
}
|
||||
|
||||
@@ -166,17 +171,20 @@ public class HoverMenuService extends Service {
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
mWindowHoverMenu.show();
|
||||
if (mWindowHoverMenu != null)
|
||||
mWindowHoverMenu.show();
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
mWindowHoverMenu.hide();
|
||||
EventBus.getDefault().unregister(this);
|
||||
if (mWindowHoverMenu != null)
|
||||
mWindowHoverMenu.hide();
|
||||
if (EventBus.getDefault().isRegistered(this))
|
||||
EventBus.getDefault().unregister(this);
|
||||
setIsRunning(false);
|
||||
if (service.get() == this)
|
||||
service.clear();
|
||||
if (service == this)
|
||||
service = null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,21 +1,28 @@
|
||||
package com.stardust.scriptdroid.external.floating_window.content;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.accessibility.AccessibilityInfoProvider;
|
||||
import com.stardust.scriptdroid.droid.Droid;
|
||||
import com.stardust.scriptdroid.external.floating_window.HoverMenuService;
|
||||
import com.stardust.scriptdroid.layout_inspector.LayoutInspector;
|
||||
import com.stardust.scriptdroid.tool.ClipboardTool;
|
||||
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 java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -36,11 +43,19 @@ public class MainMenuNavigatorContent implements NavigatorContent {
|
||||
|
||||
|
||||
private View mView;
|
||||
@ViewBinding.Id(R.id.current_package)
|
||||
private TextView mCurrentPackageTextView;
|
||||
@ViewBinding.Id(R.id.current_activity)
|
||||
private TextView mCurrentActivityTextView;
|
||||
private String mCurrentPackage, mCurrentActivity;
|
||||
private Context mContext;
|
||||
|
||||
|
||||
public MainMenuNavigatorContent(Context context) {
|
||||
mContext = context;
|
||||
mView = View.inflate(context, R.layout.floating_window_main_menu, null);
|
||||
ViewBinder.bind(this);
|
||||
EventBus.getDefault().register(this);
|
||||
}
|
||||
|
||||
@ViewBinding.Click(R.id.layout_hierarchy)
|
||||
@@ -70,6 +85,13 @@ public class MainMenuNavigatorContent implements NavigatorContent {
|
||||
Toast.makeText(mView.getContext(), R.string.text_no_running_script, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@ViewBinding.Click(R.id.open_launcher)
|
||||
private void openMainActivity() {
|
||||
App.getApp().startActivity(new Intent(App.getApp(), MainActivity.class)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY | Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
EventBus.getDefault().post(new MessageEvent(HoverMenuService.MESSAGE_COLLAPSE_MENU));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public View getView() {
|
||||
@@ -81,11 +103,40 @@ public class MainMenuNavigatorContent implements NavigatorContent {
|
||||
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private void syncCurrentInfo() {
|
||||
mCurrentPackage = AccessibilityInfoProvider.getInstance().getLatestPackage();
|
||||
mCurrentActivity = AccessibilityInfoProvider.getInstance().getLatestActivity();
|
||||
mCurrentActivityTextView.setText(mContext.getString(R.string.text_current_activity) + mCurrentActivity);
|
||||
mCurrentPackageTextView.setText(mContext.getString(R.string.text_current_package) + mCurrentPackage);
|
||||
}
|
||||
|
||||
@ViewBinding.Click(R.id.current_activity)
|
||||
private void copyCurrentActivity() {
|
||||
ClipboardTool.setClip(mCurrentActivity);
|
||||
Toast.makeText(mContext, R.string.text_copied, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@ViewBinding.Click(R.id.current_package)
|
||||
private void copyCurrentPackage() {
|
||||
ClipboardTool.setClip(mCurrentPackage);
|
||||
Toast.makeText(mContext, R.string.text_copied, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHidden() {
|
||||
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onMessageEvent(MessageEvent event) {
|
||||
if (event.message.equals(HoverMenuService.MESSAGE_MENU_EXPANDING)) {
|
||||
syncCurrentInfo();
|
||||
} else if (event.message.equals(HoverMenuService.MESSAGE_MENU_EXIT)) {
|
||||
EventBus.getDefault().unregister(this);
|
||||
}
|
||||
}
|
||||
|
||||
public View findViewById(int id) {
|
||||
return mView.findViewById(id);
|
||||
}
|
||||
|
||||
@@ -2,24 +2,61 @@ package com.stardust.scriptdroid.external.floating_window.content;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.widget.SwitchCompat;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.accessibility.AccessibilityEventHelper;
|
||||
import com.stardust.scriptdroid.external.floating_window.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.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;
|
||||
import io.mattcarroll.hover.NavigatorContent;
|
||||
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/12.
|
||||
*/
|
||||
|
||||
public class RecordNavigatorContent implements NavigatorContent {
|
||||
public class RecordNavigatorContent implements NavigatorContent, Recorder.OnStateChangedListener {
|
||||
|
||||
private View mView;
|
||||
@ViewBinding.Id(R.id.sw_recorded_by_root)
|
||||
private SwitchCompat mRecordedByRootSwitch;
|
||||
|
||||
@ViewBinding.Id(R.id.sw_record_toast)
|
||||
private SwitchCompat mRecordToastSwitch;
|
||||
|
||||
@ViewBinding.Id(R.id.img_start_or_pause)
|
||||
private ImageView mStartOrPauseRecordIcon;
|
||||
|
||||
@ViewBinding.Id(R.id.text_start_or_pause)
|
||||
private TextView mStartOrPauseRecordText;
|
||||
|
||||
|
||||
@ViewBinding.Id(R.id.stop_record)
|
||||
private View mStopRecord;
|
||||
|
||||
private Recorder mRecorder;
|
||||
private Context mContext;
|
||||
|
||||
public RecordNavigatorContent(Context context) {
|
||||
mView = new View(context);
|
||||
mContext = context;
|
||||
mView = View.inflate(context, R.layout.floating_window_record, null);
|
||||
ViewBinder.bind(this);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -30,11 +67,118 @@ public class RecordNavigatorContent implements NavigatorContent {
|
||||
|
||||
@Override
|
||||
public void onShown(@NonNull Navigator navigator) {
|
||||
|
||||
if (!EventBus.getDefault().isRegistered(this)) {
|
||||
EventBus.getDefault().register(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHidden() {
|
||||
if (EventBus.getDefault().isRegistered(this)) {
|
||||
EventBus.getDefault().unregister(this);
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBinding.Click(R.id.sw_root_container)
|
||||
private void toggleRecordedByRootSwitch() {
|
||||
mRecordedByRootSwitch.toggle();
|
||||
}
|
||||
|
||||
@ViewBinding.Click(R.id.sw_record_toast_container)
|
||||
private void toggleRecordToastSwitch() {
|
||||
mRecordToastSwitch.toggle();
|
||||
}
|
||||
|
||||
@ViewBinding.Click(R.id.start_or_pause)
|
||||
private void startOrPauseRecord() {
|
||||
if (mRecorder == null) {
|
||||
startRecord();
|
||||
} else if (mRecorder.getState() == Recorder.STATE_PAUSED) {
|
||||
resumeRecord();
|
||||
} else {
|
||||
pauseRecord();
|
||||
}
|
||||
}
|
||||
|
||||
private void resumeRecord() {
|
||||
mRecorder.resume();
|
||||
setState(Recorder.STATE_RECORDING);
|
||||
EventBus.getDefault().post(new MessageEvent(HoverMenuService.MESSAGE_COLLAPSE_MENU));
|
||||
}
|
||||
|
||||
private void pauseRecord() {
|
||||
mRecorder.pause();
|
||||
setState(Recorder.STATE_PAUSED);
|
||||
}
|
||||
|
||||
private void startRecord() {
|
||||
mRecorder = mRecordedByRootSwitch.isChecked() ? new TouchRecorder() : AccessibilityActionRecorder.getInstance();
|
||||
AccessibilityActionRecorder.getInstance().setRecordMessageEnabled(mRecordToastSwitch.isChecked());
|
||||
mRecorder.setOnStateChangedListener(this);
|
||||
mRecorder.start();
|
||||
setState(Recorder.STATE_RECORDING);
|
||||
EventBus.getDefault().post(new MessageEvent(HoverMenuService.MESSAGE_COLLAPSE_MENU));
|
||||
}
|
||||
|
||||
private void setState(int state) {
|
||||
mStopRecord.setVisibility(state == Recorder.STATE_STOPPED ? View.GONE : View.VISIBLE);
|
||||
mStartOrPauseRecordIcon.setImageResource(state == Recorder.STATE_RECORDING ? R.drawable.ic_pause_white_24dp : R.drawable.ic_play_arrow_white_48dp);
|
||||
//我知道这样写代码会被打 但我懒...
|
||||
mStartOrPauseRecordText.setText(state == Recorder.STATE_RECORDING ? R.string.text_pause_record :
|
||||
state == Recorder.STATE_PAUSED ? R.string.text_resume_record : R.string.text_start_record);
|
||||
|
||||
}
|
||||
|
||||
@ViewBinding.Click(R.id.stop_record)
|
||||
private void stopRecord() {
|
||||
mRecorder.stop();
|
||||
setState(Recorder.STATE_STOPPED);
|
||||
EventBus.getDefault().post(new MessageEvent(HoverMenuService.MESSAGE_COLLAPSE_MENU));
|
||||
}
|
||||
|
||||
|
||||
public View findViewById(int id) {
|
||||
return mView.findViewById(id);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onMessageEvent(MessageEvent event) {
|
||||
if (event.message.equals(HoverMenuService.MESSAGE_MENU_EXPANDING)) {
|
||||
pauseRecord();
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onAccessibilityActionRecordEvent(AccessibilityActionRecorder.AccessibilityActionRecordEvent event) {
|
||||
if (mRecordToastSwitch.isChecked()) {
|
||||
Toast.makeText(mContext, AccessibilityEventHelper.getEventTypeNameResId(event.getAccessibilityEvent()), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onTouchRecorderStateChanged(InputEventConverter.RecordStateChangeEvent event) {
|
||||
if (!event.isRecording()) {
|
||||
stopRecord();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
Toast.makeText(mContext, R.string.text_start_record, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
MainActivity.onActionRecordStopped(mContext, mRecorder.getCode());
|
||||
mRecorder = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.view.ContextThemeWrapper;
|
||||
import android.view.View;
|
||||
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.droid.script.file.ScriptFileList;
|
||||
import com.stardust.scriptdroid.droid.script.file.SharedPrefScriptFileList;
|
||||
import com.stardust.scriptdroid.external.floating_window.view.FloatingScriptFileListView;
|
||||
|
||||
@@ -22,7 +23,7 @@ public class ScritpListNavigatorContent implements NavigatorContent {
|
||||
|
||||
public ScritpListNavigatorContent(Context context) {
|
||||
mFloatingScriptFileListView = new FloatingScriptFileListView(new ContextThemeWrapper(context, R.style.AppTheme));
|
||||
mFloatingScriptFileListView.setScriptFileList(SharedPrefScriptFileList.getInstance());
|
||||
mFloatingScriptFileListView.setScriptFileList(ScriptFileList.getImpl());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
package com.stardust.scriptdroid.external.notification.record;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.record.Recorder;
|
||||
import com.stardust.scriptdroid.record.accessibility.AccessibilityActionRecorder;
|
||||
import com.stardust.scriptdroid.service.AccessibilityWatchDogService;
|
||||
import com.stardust.scriptdroid.service.VolumeChangeObverseService;
|
||||
import com.stardust.scriptdroid.ui.main.MainActivity;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/2/14.
|
||||
*/
|
||||
|
||||
public class AccessibilityActionRecordNotification {
|
||||
|
||||
private static final String INTENT_ACTION = " com.stardust.scriptdroid.Record";
|
||||
private static final String EXTRA_ACTION = "action";
|
||||
private static final int ACTION_STOP = 17771;
|
||||
private static final int ACTION_START_OR_PAUSE = 17772;
|
||||
private static final int ACTION_DELETE = 17773;
|
||||
private static final int ACTION_REDO = 17774;
|
||||
|
||||
private static final int NOTIFY_ID = 22236;
|
||||
private static NotificationCompat.Builder builder;
|
||||
private static BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
int action = intent.getIntExtra(EXTRA_ACTION, 0);
|
||||
switch (action) {
|
||||
case ACTION_STOP:
|
||||
stopRecord(context);
|
||||
collapseNotificationBar(context);
|
||||
break;
|
||||
case ACTION_START_OR_PAUSE:
|
||||
startOrPauseRecord(context);
|
||||
collapseNotificationBar(context);
|
||||
break;
|
||||
case ACTION_DELETE:
|
||||
AccessibilityActionRecordNotification.cancelNotification();
|
||||
stopRecordIfNeeded(context);
|
||||
VolumeChangeObverseService.stopServiceIfNeeded();
|
||||
break;
|
||||
case ACTION_REDO:
|
||||
redoRecord(context);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static PendingIntent getStartOrPauseIntent() {
|
||||
Intent intent = new Intent(INTENT_ACTION)
|
||||
.putExtra(EXTRA_ACTION, ACTION_START_OR_PAUSE);
|
||||
return PendingIntent.getBroadcast(App.getApp(), ACTION_START_OR_PAUSE, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}
|
||||
|
||||
static PendingIntent getStopIntent() {
|
||||
Intent intent = new Intent(INTENT_ACTION)
|
||||
.putExtra(EXTRA_ACTION, ACTION_STOP);
|
||||
return PendingIntent.getBroadcast(App.getApp(), ACTION_STOP, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}
|
||||
|
||||
static PendingIntent getDeleteIntent() {
|
||||
Intent intent = new Intent(INTENT_ACTION)
|
||||
.putExtra(EXTRA_ACTION, ACTION_DELETE);
|
||||
return PendingIntent.getBroadcast(App.getApp(), ACTION_DELETE, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}
|
||||
|
||||
|
||||
static PendingIntent getRedoIntent() {
|
||||
Intent intent = new Intent(INTENT_ACTION)
|
||||
.putExtra(EXTRA_ACTION, ACTION_REDO);
|
||||
return PendingIntent.getService(App.getApp(), ACTION_REDO, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}
|
||||
|
||||
public static void showOrUpdateNotification() {
|
||||
if (builder == null) {
|
||||
builder = new NotificationCompat.Builder(App.getApp())
|
||||
.setAutoCancel(false)
|
||||
.setSmallIcon(R.drawable.ic_robot_head)
|
||||
.setDeleteIntent(getDeleteIntent())
|
||||
.setCustomContentView(AccessibilityActionRecordSwitchView.getInstance());
|
||||
}
|
||||
showNotification(builder.build());
|
||||
VolumeChangeObverseService.startServiceIfNeeded(App.getApp());
|
||||
}
|
||||
|
||||
private static void showNotification(Notification notification) {
|
||||
NotificationManager notificationManager = (NotificationManager) App.getApp().getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.notify(NOTIFY_ID, notification);
|
||||
App.getApp().registerReceiver(broadcastReceiver, new IntentFilter(INTENT_ACTION));
|
||||
}
|
||||
|
||||
public static void cancelNotification() {
|
||||
NotificationManager notificationManager = (NotificationManager) App.getApp().getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.cancel(NOTIFY_ID);
|
||||
App.getApp().unregisterReceiver(broadcastReceiver);
|
||||
}
|
||||
|
||||
private static void collapseNotificationBar(Context context) {
|
||||
context.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
|
||||
}
|
||||
|
||||
private static void stopRecordIfNeeded(Context context) {
|
||||
int state = AccessibilityActionRecorder.getInstance().getState();
|
||||
if (state == Recorder.STATE_RECORDING || state == Recorder.STATE_PAUSED) {
|
||||
stopRecord(context);
|
||||
}
|
||||
}
|
||||
|
||||
private static void startOrPauseRecord(Context context) {
|
||||
int state = AccessibilityActionRecorder.getInstance().getState();
|
||||
if (state == Recorder.STATE_PAUSED) {
|
||||
resumeRecord(context);
|
||||
} else if (state == Recorder.STATE_RECORDING) {
|
||||
pauseRecord(context);
|
||||
} else {
|
||||
//state == STOPPED
|
||||
startRecord(context);
|
||||
}
|
||||
}
|
||||
|
||||
public static void startRecord(Context context) {
|
||||
if (AccessibilityWatchDogService.getInstance() == null) {
|
||||
Toast.makeText(context, R.string.text_need_enable_accessibility_service, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
AccessibilityActionRecorder.getInstance().start();
|
||||
AccessibilityActionRecordSwitchView.getInstance().setState(Recorder.STATE_RECORDING);
|
||||
Toast.makeText(context, R.string.text_start_record, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
private static void pauseRecord(Context context) {
|
||||
AccessibilityActionRecorder.getInstance().pause();
|
||||
AccessibilityActionRecordSwitchView.getInstance().setState(Recorder.STATE_PAUSED);
|
||||
}
|
||||
|
||||
private static void resumeRecord(Context context) {
|
||||
AccessibilityActionRecorder.getInstance().resume();
|
||||
AccessibilityActionRecordSwitchView.getInstance().setState(Recorder.STATE_RECORDING);
|
||||
}
|
||||
|
||||
public static void stopRecord(Context context) {
|
||||
if (AccessibilityActionRecorder.getInstance().getState() != Recorder.STATE_STOPPED) {
|
||||
AccessibilityActionRecorder.getInstance().stop();
|
||||
String script = AccessibilityActionRecorder.getInstance().getCode();
|
||||
AccessibilityActionRecordSwitchView.getInstance().setState(Recorder.STATE_STOPPED);
|
||||
MainActivity.onActionRecordStopped(context, script);
|
||||
} else {
|
||||
Toast.makeText(App.getApp(), R.string.text_not_recording, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
private static void redoRecord(Context context) {
|
||||
if (AccessibilityActionRecorder.getInstance().getState() != Recorder.STATE_STOPPED) {
|
||||
AccessibilityActionRecorder.getInstance().stop();
|
||||
AccessibilityActionRecordSwitchView.getInstance().setState(Recorder.STATE_STOPPED);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,53 +4,50 @@ import android.widget.RemoteViews;
|
||||
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.record.Recorder;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/2/14.
|
||||
*/
|
||||
|
||||
public class ActionRecordSwitchView extends RemoteViews {
|
||||
public class AccessibilityActionRecordSwitchView extends RemoteViews {
|
||||
|
||||
private static ActionRecordSwitchView instance;
|
||||
private static AccessibilityActionRecordSwitchView instance;
|
||||
|
||||
public static final int STOPPED = 0;
|
||||
public static final int PAUSED = 1;
|
||||
public static final int RECORDING = 2;
|
||||
|
||||
public static ActionRecordSwitchView getInstance() {
|
||||
public static AccessibilityActionRecordSwitchView getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new ActionRecordSwitchView();
|
||||
instance = new AccessibilityActionRecordSwitchView();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private ActionRecordSwitchView() {
|
||||
private AccessibilityActionRecordSwitchView() {
|
||||
super(App.getApp().getPackageName(), R.layout.remote_views_record_switch);
|
||||
setUpOnClick();
|
||||
}
|
||||
|
||||
public void setState(int state) {
|
||||
switch (state) {
|
||||
case STOPPED:
|
||||
case Recorder.STATE_STOPPED:
|
||||
setImageViewResource(R.id.img_start_or_pause, R.drawable.ic_play_arrow_grey600_48dp);
|
||||
setTextViewText(R.id.text_start_or_pause, App.getApp().getString(R.string.text_start_record));
|
||||
break;
|
||||
case RECORDING:
|
||||
case Recorder.STATE_RECORDING:
|
||||
setImageViewResource(R.id.img_start_or_pause, R.drawable.ic_pause_grey600_48dp);
|
||||
setTextViewText(R.id.text_start_or_pause, App.getApp().getString(R.string.text_pause_record));
|
||||
break;
|
||||
case PAUSED:
|
||||
case Recorder.STATE_PAUSED:
|
||||
setImageViewResource(R.id.img_start_or_pause, R.drawable.ic_play_arrow_grey600_48dp);
|
||||
setTextViewText(R.id.text_start_or_pause, App.getApp().getString(R.string.text_resume_record));
|
||||
break;
|
||||
}
|
||||
ActionRecordSwitchNotification.showOrUpdateNotification();
|
||||
AccessibilityActionRecordNotification.showOrUpdateNotification();
|
||||
}
|
||||
|
||||
private void setUpOnClick() {
|
||||
setOnClickPendingIntent(R.id.stop, ActionRecordSwitchHandleService.getStopIntent());
|
||||
setOnClickPendingIntent(R.id.start_or_pause, ActionRecordSwitchHandleService.getStartOrPauseIntent());
|
||||
setOnClickPendingIntent(R.id.close, ActionRecordSwitchHandleService.getDeleteIntent());
|
||||
setOnClickPendingIntent(R.id.redo, ActionRecordSwitchHandleService.getRedoIntent());
|
||||
setOnClickPendingIntent(R.id.stop, AccessibilityActionRecordNotification.getStopIntent());
|
||||
setOnClickPendingIntent(R.id.start_or_pause, AccessibilityActionRecordNotification.getStartOrPauseIntent());
|
||||
setOnClickPendingIntent(R.id.close, AccessibilityActionRecordNotification.getDeleteIntent());
|
||||
setOnClickPendingIntent(R.id.redo, AccessibilityActionRecordNotification.getRedoIntent());
|
||||
}
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
package com.stardust.scriptdroid.external.notification.record;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.stardust.scriptdroid.record.AccessibilityRecorderDelegate;
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.service.AccessibilityWatchDogService;
|
||||
import com.stardust.scriptdroid.service.VolumeChangeListenService;
|
||||
import com.stardust.scriptdroid.ui.main.MainActivity;
|
||||
|
||||
import static com.stardust.scriptdroid.external.notification.record.ActionRecordSwitchView.PAUSED;
|
||||
import static com.stardust.scriptdroid.external.notification.record.ActionRecordSwitchView.RECORDING;
|
||||
import static com.stardust.scriptdroid.external.notification.record.ActionRecordSwitchView.STOPPED;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/2/15.
|
||||
*/
|
||||
|
||||
public class ActionRecordSwitchHandleService extends Service {
|
||||
|
||||
|
||||
private static final String EXTRA_INTENT_VALID = "ActionRecordSwitchHandleService.intentValid";
|
||||
private static final String EXTRA_ACTION = "action";
|
||||
private static final int ACTION_STOP = 17771;
|
||||
private static final int ACTION_START_OR_PAUSE = 17772;
|
||||
private static final int ACTION_DELETE = 17773;
|
||||
private static final int ACTION_REDO = 17774;
|
||||
|
||||
public static PendingIntent getStartOrPauseIntent() {
|
||||
Intent intent = new Intent(App.getApp(), ActionRecordSwitchHandleService.class)
|
||||
.putExtra(EXTRA_INTENT_VALID, true)
|
||||
.putExtra(EXTRA_ACTION, ACTION_START_OR_PAUSE);
|
||||
return PendingIntent.getService(App.getApp(), ACTION_START_OR_PAUSE, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}
|
||||
|
||||
public static PendingIntent getStopIntent() {
|
||||
Intent intent = new Intent(App.getApp(), ActionRecordSwitchHandleService.class)
|
||||
.putExtra(EXTRA_INTENT_VALID, true)
|
||||
.putExtra(EXTRA_ACTION, ACTION_STOP);
|
||||
return PendingIntent.getService(App.getApp(), ACTION_STOP, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}
|
||||
|
||||
public static PendingIntent getDeleteIntent() {
|
||||
Intent intent = new Intent(App.getApp(), ActionRecordSwitchHandleService.class)
|
||||
.putExtra(EXTRA_INTENT_VALID, true)
|
||||
.putExtra(EXTRA_ACTION, ACTION_DELETE);
|
||||
return PendingIntent.getService(App.getApp(), ACTION_DELETE, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}
|
||||
|
||||
|
||||
public static PendingIntent getRedoIntent() {
|
||||
Intent intent = new Intent(App.getApp(), ActionRecordSwitchHandleService.class)
|
||||
.putExtra(EXTRA_INTENT_VALID, true)
|
||||
.putExtra(EXTRA_ACTION, ACTION_REDO);
|
||||
return PendingIntent.getService(App.getApp(), ACTION_REDO, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
boolean intentValid = intent.getBooleanExtra(EXTRA_INTENT_VALID, false);
|
||||
if (intentValid) {
|
||||
performAction(intent.getIntExtra(EXTRA_ACTION, 0));
|
||||
}
|
||||
stopSelf();
|
||||
return super.onStartCommand(intent, flags, startId);
|
||||
}
|
||||
|
||||
private void performAction(int action) {
|
||||
switch (action) {
|
||||
case ACTION_STOP:
|
||||
stopRecord(this);
|
||||
collapseNotificationBar();
|
||||
break;
|
||||
case ACTION_START_OR_PAUSE:
|
||||
startOrPauseRecord(this);
|
||||
collapseNotificationBar();
|
||||
break;
|
||||
case ACTION_DELETE:
|
||||
ActionRecordSwitchNotification.cancelNotification();
|
||||
stopRecordIfNeeded();
|
||||
VolumeChangeListenService.stopServiceIfNeeded();
|
||||
break;
|
||||
case ACTION_REDO:
|
||||
redoRecord(this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void collapseNotificationBar() {
|
||||
sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
|
||||
}
|
||||
|
||||
private void stopRecordIfNeeded() {
|
||||
if (AccessibilityRecorderDelegate.getInstance().getState() != STOPPED) {
|
||||
stopRecord(this);
|
||||
}
|
||||
}
|
||||
|
||||
private static void startOrPauseRecord(Context context) {
|
||||
int state = AccessibilityRecorderDelegate.getInstance().getState();
|
||||
if (state == PAUSED) {
|
||||
resumeRecord(context);
|
||||
} else if (state == RECORDING) {
|
||||
pauseRecord(context);
|
||||
} else {
|
||||
//state == STOPPED
|
||||
startRecord(context);
|
||||
}
|
||||
}
|
||||
|
||||
public static void startRecord(Context context) {
|
||||
if (AccessibilityWatchDogService.getInstance() == null) {
|
||||
Toast.makeText(context, R.string.text_need_enable_accessibility_service, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
AccessibilityRecorderDelegate.getInstance().startRecord();
|
||||
ActionRecordSwitchView.getInstance().setState(RECORDING);
|
||||
Toast.makeText(context, R.string.text_start_record, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
private static void pauseRecord(Context context) {
|
||||
AccessibilityRecorderDelegate.getInstance().pauseRecord();
|
||||
ActionRecordSwitchView.getInstance().setState(PAUSED);
|
||||
}
|
||||
|
||||
private static void resumeRecord(Context context) {
|
||||
AccessibilityRecorderDelegate.getInstance().resumeRecord();
|
||||
ActionRecordSwitchView.getInstance().setState(RECORDING);
|
||||
}
|
||||
|
||||
public static void stopRecord(Context context) {
|
||||
if (AccessibilityRecorderDelegate.getInstance().getState() != STOPPED) {
|
||||
String script = AccessibilityRecorderDelegate.getInstance().stopRecord();
|
||||
ActionRecordSwitchView.getInstance().setState(STOPPED);
|
||||
MainActivity.onActionRecordStopped(context, script);
|
||||
} else {
|
||||
Toast.makeText(App.getApp(), R.string.text_not_recording, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
private static void redoRecord(Context context) {
|
||||
if (AccessibilityRecorderDelegate.getInstance().getState() != STOPPED) {
|
||||
AccessibilityRecorderDelegate.getInstance().stopRecord();
|
||||
ActionRecordSwitchView.getInstance().setState(STOPPED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package com.stardust.scriptdroid.external.notification.record;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.service.VolumeChangeListenService;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/2/14.
|
||||
*/
|
||||
|
||||
public class ActionRecordSwitchNotification {
|
||||
|
||||
private static final int NOTIFY_ID = 22236;
|
||||
private static NotificationCompat.Builder builder;
|
||||
|
||||
|
||||
public static void showOrUpdateNotification() {
|
||||
if (builder == null) {
|
||||
builder = new NotificationCompat.Builder(App.getApp())
|
||||
.setAutoCancel(false)
|
||||
.setSmallIcon(R.drawable.ic_robot_head)
|
||||
.setDeleteIntent(ActionRecordSwitchHandleService.getDeleteIntent())
|
||||
.setCustomContentView(ActionRecordSwitchView.getInstance());
|
||||
}
|
||||
showNotification(builder.build());
|
||||
VolumeChangeListenService.startServiceIfNeeded(App.getApp());
|
||||
}
|
||||
|
||||
private static void showNotification(Notification notification) {
|
||||
NotificationManager notificationManager = (NotificationManager) App.getApp().getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.notify(NOTIFY_ID, notification);
|
||||
}
|
||||
|
||||
public static void cancelNotification() {
|
||||
NotificationManager notificationManager = (NotificationManager) App.getApp().getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.cancel(NOTIFY_ID);
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,9 @@ import android.widget.Toast;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
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.tool.FileUtils;
|
||||
import com.stardust.scriptdroid.ui.BaseActivity;
|
||||
import com.stardust.scriptdroid.ui.main.MainActivity;
|
||||
import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder;
|
||||
@@ -31,8 +33,8 @@ public class ImportIntentActivity extends BaseActivity {
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Toast.makeText(this, R.string.edit_and_run_handle_intent_error, Toast.LENGTH_LONG).show();
|
||||
finish();
|
||||
}
|
||||
finish();
|
||||
}
|
||||
|
||||
private void handleIntent() {
|
||||
@@ -41,19 +43,22 @@ public class ImportIntentActivity extends BaseActivity {
|
||||
if (!TextUtils.isEmpty(path)) {
|
||||
new ThemeColorMaterialDialogBuilder(this)
|
||||
.title(R.string.text_please_input_name)
|
||||
.input(getString(R.string.text_name), new File(path).getName(), new MaterialDialog.InputCallback() {
|
||||
.input(getString(R.string.text_name), FileUtils.getNameWithoutExtension(path), new MaterialDialog.InputCallback() {
|
||||
@Override
|
||||
public void onInput(@NonNull MaterialDialog dialog, CharSequence input) {
|
||||
SharedPrefScriptFileList.getInstance().add(new ScriptFile(input.toString(), path));
|
||||
ScriptFileList.getImpl().add(new ScriptFile(input.toString(), path));
|
||||
startMainActivity();
|
||||
}
|
||||
})
|
||||
.show();
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
private void startMainActivity() {
|
||||
startActivity(new Intent(this, MainActivity.class)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
finish();
|
||||
}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
package com.stardust.scriptdroid.record;
|
||||
|
||||
import android.accessibilityservice.AccessibilityService;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
|
||||
import com.stardust.view.accessibility.AccessibilityDelegate;
|
||||
|
||||
import static com.stardust.scriptdroid.external.notification.record.ActionRecordSwitchView.PAUSED;
|
||||
import static com.stardust.scriptdroid.external.notification.record.ActionRecordSwitchView.RECORDING;
|
||||
import static com.stardust.scriptdroid.external.notification.record.ActionRecordSwitchView.STOPPED;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/2/14.
|
||||
*/
|
||||
|
||||
public class AccessibilityRecorderDelegate implements AccessibilityDelegate {
|
||||
|
||||
private static final int PRIORITY = 200;
|
||||
private static final long RECORD_TIME_OUT = 10 * 60 * 1000;
|
||||
|
||||
private static AccessibilityRecorderDelegate instance;
|
||||
private int mState = STOPPED;
|
||||
|
||||
public static AccessibilityRecorderDelegate getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new AccessibilityRecorderDelegate();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private ActionRecorder mRecorder = new ActionRecorder();
|
||||
private long mRecordStartMillis;
|
||||
|
||||
public void startRecord() {
|
||||
if (mState != STOPPED) {
|
||||
throw new IllegalStateException("Recording");
|
||||
}
|
||||
mState = RECORDING;
|
||||
mRecorder = new ActionRecorder();
|
||||
mRecordStartMillis = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
|
||||
public String stopRecord() {
|
||||
if (mState == STOPPED) {
|
||||
throw new IllegalStateException("Not recording");
|
||||
}
|
||||
mState = STOPPED;
|
||||
String script = mRecorder.getScript();
|
||||
mRecorder = null;
|
||||
return script;
|
||||
}
|
||||
|
||||
|
||||
public void pauseRecord() {
|
||||
if (mState != RECORDING) {
|
||||
throw new IllegalStateException("Not recording");
|
||||
}
|
||||
mState = PAUSED;
|
||||
}
|
||||
|
||||
public void resumeRecord() {
|
||||
if (mState != PAUSED) {
|
||||
throw new IllegalStateException("Not paused");
|
||||
}
|
||||
mRecorder.onResume();
|
||||
mState = RECORDING;
|
||||
}
|
||||
|
||||
public void stopRecordIfNeeded() {
|
||||
if (mRecorder != null) {
|
||||
mRecorder = null;
|
||||
}
|
||||
}
|
||||
|
||||
public int getState() {
|
||||
return mState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onAccessibilityEvent(AccessibilityService service, AccessibilityEvent event) {
|
||||
if (mState == RECORDING) {
|
||||
mRecorder.record(service, event);
|
||||
checkTimeOut();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void checkTimeOut() {
|
||||
if (System.currentTimeMillis() - mRecordStartMillis > RECORD_TIME_OUT) {
|
||||
stopRecord();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
154
app/src/main/java/com/stardust/scriptdroid/record/Recorder.java
Normal file
154
app/src/main/java/com/stardust/scriptdroid/record/Recorder.java
Normal file
@@ -0,0 +1,154 @@
|
||||
package com.stardust.scriptdroid.record;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/16.
|
||||
*/
|
||||
|
||||
public interface Recorder {
|
||||
|
||||
interface OnStateChangedListener {
|
||||
|
||||
void onStart();
|
||||
|
||||
void onStop();
|
||||
|
||||
void onPause();
|
||||
|
||||
void onResume();
|
||||
|
||||
}
|
||||
|
||||
OnStateChangedListener NO_OPERATION_LISTENER = new OnStateChangedListener() {
|
||||
@Override
|
||||
public void onStart() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
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 DefaultIMPL implements Recorder {
|
||||
|
||||
|
||||
private OnStateChangedListener mOnStateChangedListener = NO_OPERATION_LISTENER;
|
||||
|
||||
|
||||
private final boolean mSync;
|
||||
private int mState = STATE_NOT_START;
|
||||
|
||||
public DefaultIMPL(boolean syncOfState) {
|
||||
mSync = syncOfState;
|
||||
}
|
||||
|
||||
public DefaultIMPL() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
public void start() {
|
||||
checkState(STATE_NOT_START);
|
||||
setState(STATE_RECORDING);
|
||||
startImpl();
|
||||
mOnStateChangedListener.onStart();
|
||||
}
|
||||
|
||||
|
||||
private void checkState(int... expectedStates) {
|
||||
for (int expectedState : expectedStates) {
|
||||
if (mState == expectedState)
|
||||
return;
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
|
||||
protected abstract void startImpl();
|
||||
|
||||
public void stop() {
|
||||
checkState(STATE_RECORDING, STATE_PAUSED);
|
||||
setState(STATE_STOPPED);
|
||||
stopImpl();
|
||||
mOnStateChangedListener.onStop();
|
||||
}
|
||||
|
||||
protected abstract void stopImpl();
|
||||
|
||||
public void pause() {
|
||||
checkState(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() {
|
||||
checkState(STATE_PAUSED);
|
||||
setState(STATE_RECORDING);
|
||||
resumeImpl();
|
||||
mOnStateChangedListener.onResume();
|
||||
}
|
||||
|
||||
protected void resumeImpl() {
|
||||
|
||||
}
|
||||
|
||||
public void setOnStateChangedListener(OnStateChangedListener onStateChangedListener) {
|
||||
mOnStateChangedListener = onStateChangedListener == null ? NO_OPERATION_LISTENER : onStateChangedListener;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.stardust.scriptdroid.record;
|
||||
package com.stardust.scriptdroid.record.accessibility;
|
||||
|
||||
import android.accessibilityservice.AccessibilityService;
|
||||
import android.os.Build;
|
||||
@@ -11,6 +11,8 @@ import com.stardust.scriptdroid.layout_inspector.NodeInfo;
|
||||
import com.stardust.util.SparseArrayEntries;
|
||||
import com.stardust.view.accessibility.AccessibilityNodeInfoHelper;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@@ -18,7 +20,7 @@ import java.util.List;
|
||||
* Created by Stardust on 2017/2/14.
|
||||
*/
|
||||
|
||||
public class ActionRecorder {
|
||||
public class AccessibilityActionConverter {
|
||||
|
||||
private static final SparseArray<EventToScriptConverter> CONVERTER_MAP = new SparseArrayEntries<EventToScriptConverter>()
|
||||
.entry(AccessibilityEvent.TYPE_VIEW_CLICKED, new DoUtilSucceedConverter("click"))
|
||||
@@ -36,15 +38,22 @@ public class ActionRecorder {
|
||||
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) {
|
||||
if (mFirstAction && mShouldIgnoreFirstAction) {
|
||||
mFirstAction = false;
|
||||
return;
|
||||
}
|
||||
converter.onAccessibilityEvent(service, event, mScript);
|
||||
mScript.append("\n");
|
||||
EventBus.getDefault().post(new AccessibilityActionRecorder.AccessibilityActionRecordEvent(event));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
package com.stardust.scriptdroid.record.accessibility;
|
||||
|
||||
import android.accessibilityservice.AccessibilityService;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
|
||||
import com.stardust.scriptdroid.record.Recorder;
|
||||
import com.stardust.view.accessibility.AccessibilityDelegate;
|
||||
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/2/14.
|
||||
*/
|
||||
|
||||
public class AccessibilityActionRecorder extends Recorder.DefaultIMPL implements AccessibilityDelegate {
|
||||
|
||||
public static class AccessibilityActionRecordEvent {
|
||||
|
||||
private final AccessibilityEvent mAccessibilityEvent;
|
||||
|
||||
public AccessibilityActionRecordEvent(AccessibilityEvent event) {
|
||||
mAccessibilityEvent = event;
|
||||
}
|
||||
|
||||
public AccessibilityEvent getAccessibilityEvent() {
|
||||
return mAccessibilityEvent;
|
||||
}
|
||||
}
|
||||
|
||||
private static final long RECORD_TIME_OUT = 10 * 60 * 1000;
|
||||
|
||||
private static AccessibilityActionRecorder instance;
|
||||
private boolean mRecordMessageEnabled;
|
||||
|
||||
private boolean mShouldIgnoreFirstAction = false;
|
||||
|
||||
public static AccessibilityActionRecorder getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new AccessibilityActionRecorder();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
public void setRecordMessageEnabled(boolean recordMessageEnabled) {
|
||||
// TODO: 2017/3/16 添加录制提示
|
||||
mRecordMessageEnabled = recordMessageEnabled;
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,8 @@ import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.droid.runtime.DroidRuntime;
|
||||
import com.stardust.scriptdroid.ui.main.MainActivity;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -17,6 +19,21 @@ import java.util.regex.Pattern;
|
||||
public abstract class InputEventConverter {
|
||||
|
||||
|
||||
public static class RecordStateChangeEvent {
|
||||
|
||||
private boolean mIsRecording;
|
||||
|
||||
public RecordStateChangeEvent(boolean isRecording) {
|
||||
this.mIsRecording = isRecording;
|
||||
}
|
||||
|
||||
|
||||
public boolean isRecording() {
|
||||
return mIsRecording;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class Event {
|
||||
|
||||
static final Pattern PATTERN = Pattern.compile("^\\[([^\\]]*)\\]\\s+([^:]*):\\s+([^\\s]*)\\s+([^\\s]*)\\s+([^\\s]*)\\s*$");
|
||||
@@ -100,11 +117,11 @@ public abstract class InputEventConverter {
|
||||
}
|
||||
|
||||
public void notifyRecordStopped() {
|
||||
MainActivity.onRootRecordStopped(App.getApp());
|
||||
EventBus.getDefault().post(new RecordStateChangeEvent(false));
|
||||
}
|
||||
|
||||
public void notifyRecordStarted() {
|
||||
DroidRuntime.getRuntime().toast(App.getApp().getString(R.string.text_start_record));
|
||||
EventBus.getDefault().post(new RecordStateChangeEvent(true));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,10 +3,9 @@ package com.stardust.scriptdroid.record.inputevent;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.record.Recorder;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
import jackpal.androidterm.ShellTermSession;
|
||||
import jackpal.androidterm.emulatorview.TermSession;
|
||||
@@ -16,9 +15,8 @@ import jackpal.androidterm.util.TermSettings;
|
||||
* Created by Stardust on 2017/3/6.
|
||||
*/
|
||||
|
||||
public abstract class InputEventRecorder {
|
||||
public abstract class InputEventRecorder extends Recorder.DefaultIMPL {
|
||||
|
||||
private Thread mRecordThread;
|
||||
private TermSession mTermSession;
|
||||
private String mGetEventCommand;
|
||||
protected InputEventConverter mInputEventConverter;
|
||||
@@ -31,78 +29,61 @@ public abstract class InputEventRecorder {
|
||||
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 = new MyShellTermSession(settings, "su\r");
|
||||
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() {
|
||||
@Override
|
||||
protected void startImpl() {
|
||||
mInputEventConverter.start();
|
||||
}
|
||||
|
||||
public void pause() {
|
||||
@Override
|
||||
protected void pauseImpl() {
|
||||
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);
|
||||
}
|
||||
@Override
|
||||
protected void resumeImpl() {
|
||||
mInputEventConverter.start();
|
||||
}
|
||||
|
||||
protected abstract void parseAndRecordEvent(String eventStr);
|
||||
|
||||
public abstract String getCode();
|
||||
|
||||
public void stop() {
|
||||
mRecordThread.interrupt();
|
||||
@Override
|
||||
protected void stopImpl() {
|
||||
mTermSession.finish();
|
||||
mInputEventConverter.stop();
|
||||
}
|
||||
|
||||
|
||||
protected abstract void parseAndRecordEvent(String eventStr);
|
||||
|
||||
private class MyShellTermSession extends ShellTermSession {
|
||||
|
||||
private boolean mGettingEvents = false;
|
||||
|
||||
public MyShellTermSession(TermSettings settings, String initialCommand) throws IOException {
|
||||
super(settings, initialCommand);
|
||||
}
|
||||
|
||||
|
||||
@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 (!mGettingEvents && line.endsWith("data # ")) {
|
||||
mTermSession.write(mGetEventCommand + "\r");
|
||||
mGettingEvents = true;
|
||||
} else if (mGettingEvents) {
|
||||
parseAndRecordEvent(line);
|
||||
}
|
||||
}
|
||||
appendToEmulator(data, offset, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ import java.util.Map;
|
||||
|
||||
public class InputEventToJsConverter extends InputEventConverter {
|
||||
|
||||
|
||||
interface EventHandler {
|
||||
void handle(Event event);
|
||||
}
|
||||
@@ -22,10 +21,6 @@ public class InputEventToJsConverter extends InputEventConverter {
|
||||
|
||||
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;
|
||||
@@ -112,6 +107,7 @@ public class InputEventToJsConverter extends InputEventConverter {
|
||||
.entry("KEY_VOLUMEDOWN", "VolumeDown")
|
||||
.entry("KEY_VOLUMEUP", "VolumeUp")
|
||||
.entry("KEY_BACK", "Back")
|
||||
.entry("KEY_CAMERA", "Camera")
|
||||
.map();
|
||||
|
||||
@Override
|
||||
@@ -124,10 +120,10 @@ public class InputEventToJsConverter extends InputEventConverter {
|
||||
mSwipe = false;
|
||||
}
|
||||
} else if (event.value.equals("UP")) {
|
||||
if (!mStarted && event.code.equals("KEY_VOLUMEUP")) {
|
||||
if (!mStarted && event.code.equals(mStartTriggerKey)) {
|
||||
mStarted = true;
|
||||
notifyRecordStarted();
|
||||
} else if (mStarted && event.code.equals("KEY_VOLUMEDOWN")) {
|
||||
} else if (mStarted && event.code.equals(mStopTriggerKey)) {
|
||||
mStarted = false;
|
||||
notifyRecordStopped();
|
||||
} else {
|
||||
@@ -145,6 +141,7 @@ public class InputEventToJsConverter extends InputEventConverter {
|
||||
}
|
||||
|
||||
private EventHandler mEventHandler = new TypeRouter();
|
||||
private String mStartTriggerKey, mStopTriggerKey;
|
||||
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;
|
||||
@@ -166,5 +163,13 @@ public class InputEventToJsConverter extends InputEventConverter {
|
||||
return mCode.toString();
|
||||
}
|
||||
|
||||
public void setStartTriggerKey(String startTriggerKey) {
|
||||
mStartTriggerKey = startTriggerKey;
|
||||
}
|
||||
|
||||
public void setStopTriggerKey(String stopTriggerKey) {
|
||||
mStopTriggerKey = stopTriggerKey;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -6,9 +6,11 @@ package com.stardust.scriptdroid.record.inputevent;
|
||||
|
||||
public class InputEventToJsRecorder extends InputEventRecorder {
|
||||
|
||||
private InputEventToJsConverter mInputEventToJsConverter;
|
||||
|
||||
public InputEventToJsRecorder() {
|
||||
super("getevent -t -l", new InputEventToJsConverter());
|
||||
mInputEventToJsConverter = (InputEventToJsConverter) mInputEventConverter;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -20,4 +22,12 @@ public class InputEventToJsRecorder extends InputEventRecorder {
|
||||
public String getCode() {
|
||||
return mInputEventConverter.getCode();
|
||||
}
|
||||
|
||||
public void setStartTriggerKey(String startTriggerKey) {
|
||||
mInputEventToJsConverter.setStartTriggerKey(startTriggerKey);
|
||||
}
|
||||
|
||||
public void setStopTriggerKey(String stopTriggerKey) {
|
||||
mInputEventToJsConverter.setStopTriggerKey(stopTriggerKey);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.stardust.scriptdroid.record.inputevent;
|
||||
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.Pref;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.record.Recorder;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/16.
|
||||
*/
|
||||
|
||||
public class TouchRecorder extends InputEventToJsRecorder {
|
||||
|
||||
|
||||
public TouchRecorder() {
|
||||
listen();
|
||||
setUpTriggers();
|
||||
}
|
||||
|
||||
private void setUpTriggers() {
|
||||
setStartTriggerKey(Pref.def().getString(App.getResString(R.string.key_start_record_trigger), null));
|
||||
setStopTriggerKey(Pref.def().getString(App.getResString(R.string.key_stop_record_trigger), null));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -23,15 +23,6 @@ import java.util.Map;
|
||||
*/
|
||||
public class SampleFileManager {
|
||||
|
||||
private static final Map<String, Integer> SAMPLES = new MapEntries<>(new LinkedHashMap<String, Integer>())
|
||||
.entry("sample/自动操作/sample_open_running_services.js", R.string.text_sample_open_running_services)
|
||||
.entry("sample/自动操作/sample_qq_hongbao.js", R.string.text_sample_qq_hongbao)
|
||||
.entry("sample/自动操作/sample_simple_calculator.js", R.string.text_sample_simple_calculator)
|
||||
.entry("sample/自动操作/sample_force_qq_chat.js", R.string.text_sample_for_qq_chat)
|
||||
.entry("sample/自动操作/sample_wechat_scan.js", R.string.text_sample_wechat_scan)
|
||||
.entry("sample/自动操作/sample_alipay_scan.js", R.string.text_sample_alipay_scan)
|
||||
.map();
|
||||
|
||||
private static SampleFileManager instance = new SampleFileManager();
|
||||
|
||||
public static SampleFileManager getInstance() {
|
||||
@@ -42,33 +33,6 @@ public class SampleFileManager {
|
||||
return App.getApp();
|
||||
}
|
||||
|
||||
public void copySampleScriptFileIfNeeded() {
|
||||
if (!Pref.def().getBoolean(Pref.SAMPLE_SCRIPTS_COPIED, false)) {
|
||||
copySampleScriptFile();
|
||||
}
|
||||
}
|
||||
|
||||
public int copySampleScriptFile() {
|
||||
ScriptFileList list = SharedPrefScriptFileList.getInstance();
|
||||
int failCount = 0;
|
||||
for (Map.Entry<String, Integer> entry : SAMPLES.entrySet()) {
|
||||
String assetFile = entry.getKey();
|
||||
String name = getContext().getString(entry.getValue());
|
||||
String path = ScriptFile.DEFAULT_FOLDER + name + ".js";
|
||||
if (!list.containsPath(path)) {
|
||||
if (FileUtils.copyAsset(assetFile, path)) {
|
||||
list.add(new ScriptFile(name, path));
|
||||
} else {
|
||||
failCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (failCount < SAMPLES.size()) {
|
||||
Pref.def().edit().putBoolean(Pref.SAMPLE_SCRIPTS_COPIED, true).apply();
|
||||
}
|
||||
return failCount;
|
||||
}
|
||||
|
||||
public List<SampleGroup> getSamplesFromAssets(AssetManager assets, String path) {
|
||||
List<SampleGroup> sampleGroups = new ArrayList<>();
|
||||
try {
|
||||
|
||||
@@ -81,7 +81,7 @@ public class AccessibilityWatchDogService extends AccessibilityService {
|
||||
Log.v(TAG, "onAccessibilityEvent: " + event);
|
||||
synchronized (mDelegates) {
|
||||
for (Map.Entry<Integer, AccessibilityDelegate> entry : mDelegates.entrySet()) {
|
||||
Log.v(TAG, "delegate: " + entry.getValue().getClass().getName());
|
||||
//Log.v(TAG, "delegate: " + entry.getValue().getClass().getName());
|
||||
if (entry.getValue().onAccessibilityEvent(this, event))
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -8,34 +8,35 @@ import android.content.IntentFilter;
|
||||
import android.os.IBinder;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.stardust.scriptdroid.external.notification.record.ActionRecordSwitchHandleService;
|
||||
import com.stardust.scriptdroid.record.AccessibilityRecorderDelegate;
|
||||
import com.stardust.scriptdroid.external.notification.record.AccessibilityActionRecordNotification;
|
||||
import com.stardust.scriptdroid.record.Recorder;
|
||||
import com.stardust.scriptdroid.record.accessibility.AccessibilityActionRecorder;
|
||||
import com.stardust.scriptdroid.Pref;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import static com.stardust.scriptdroid.external.notification.record.ActionRecordSwitchView.STOPPED;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/2/16.
|
||||
*/
|
||||
|
||||
public class VolumeChangeListenService extends Service {
|
||||
public class VolumeChangeObverseService extends Service {
|
||||
|
||||
private static final String ACTION_VOLUME_CHANGE = "android.media.VOLUME_CHANGED_ACTION";
|
||||
|
||||
private VolumeChangeReceiver mVolumeChangeReceiver;
|
||||
private static WeakReference<VolumeChangeListenService> instance;
|
||||
private static VolumeChangeObverseService instance;
|
||||
|
||||
public static void stopServiceIfNeeded() {
|
||||
if (instance != null && instance.get() != null) {
|
||||
instance.get().stopSelf();
|
||||
if (instance != null) {
|
||||
instance.stopSelf();
|
||||
instance = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void startServiceIfNeeded(Context context) {
|
||||
if (Pref.isRecordVolumeControlEnable() && (instance == null || instance.get() == null)) {
|
||||
context.startService(new Intent(context, VolumeChangeListenService.class));
|
||||
if (Pref.isRecordVolumeControlEnable() && instance == null) {
|
||||
context.startService(new Intent(context, VolumeChangeObverseService.class));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,10 +44,10 @@ public class VolumeChangeListenService extends Service {
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
if (instance != null && instance.get() != null) {
|
||||
instance.get().stopSelf();
|
||||
if (instance != null) {
|
||||
instance.stopSelf();
|
||||
}
|
||||
instance = new WeakReference<>(this);
|
||||
instance = this;
|
||||
mVolumeChangeReceiver = new VolumeChangeReceiver();
|
||||
registerReceiver(mVolumeChangeReceiver, new IntentFilter(ACTION_VOLUME_CHANGE));
|
||||
}
|
||||
@@ -60,6 +61,7 @@ public class VolumeChangeListenService extends Service {
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
instance = null;
|
||||
unregisterReceiver(mVolumeChangeReceiver);
|
||||
}
|
||||
|
||||
@@ -74,10 +76,10 @@ public class VolumeChangeListenService extends Service {
|
||||
return;
|
||||
}
|
||||
mLastChangeMillis = System.currentTimeMillis();
|
||||
if (AccessibilityRecorderDelegate.getInstance().getState() == STOPPED) {
|
||||
ActionRecordSwitchHandleService.startRecord(VolumeChangeListenService.this);
|
||||
if (AccessibilityActionRecorder.getInstance().getState() == Recorder.STATE_STOPPED) {
|
||||
AccessibilityActionRecordNotification.startRecord(VolumeChangeObverseService.this);
|
||||
} else {
|
||||
ActionRecordSwitchHandleService.stopRecord(VolumeChangeListenService.this);
|
||||
AccessibilityActionRecordNotification.stopRecord(VolumeChangeObverseService.this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ public interface BackPressedHandler {
|
||||
mActivity = activity;
|
||||
}
|
||||
|
||||
public DoublePressExit setDoublePressInterval(long doublePressInterval) {
|
||||
public DoublePressExit doublePressInterval(long doublePressInterval) {
|
||||
mDoublePressInterval = doublePressInterval;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -16,15 +16,15 @@ import com.stardust.scriptdroid.R;
|
||||
public class ImageSelector implements OnActivityResultDelegate {
|
||||
|
||||
public interface ImageSelectorCallback {
|
||||
void onImageSelected(String path);
|
||||
void onImageSelected(ImageSelector selector, String path);
|
||||
}
|
||||
|
||||
private static final int REQUEST_CODE = "LOVE EATING".hashCode() >> 16;
|
||||
private Activity mActivity;
|
||||
private ImageSelectorCallback mCallback;
|
||||
|
||||
public ImageSelector(Activity activity, Manager manager, ImageSelectorCallback callback) {
|
||||
manager.addDelegate(REQUEST_CODE, this);
|
||||
public ImageSelector(Activity activity, Intermediary intermediary, ImageSelectorCallback callback) {
|
||||
intermediary.addDelegate(REQUEST_CODE, this);
|
||||
mActivity = activity;
|
||||
mCallback = callback;
|
||||
}
|
||||
@@ -48,7 +48,7 @@ public class ImageSelector implements OnActivityResultDelegate {
|
||||
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
|
||||
String filePath = cursor.getString(columnIndex);
|
||||
cursor.close();
|
||||
mCallback.onImageSelected(filePath);
|
||||
mCallback.onImageSelected(this, filePath);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -38,49 +38,6 @@ 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);
|
||||
}
|
||||
@@ -97,7 +54,6 @@ public class Shell {
|
||||
}
|
||||
|
||||
public Shell execute(String command) {
|
||||
|
||||
try {
|
||||
mCommandOutputStream.writeBytes(command);
|
||||
if (!command.endsWith(COMMAND_LINE_END)) {
|
||||
|
||||
@@ -38,6 +38,9 @@ import com.stardust.theme.ThemeColorManager;
|
||||
import com.stardust.view.ViewBinder;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Timer;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/29.
|
||||
@@ -98,8 +101,10 @@ public class EditActivity extends Editor920Activity {
|
||||
if (intent.getAction().equals(ACTION_ON_RUN_FINISHED)) {
|
||||
setMenuStatus(R.id.run, MenuDef.STATUS_NORMAL);
|
||||
String msg = intent.getStringExtra(EXTRA_EXCEPTION_MESSAGE);
|
||||
if (msg != null)
|
||||
if (msg != null) {
|
||||
Snackbar.make(mView, getString(R.string.text_error) + ": " + msg, Snackbar.LENGTH_LONG).show();
|
||||
Timber.e(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -101,11 +101,16 @@ public class CodeCompletion implements TextWatcher {
|
||||
|
||||
private static final String[] KEYWORDS = {"arguments", "break", "case", "catch", "class", "continue", "default", "do", "else", "eval", "export", "false", "for", "function", "if", "import", "in", "int", "new", "null", "package", "return", "switch", "this", "throw", "throws", "true", "try", "typeof", "var", "volatile", "while", "with", "Array", "Date", "hasOwnProperty", "Infinity", "isFinite", "isNaN", "isPrototypeOf", "length", "Math", "NaN", "name", "Number", "Object", "prototype", "String", "toString", "undefined", "valueOf"};
|
||||
private static final int KEY_WORD_LENGTH_MAX = 15;
|
||||
private static final String[] FUNCTIONS = {"toast", "launchPackage", "launch", "launchApp", "click", "longClick", "scrollUp", "scrollDown", "select", "focus", "paste", "input", "sleep", "isStopped", "notStopped", "log", "err", "openConsole", "clearConsole", "shell", "getTexts", "getPackageName", "getActivityName", "setClip", "addAccessibilityDelegate"};
|
||||
|
||||
public void setFunctions(String[] functions) {
|
||||
mFunctions = functions;
|
||||
}
|
||||
|
||||
private String[] mFunctions = {"toast", "launchPackage", "launch", "launchApp", "click", "longClick", "scrollUp", "scrollDown", "select", "focus", "paste", "input", "sleep", "isStopped", "notStopped", "log", "err", "openConsole", "clearConsole", "shell", "getTexts", "getPackageName", "getActivityName", "setClip", "addAccessibilityDelegate"};
|
||||
|
||||
private boolean searchCodeCompletion(String str) {
|
||||
Collection<CodeCompletionItem> c = searchWordCompletion(str);
|
||||
c.addAll(searchCodeCompletion(str, FUNCTIONS));
|
||||
c.addAll(searchCodeCompletion(str, mFunctions));
|
||||
c.addAll(searchKeyWordCompletion(str));
|
||||
if (c.size() > 0) {
|
||||
mOnCodeCompletionChangeListener.OnCodeCompletionChange(c, DEFAULT_CODE_COMPLETION_LIST);
|
||||
|
||||
@@ -14,6 +14,7 @@ import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.droid.script.JavaScriptEngine;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@@ -73,6 +74,7 @@ public class InputMethodEnhanceBar extends RecyclerView implements CodeCompletio
|
||||
private void init() {
|
||||
setAdapter(new CodeCompletionAdapter());
|
||||
setLayoutManager(new LinearLayoutManager(getContext(), HORIZONTAL, false));
|
||||
mCodeCompletion.setFunctions(JavaScriptEngine.getDefault().getGlobalFunctions());
|
||||
}
|
||||
|
||||
public void setEditTextBridge(EditTextBridge editTextBridge) {
|
||||
|
||||
@@ -11,6 +11,8 @@ import com.jecelyin.editor.v2.ui.IActivity;
|
||||
import com.jecelyin.editor.v2.ui.TabManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/30.
|
||||
@@ -21,6 +23,18 @@ public class Editor920Activity extends IActivity {
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
Pref.getInstance(this).setReadOnly(false);
|
||||
setPref(Pref.KEY_PREF_KEEP_BACKUP_FILE, false);
|
||||
|
||||
}
|
||||
|
||||
private void setPref(String key, Object value) {
|
||||
try {
|
||||
Field field = Pref.class.getDeclaredField("map");
|
||||
field.setAccessible(true);
|
||||
((Map) field.get(Pref.getInstance(this))).put(key, value);
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -66,11 +66,19 @@ public class IssueReportActivity extends IssueReporterActivity {
|
||||
final String errorDetail = getIntent().getStringExtra("error");
|
||||
if (errorDetail != null) {
|
||||
((EditText) findViewById(R.id.air_inputDescription)).setText(errorDetail);
|
||||
((EditText) findViewById(R.id.air_inputTitle)).setText(R.string.text_crash_en);
|
||||
String title = getFirstLine(errorDetail);
|
||||
((EditText) findViewById(R.id.air_inputTitle)).setText(title);
|
||||
mCrash = true;
|
||||
}
|
||||
}
|
||||
|
||||
private String getFirstLine(String str) {
|
||||
int i = str.indexOf('\n');
|
||||
if(i < 0)
|
||||
return str;
|
||||
return str.substring(0, i);
|
||||
}
|
||||
|
||||
private boolean validateInput() {
|
||||
if (mValidateInput == null) {
|
||||
try {
|
||||
|
||||
@@ -9,12 +9,17 @@ import com.stardust.widget.CommonMarkdownView;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.tool.FileUtils;
|
||||
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/2/1.
|
||||
*/
|
||||
|
||||
|
||||
public class DocumentationActivity extends BaseActivity {
|
||||
|
||||
private CommonMarkdownView mCommonMarkdownView;
|
||||
|
||||
@@ -33,7 +33,7 @@ import com.stardust.scriptdroid.Pref;
|
||||
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.external.notification.record.AccessibilityActionRecordNotification;
|
||||
import com.stardust.scriptdroid.record.inputevent.InputEventRecorder;
|
||||
import com.stardust.scriptdroid.record.inputevent.InputEventToJsRecorder;
|
||||
import com.stardust.scriptdroid.service.AccessibilityWatchDogService;
|
||||
@@ -68,12 +68,14 @@ public class MainActivity extends BaseActivity implements FileChooserDialog.File
|
||||
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 ScriptFileList mScriptFileList;
|
||||
private DrawerLayout mDrawerLayout;
|
||||
@ViewBinding.Id(R.id.bottom_menu)
|
||||
private SlidingUpPanel mAddBottomMenuPanel;
|
||||
|
||||
private MyScriptListFragment mMyScriptListFragment;
|
||||
private SampleScriptListFragment mSampleScriptListFragment;
|
||||
private DrawerLayout mDrawerLayout;
|
||||
private OnActivityResultDelegate.Manager mManager = new OnActivityResultDelegate.Manager();
|
||||
private OnActivityResultDelegate.Intermediary mActivityResultIntermediary = new OnActivityResultDelegate.Intermediary();
|
||||
private BackPressedHandler.Observer mBackPressObserver = new BackPressedHandler.Observer();
|
||||
|
||||
@Override
|
||||
@@ -113,7 +115,7 @@ public class MainActivity extends BaseActivity implements FileChooserDialog.File
|
||||
private void addScriptFile(final String path) {
|
||||
new ThemeColorMaterialDialogBuilder(this).title(R.string.text_name)
|
||||
.inputType(InputType.TYPE_CLASS_TEXT)
|
||||
.input(getString(R.string.text_please_input_name), new File(path).getName(), new MaterialDialog.InputCallback() {
|
||||
.input(getString(R.string.text_please_input_name), FileUtils.getNameWithoutExtension(path), new MaterialDialog.InputCallback() {
|
||||
@Override
|
||||
public void onInput(@NonNull MaterialDialog dialog, CharSequence input) {
|
||||
MainActivity.this.addScriptFile(input.toString(), path);
|
||||
@@ -130,7 +132,6 @@ public class MainActivity extends BaseActivity implements FileChooserDialog.File
|
||||
mDrawerLayout = (DrawerLayout) View.inflate(this, R.layout.activity_main, null);
|
||||
setContentView(mDrawerLayout);
|
||||
setUpFragment();
|
||||
mAddFilePanel = $(R.id.bottom_menu);
|
||||
setUpToolbar();
|
||||
setUpTabLayout();
|
||||
setUpDrawerHeader();
|
||||
@@ -141,7 +142,7 @@ public class MainActivity extends BaseActivity implements FileChooserDialog.File
|
||||
private void setUpFragment() {
|
||||
SlideMenuFragment.setFragment(this, R.id.fragment_slide_menu);
|
||||
mMyScriptListFragment = new MyScriptListFragment();
|
||||
mScriptFileList = SharedPrefScriptFileList.getInstance();
|
||||
mScriptFileList = ScriptFileList.getImpl();
|
||||
mSampleScriptListFragment = new SampleScriptListFragment();
|
||||
}
|
||||
|
||||
@@ -188,7 +189,7 @@ public class MainActivity extends BaseActivity implements FileChooserDialog.File
|
||||
|
||||
@ViewBinding.Click(R.id.add)
|
||||
private void showAddFilePanel() {
|
||||
mAddFilePanel.show();
|
||||
mAddBottomMenuPanel.show();
|
||||
}
|
||||
|
||||
@ViewBinding.Click(R.id.create_new_file)
|
||||
@@ -238,7 +239,7 @@ public class MainActivity extends BaseActivity implements FileChooserDialog.File
|
||||
Snackbar.make(mDrawerLayout, R.string.text_need_enable_accessibility_service, Snackbar.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
ActionRecordSwitchNotification.showOrUpdateNotification();
|
||||
AccessibilityActionRecordNotification.showOrUpdateNotification();
|
||||
Snackbar.make(mDrawerLayout, R.string.hint_start_record, Snackbar.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@@ -265,11 +266,12 @@ public class MainActivity extends BaseActivity implements FileChooserDialog.File
|
||||
|
||||
@ViewBinding.Click(R.id.drawer_header_img)
|
||||
public void selectHeaderImage() {
|
||||
new ImageSelector(this, mManager, new ImageSelector.ImageSelectorCallback() {
|
||||
new ImageSelector(this, mActivityResultIntermediary, new ImageSelector.ImageSelectorCallback() {
|
||||
@Override
|
||||
public void onImageSelected(String path) {
|
||||
public void onImageSelected(ImageSelector selector, String path) {
|
||||
setDrawerHeaderImage(path);
|
||||
Pref.def().edit().putString(Pref.KEY_DRAWER_HEADER_IMAGE_PATH, path).apply();
|
||||
mActivityResultIntermediary.removeDelegate(selector);
|
||||
}
|
||||
}).select();
|
||||
}
|
||||
@@ -334,8 +336,8 @@ public class MainActivity extends BaseActivity implements FileChooserDialog.File
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (mAddFilePanel.isShowing()) {
|
||||
mAddFilePanel.dismiss();
|
||||
if (mAddBottomMenuPanel.isShowing()) {
|
||||
mAddBottomMenuPanel.dismiss();
|
||||
} else if (mDrawerLayout.isDrawerOpen(Gravity.START)) {
|
||||
mDrawerLayout.closeDrawer(Gravity.START);
|
||||
} else {
|
||||
@@ -350,7 +352,7 @@ public class MainActivity extends BaseActivity implements FileChooserDialog.File
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
mManager.onActivityResult(requestCode, resultCode, data);
|
||||
mActivityResultIntermediary.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
public static void onActionRecordStopped(Context context, String script) {
|
||||
@@ -370,11 +372,12 @@ public class MainActivity extends BaseActivity implements FileChooserDialog.File
|
||||
}
|
||||
|
||||
public void OnAppBarClick(View view) {
|
||||
new ImageSelector(this, mManager, new ImageSelector.ImageSelectorCallback() {
|
||||
new ImageSelector(this, mActivityResultIntermediary, new ImageSelector.ImageSelectorCallback() {
|
||||
@Override
|
||||
public void onImageSelected(String path) {
|
||||
public void onImageSelected(ImageSelector selector, String path) {
|
||||
Pref.def().edit().putString(Pref.KEY_APP_BAR_IMAGE_PATH, path).apply();
|
||||
setAppBarImage(path);
|
||||
mActivityResultIntermediary.removeDelegate(selector);
|
||||
}
|
||||
}).select();
|
||||
}
|
||||
|
||||
@@ -39,8 +39,7 @@ public class MyScriptListFragment extends Fragment implements BackPressedHandler
|
||||
@Nullable
|
||||
@Override
|
||||
public View createView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.fragment_my_script_list, container, false);
|
||||
return view;
|
||||
return inflater.inflate(R.layout.fragment_my_script_list, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -55,7 +54,7 @@ public class MyScriptListFragment extends Fragment implements BackPressedHandler
|
||||
|
||||
private void setUpScriptList() {
|
||||
mScriptListRecyclerView = $(R.id.script_list);
|
||||
mScriptFileList = SharedPrefScriptFileList.getInstance();
|
||||
mScriptFileList = ScriptFileList.getImpl();
|
||||
mNoScriptHint = $(R.id.hint_no_script);
|
||||
mScriptListRecyclerView.getAdapter().registerAdapterDataObserver(new SimpleAdapterDataObserver() {
|
||||
@Override
|
||||
@@ -91,6 +90,18 @@ public class MyScriptListFragment extends Fragment implements BackPressedHandler
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
EventBus.getDefault().register(mScriptListRecyclerView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
EventBus.getDefault().unregister(mScriptListRecyclerView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
@@ -139,18 +139,6 @@ public class ScriptListRecyclerView extends ThemeColorRecyclerView {
|
||||
Snackbar.make(this, event.messageResId, Snackbar.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
EventBus.getDefault().register(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
EventBus.getDefault().unregister(this);
|
||||
}
|
||||
|
||||
private class Adapter extends RecyclerView.Adapter<ViewHolder> {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -2,13 +2,27 @@ package com.stardust.scriptdroid.ui.main.sample_list;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.stardust.app.Fragment;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.droid.script.file.ScriptFile;
|
||||
import com.stardust.scriptdroid.droid.script.file.ScriptFileList;
|
||||
import com.stardust.scriptdroid.sample.Sample;
|
||||
import com.stardust.scriptdroid.sample.SampleFileManager;
|
||||
import com.stardust.scriptdroid.tool.FileUtils;
|
||||
import com.stardust.scriptdroid.ui.edit.EditActivity;
|
||||
import com.stardust.scriptdroid.ui.main.my_script_list.MyScriptListFragment;
|
||||
import com.stardust.util.MessageEvent;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/13.
|
||||
@@ -28,7 +42,47 @@ public class SampleScriptListFragment extends Fragment {
|
||||
protected void afterCreateView() {
|
||||
mSampleScriptListRecyclerView = $(R.id.script_list);
|
||||
mSampleScriptListRecyclerView.setSamples(SampleFileManager.getInstance().getSamplesFromAssets(getContext().getAssets(), "sample"));
|
||||
mSampleScriptListRecyclerView.setOnItemLongClickListener(new SampleScriptListRecyclerView.OnItemLongClickListener() {
|
||||
@Override
|
||||
public void onItemLongClick(Sample sample) {
|
||||
showMenuDialog(sample);
|
||||
}
|
||||
});
|
||||
mSampleScriptListRecyclerView.setOnItemClickListener(new SampleScriptListRecyclerView.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(Sample sample) {
|
||||
viewSample(sample);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void showMenuDialog(final Sample sample) {
|
||||
new MaterialDialog.Builder(getActivity())
|
||||
.title(sample.name)
|
||||
.items(getString(R.string.text_copy_to_my_scripts))
|
||||
.itemsCallback(new MaterialDialog.ListCallback() {
|
||||
@Override
|
||||
public void onSelection(MaterialDialog dialog, View itemView, int position, CharSequence text) {
|
||||
copySampleToMyScripts(sample);
|
||||
}
|
||||
|
||||
})
|
||||
.show();
|
||||
}
|
||||
|
||||
private void copySampleToMyScripts(Sample sample) {
|
||||
String path = ScriptFile.DEFAULT_FOLDER + sample.name + ".js";
|
||||
if (!ScriptFileList.getImpl().containsPath(path) && FileUtils.copyAsset(sample.path, path)) {
|
||||
ScriptFileList.getImpl().add(new ScriptFile(sample.name, path));
|
||||
EventBus.getDefault().post(new MessageEvent(MyScriptListFragment.MESSAGE_SCRIPT_FILE_ADDED));
|
||||
Snackbar.make(mSampleScriptListRecyclerView, R.string.text_import_succeed, Snackbar.LENGTH_SHORT).show();
|
||||
} else {
|
||||
Snackbar.make(mSampleScriptListRecyclerView, R.string.text_file_exists, Snackbar.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
private void viewSample(Sample sample) {
|
||||
EditActivity.editAssetFile(getContext(), sample.name, sample.path);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -29,14 +29,36 @@ import java.util.List;
|
||||
|
||||
public class SampleScriptListRecyclerView extends RecyclerView {
|
||||
|
||||
public interface OnItemLongClickListener {
|
||||
void onItemLongClick(Sample sample);
|
||||
}
|
||||
|
||||
private OnClickListener mOnItemClickListener = new OnClickListener() {
|
||||
public interface OnItemClickListener {
|
||||
void onItemClick(Sample sample);
|
||||
}
|
||||
|
||||
private OnClickListener mOnItemClickListenerProxy = new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
SampleViewHolder viewHolder = (SampleViewHolder) getChildViewHolder(v);
|
||||
viewSample(viewHolder.getChild());
|
||||
if (mOnItemClickListener != null) {
|
||||
SampleViewHolder viewHolder = (SampleViewHolder) getChildViewHolder(v);
|
||||
mOnItemClickListener.onItemClick(viewHolder.getChild());
|
||||
}
|
||||
}
|
||||
};
|
||||
private OnLongClickListener mOnLongClickListenerProxy = new OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
if (mOnItemLongClickListener != null) {
|
||||
SampleViewHolder viewHolder = (SampleViewHolder) getChildViewHolder(v);
|
||||
mOnItemLongClickListener.onItemLongClick(viewHolder.getChild());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
private OnItemLongClickListener mOnItemLongClickListener;
|
||||
private OnItemClickListener mOnItemClickListener;
|
||||
|
||||
|
||||
private Adapter mAdapter;
|
||||
@@ -57,6 +79,14 @@ public class SampleScriptListRecyclerView extends RecyclerView {
|
||||
init();
|
||||
}
|
||||
|
||||
public void setOnItemLongClickListener(OnItemLongClickListener onItemLongClickListener) {
|
||||
mOnItemLongClickListener = onItemLongClickListener;
|
||||
}
|
||||
|
||||
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
|
||||
mOnItemClickListener = onItemClickListener;
|
||||
}
|
||||
|
||||
public void setSamples(List<com.stardust.scriptdroid.sample.SampleGroup> samples) {
|
||||
mSampleGroups.clear();
|
||||
for (com.stardust.scriptdroid.sample.SampleGroup sampleGroup : samples) {
|
||||
@@ -71,12 +101,6 @@ public class SampleScriptListRecyclerView extends RecyclerView {
|
||||
addItemDecoration(new DividerItemDecoration(getContext(), VERTICAL));
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void viewSample(Sample sample) {
|
||||
EditActivity.editAssetFile(getContext(), sample.name, sample.path);
|
||||
}
|
||||
|
||||
private class SampleGroup implements Parent<Sample> {
|
||||
|
||||
private com.stardust.scriptdroid.sample.SampleGroup mSampleGroup;
|
||||
@@ -108,7 +132,8 @@ public class SampleScriptListRecyclerView extends RecyclerView {
|
||||
super(itemView);
|
||||
name = (TextView) itemView.findViewById(R.id.name);
|
||||
((LevelBeamView) itemView.findViewById(R.id.level)).setLevel(2);
|
||||
itemView.setOnClickListener(mOnItemClickListener);
|
||||
itemView.setOnClickListener(mOnItemClickListenerProxy);
|
||||
itemView.setOnLongClickListener(mOnLongClickListenerProxy);
|
||||
}
|
||||
|
||||
void bind(Sample sample) {
|
||||
|
||||
@@ -3,11 +3,14 @@ package com.stardust.view;
|
||||
import android.view.View;
|
||||
import android.widget.CompoundButton;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/30.
|
||||
*
|
||||
* 哈?你说我为什么不用AA框架?之前还不知道嘛所以现在用了。
|
||||
*/
|
||||
|
||||
public class ViewBinder {
|
||||
@@ -21,6 +24,7 @@ public class ViewBinder {
|
||||
throw new RuntimeException("You must implement findViewById to use view binding", e);
|
||||
}
|
||||
Method[] methods = o.getClass().getDeclaredMethods();
|
||||
bindId(o, findViewById);
|
||||
for (Method method : methods) {
|
||||
method.setAccessible(true);
|
||||
bindClick(o, method, findViewById);
|
||||
@@ -28,6 +32,20 @@ public class ViewBinder {
|
||||
}
|
||||
}
|
||||
|
||||
private static void bindId(Object o, Method findViewById) {
|
||||
for (Field field : o.getClass().getDeclaredFields()) {
|
||||
field.setAccessible(true);
|
||||
ViewBinding.Id id = field.getAnnotation(ViewBinding.Id.class);
|
||||
if (id == null || id.value() == 0)
|
||||
continue;
|
||||
try {
|
||||
field.set(o, findViewById.invoke(o, id.value()));
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void bindCheck(final Object o, final Method method, Method findViewById) {
|
||||
ViewBinding.Check annotation = method.getAnnotation(ViewBinding.Check.class);
|
||||
if (annotation == null || annotation.value() == 0)
|
||||
|
||||
@@ -32,4 +32,10 @@ public @interface ViewBinding {
|
||||
@interface Check {
|
||||
int value();
|
||||
}
|
||||
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface Id {
|
||||
int value();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user