diff --git a/app-release-1.17.0213.apk b/app-release-1.17.0215.apk similarity index 66% rename from app-release-1.17.0213.apk rename to app-release-1.17.0215.apk index 7859212d..2b1b9040 100644 Binary files a/app-release-1.17.0213.apk and b/app-release-1.17.0215.apk differ diff --git a/app/build.gradle b/app/build.gradle index 6682df18..e8379456 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -7,8 +7,8 @@ android { applicationId "com.stardust.scriptdroid" minSdkVersion 19 targetSdkVersion 23 - versionCode 22 - versionName "1.17.0213" + versionCode 25 + versionName "1.17.0215" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { @@ -25,6 +25,10 @@ android { dataBinding { enabled = true } + lintOptions { + disable 'MissingTranslation' + disable 'ExtraTranslation' + } android.applicationVariants.all { variant -> variant.outputs.each { output -> def file = output.outputFile diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index db448335..8303add1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -17,8 +17,9 @@ android:theme="@style/AppTheme" tools:replace="android:label"> @@ -28,7 +29,7 @@ @@ -38,7 +39,7 @@ @@ -73,21 +74,22 @@ android:resource="@xml/provider_paths"/> - - - - - - + + + + + + - + + @@ -126,7 +128,7 @@ diff --git a/app/src/main/assets/javasccript_engine_init.js b/app/src/main/assets/javasccript_engine_init.js index af750f8a..f9a0efc4 100644 --- a/app/src/main/assets/javasccript_engine_init.js +++ b/app/src/main/assets/javasccript_engine_init.js @@ -120,4 +120,8 @@ var clearConsole = function(){ var shell = function(cmd, root){ root = root ? 1 : 0; droid.shell(cmd, root); +} + +var getTexts = function(){ + return droid.getTexts(); } \ No newline at end of file diff --git a/app/src/main/java/com/stardust/scriptdroid/App.java b/app/src/main/java/com/stardust/scriptdroid/App.java index c2d80eb7..5b6a1e61 100644 --- a/app/src/main/java/com/stardust/scriptdroid/App.java +++ b/app/src/main/java/com/stardust/scriptdroid/App.java @@ -5,21 +5,27 @@ import android.app.Application; import android.os.Bundle; import android.preference.PreferenceManager; +import com.stardust.scriptdroid.droid.runtime.action.ActionPerformAccessibilityDelegate; +import com.stardust.scriptdroid.record.AccessibilityRecorderDelegate; +import com.stardust.scriptdroid.service.AccessibilityWatchDogService; +import com.stardust.scriptdroid.ui.error.ErrorReportActivity; import com.stardust.util.CrashHandler; import com.stardust.util.StateObserver; +import java.lang.ref.WeakReference; + /** * Created by Stardust on 2017/1/27. */ public class App extends Application { - private static App instance; + private static WeakReference instance; private static StateObserver stateObserver; - private static Activity currentActivity; + private static WeakReference currentActivity; public static App getApp() { - return instance; + return instance.get(); } public static StateObserver getStateObserver() { @@ -29,13 +35,24 @@ public class App extends Application { public void onCreate() { super.onCreate(); - Thread.setDefaultUncaughtExceptionHandler(new CrashHandler(ErrorReportActivity.class)); - instance = this; + if (!BuildConfig.DEBUG) + Thread.setDefaultUncaughtExceptionHandler(new CrashHandler(ErrorReportActivity.class)); + instance = new WeakReference<>(this); stateObserver = new StateObserver(PreferenceManager.getDefaultSharedPreferences(this)); + registerActivityLifecycleCallback(); + initAccessibilityServiceDelegates(); + } + + private void initAccessibilityServiceDelegates() { + AccessibilityWatchDogService.addDelegateIfNeeded(100, ActionPerformAccessibilityDelegate.class); + AccessibilityWatchDogService.addDelegateIfNeeded(200, AccessibilityRecorderDelegate.getInstance()); + } + + private void registerActivityLifecycleCallback() { registerActivityLifecycleCallbacks(new SimpleActivityLifecycleCallbacks() { @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { - currentActivity = activity; + currentActivity = new WeakReference<>(activity); } @@ -46,14 +63,14 @@ public class App extends Application { @Override public void onActivityResumed(Activity activity) { - currentActivity = activity; + currentActivity = new WeakReference<>(activity); } }); } public static Activity currentActivity() { - return currentActivity; + return currentActivity.get(); } diff --git a/app/src/main/java/com/stardust/scriptdroid/IssueReportActivity.java b/app/src/main/java/com/stardust/scriptdroid/IssueReportActivity.java deleted file mode 100644 index dc1fd959..00000000 --- a/app/src/main/java/com/stardust/scriptdroid/IssueReportActivity.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.stardust.scriptdroid; - -import android.os.Bundle; -import android.support.design.widget.FloatingActionButton; -import android.view.View; -import android.widget.EditText; -import android.widget.Toast; - -import com.heinrichreimersoftware.androidissuereporter.IssueReporterActivity; -import com.heinrichreimersoftware.androidissuereporter.model.github.GithubTarget; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -/** - * Created by Stardust on 2017/2/13. - */ - -public class IssueReportActivity extends IssueReporterActivity { - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - handleIntent(); - findViewById(com.heinrichreimersoftware.androidissuereporter.R.id.air_optionAnonymous).performClick(); - ((EditText) findViewById(R.id.air_inputTitle)).setText(R.string.text_bug_report); - getSupportActionBar().setTitle(R.string.text_report_bug); - FloatingActionButton send = (FloatingActionButton) this.findViewById(com.heinrichreimersoftware.androidissuereporter.R.id.air_buttonSend); - try { - final Method reportIssue = IssueReporterActivity.class.getDeclaredMethod("reportIssue"); - reportIssue.setAccessible(true); - send.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - try { - reportIssue.invoke(IssueReportActivity.this); - Toast.makeText(IssueReportActivity.this, R.string.text_report_succeed, Toast.LENGTH_SHORT).show(); - } catch (IllegalAccessException | InvocationTargetException e) { - e.printStackTrace(); - Toast.makeText(IssueReportActivity.this, R.string.text_report_fail, Toast.LENGTH_SHORT).show(); - } - exit(); - } - }); - } catch (NoSuchMethodException e) { - e.printStackTrace(); - } - - - } - - private void handleIntent() { - final String errorDetail = getIntent().getStringExtra("error"); - ((EditText) findViewById(R.id.air_inputDescription)).setText(errorDetail); - } - - private void exit() { - finishAffinity(); - } - - @Override - protected GithubTarget getTarget() { - return new GithubTarget("hyb1996", "NoRootScriptDroid"); - } - - @Override - protected String getGuestToken() { - return "cd403d68a9f3a3590a14408d055c55180e7af7d3"; - } - -} diff --git a/app/src/main/java/com/stardust/scriptdroid/droid/assist/BoundsAssistClipList.java b/app/src/main/java/com/stardust/scriptdroid/bounds_assist/BoundsAssistClipList.java similarity index 88% rename from app/src/main/java/com/stardust/scriptdroid/droid/assist/BoundsAssistClipList.java rename to app/src/main/java/com/stardust/scriptdroid/bounds_assist/BoundsAssistClipList.java index 0e123a71..b4ebd98f 100644 --- a/app/src/main/java/com/stardust/scriptdroid/droid/assist/BoundsAssistClipList.java +++ b/app/src/main/java/com/stardust/scriptdroid/bounds_assist/BoundsAssistClipList.java @@ -1,4 +1,4 @@ -package com.stardust.scriptdroid.droid.assist; +package com.stardust.scriptdroid.bounds_assist; /** * Created by Stardust on 2017/2/4. diff --git a/app/src/main/java/com/stardust/scriptdroid/droid/assist/BoundsAssistant.java b/app/src/main/java/com/stardust/scriptdroid/bounds_assist/BoundsAssistant.java similarity index 80% rename from app/src/main/java/com/stardust/scriptdroid/droid/assist/BoundsAssistant.java rename to app/src/main/java/com/stardust/scriptdroid/bounds_assist/BoundsAssistant.java index 27a14e6d..6cc26512 100644 --- a/app/src/main/java/com/stardust/scriptdroid/droid/assist/BoundsAssistant.java +++ b/app/src/main/java/com/stardust/scriptdroid/bounds_assist/BoundsAssistant.java @@ -1,4 +1,4 @@ -package com.stardust.scriptdroid.droid.assist; +package com.stardust.scriptdroid.bounds_assist; import android.graphics.Rect; import android.preference.PreferenceManager; @@ -17,7 +17,7 @@ import com.stardust.scriptdroid.R; */ public class BoundsAssistant { - public static final String KEY_ASSIST_MODE_ENABLE = "ASSIST_MODE_ENABLE"; + public static final String KEY_BOUNDS_ASSIST_ENABLE = "ASSIST_MODE_ENABLE"; private static boolean assistModeEnable; @@ -32,7 +32,7 @@ public class BoundsAssistant { showAssistModeInfoDialog(); } BoundsAssistant.assistModeEnable = assistModeEnable; - App.getStateObserver().setState(KEY_ASSIST_MODE_ENABLE, assistModeEnable); + App.getStateObserver().setState(KEY_BOUNDS_ASSIST_ENABLE, assistModeEnable); } private static void showAssistModeInfoDialog() { @@ -59,21 +59,25 @@ public class BoundsAssistant { } } - private static Rect getBoundsInScreen(AccessibilityNodeInfo nodeInfo) { + public static Rect getBoundsInScreen(AccessibilityNodeInfo nodeInfo) { Rect rect = new Rect(); nodeInfo.getBoundsInScreen(rect); return rect; } private static void saveAndAlertBounds(Rect rect) { - String str = rect.toString().replace('-', ',').replace(" ", "").substring(4); + String str = boundsToString(rect); boundsAssistClipList.add(str); Toast.makeText(App.getApp(), str, Toast.LENGTH_SHORT).show(); } + public static String boundsToString(Rect rect) { + return rect.toString().replace('-', ',').replace(" ", "").substring(4); + } + static { - assistModeEnable = PreferenceManager.getDefaultSharedPreferences(App.getApp()).getBoolean(KEY_ASSIST_MODE_ENABLE, false); + assistModeEnable = PreferenceManager.getDefaultSharedPreferences(App.getApp()).getBoolean(KEY_BOUNDS_ASSIST_ENABLE, false); } } diff --git a/app/src/main/java/com/stardust/scriptdroid/droid/assist/SharedPrefBoundsAssistClipList.java b/app/src/main/java/com/stardust/scriptdroid/bounds_assist/SharedPrefBoundsAssistClipList.java similarity index 98% rename from app/src/main/java/com/stardust/scriptdroid/droid/assist/SharedPrefBoundsAssistClipList.java rename to app/src/main/java/com/stardust/scriptdroid/bounds_assist/SharedPrefBoundsAssistClipList.java index 8715c6b0..3a4bc1a8 100644 --- a/app/src/main/java/com/stardust/scriptdroid/droid/assist/SharedPrefBoundsAssistClipList.java +++ b/app/src/main/java/com/stardust/scriptdroid/bounds_assist/SharedPrefBoundsAssistClipList.java @@ -1,4 +1,4 @@ -package com.stardust.scriptdroid.droid.assist; +package com.stardust.scriptdroid.bounds_assist; import android.content.Context; import android.content.SharedPreferences; diff --git a/app/src/main/java/com/stardust/scriptdroid/droid/runtime/DroidRuntime.java b/app/src/main/java/com/stardust/scriptdroid/droid/runtime/DroidRuntime.java index 70e4c1f2..e881d2ef 100644 --- a/app/src/main/java/com/stardust/scriptdroid/droid/runtime/DroidRuntime.java +++ b/app/src/main/java/com/stardust/scriptdroid/droid/runtime/DroidRuntime.java @@ -13,14 +13,17 @@ import com.afollestad.materialdialogs.MaterialDialog; import com.jraska.console.Console; import com.stardust.scriptdroid.App; import com.stardust.scriptdroid.R; -import com.stardust.scriptdroid.droid.ConsoleActivity; +import com.stardust.scriptdroid.ui.console.ConsoleActivity; import com.stardust.scriptdroid.droid.runtime.action.Action; import com.stardust.scriptdroid.droid.runtime.action.ActionFactory; -import com.stardust.scriptdroid.droid.runtime.action.ActionPerformService; +import com.stardust.scriptdroid.droid.runtime.action.ActionPerformAccessibilityDelegate; import com.stardust.scriptdroid.droid.runtime.action.ActionTarget; +import com.stardust.scriptdroid.droid.runtime.action.GetTextAction; import com.stardust.scriptdroid.droid.runtime.api.IDroidRuntime; +import com.stardust.scriptdroid.service.AccessibilityWatchDogService; import com.stardust.scriptdroid.tool.Shell; +import java.util.Collections; import java.util.List; import timber.log.Timber; @@ -166,22 +169,40 @@ public class DroidRuntime implements IDroidRuntime { } private boolean performAction(Action action) { - if (ActionPerformService.getInstance() == null) { + if (AccessibilityWatchDogService.getInstance() == null) { toast(App.getApp().getString(R.string.text_no_accessibility_permission)); throw new ScriptStopException(App.getApp().getString(R.string.text_no_accessibility_permission)); } - ActionPerformService.setAction(action); + ActionPerformAccessibilityDelegate.setAction(action); synchronized (mActionPerformLock) { try { mActionPerformLock.wait(); } catch (InterruptedException e) { - ActionPerformService.setActions(ActionPerformService.NO_ACTION); + ActionPerformAccessibilityDelegate.setAction(ActionPerformAccessibilityDelegate.NO_ACTION); throw new ScriptStopException(App.getApp().getString(R.string.text_script_stopped), e); } } return mActionPerformResult; } + public List getTexts() { + if (AccessibilityWatchDogService.getInstance() == null) { + toast(App.getApp().getString(R.string.text_no_accessibility_permission)); + throw new ScriptStopException(App.getApp().getString(R.string.text_no_accessibility_permission)); + } + GetTextAction.result = Collections.EMPTY_LIST; + ActionPerformAccessibilityDelegate.setAction(new GetTextAction()); + synchronized (mActionPerformLock) { + try { + mActionPerformLock.wait(); + return GetTextAction.result; + } catch (InterruptedException e) { + ActionPerformAccessibilityDelegate.setAction(ActionPerformAccessibilityDelegate.NO_ACTION); + throw new ScriptStopException(App.getApp().getString(R.string.text_script_stopped), e); + } + } + } + @Override public void toast(final String text) { mUIHandler.post(new Runnable() { diff --git a/app/src/main/java/com/stardust/scriptdroid/droid/runtime/action/ActionPerformAccessibilityDelegate.java b/app/src/main/java/com/stardust/scriptdroid/droid/runtime/action/ActionPerformAccessibilityDelegate.java new file mode 100644 index 00000000..93bdbf20 --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/droid/runtime/action/ActionPerformAccessibilityDelegate.java @@ -0,0 +1,55 @@ +package com.stardust.scriptdroid.droid.runtime.action; + +import android.accessibilityservice.AccessibilityService; +import android.util.Log; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityNodeInfo; + +import com.stardust.scriptdroid.droid.runtime.DroidRuntime; +import com.stardust.scriptdroid.service.AccessibilityDelegate; + + +/** + * Created by Stardust on 2017/1/21. + */ + +public class ActionPerformAccessibilityDelegate implements AccessibilityDelegate { + + private static final String TAG = "ActionPerformDelegate"; + + public static final Action NO_ACTION = null; + + private static Action action; + + public static void setAction(Action action) { + synchronized (ActionPerformAccessibilityDelegate.class) { + ActionPerformAccessibilityDelegate.action = action; + } + } + + @Override + public boolean onAccessibilityEvent(AccessibilityService service, AccessibilityEvent event) { + if (action == NO_ACTION) + return false; + AccessibilityNodeInfo root = service.getRootInActiveWindow(); + if (root == null) { + Log.v(TAG, "root = null"); + } + Log.i(TAG, "perform action:" + action); + if (action.perform(root)) { + onActionPerformed(true); + } else if (!action.performUtilSucceed()) { + onActionPerformed(false); + } + return false; + } + + + private void onActionPerformed(boolean succeed) { + synchronized (ActionPerformAccessibilityDelegate.class) { + action = NO_ACTION; + DroidRuntime.getRuntime().notifyActionPerformed(succeed); + } + } + +} diff --git a/app/src/main/java/com/stardust/scriptdroid/droid/runtime/action/ActionPerformService.java b/app/src/main/java/com/stardust/scriptdroid/droid/runtime/action/ActionPerformService.java deleted file mode 100644 index af75677c..00000000 --- a/app/src/main/java/com/stardust/scriptdroid/droid/runtime/action/ActionPerformService.java +++ /dev/null @@ -1,123 +0,0 @@ -package com.stardust.scriptdroid.droid.runtime.action; - -import android.accessibilityservice.AccessibilityService; -import android.os.Build; -import android.util.Log; -import android.view.accessibility.AccessibilityEvent; -import android.view.accessibility.AccessibilityNodeInfo; - -import com.stardust.scriptdroid.App; -import com.stardust.scriptdroid.droid.assist.BoundsAssistant; -import com.stardust.scriptdroid.droid.runtime.DroidRuntime; -import com.stardust.view.accessibility.AccessibilityServiceUtils; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - - -/** - * Created by Stardust on 2017/1/21. - */ - -public class ActionPerformService extends AccessibilityService { - - private static final String TAG = "ActionPerformService"; - private static volatile ActionPerformService instance; - - @SuppressWarnings("unchecked") - public static final List NO_ACTION = Collections.EMPTY_LIST; - public static final int STATE_INACTIVE = -1; - public static final int STATE_PERFORM = 0; - - public static final List actions = new ArrayList<>(); - private static int state = STATE_INACTIVE; - - public static void setActions(Collection collection) { - synchronized (actions) { - actions.clear(); - actions.addAll(collection); - state = actions.size() > 0 ? STATE_PERFORM : STATE_INACTIVE; - } - } - - public static void setAction(Action action) { - setActions(Collections.singletonList(action)); - } - - public static ActionPerformService getInstance() { - return instance; - } - - @Override - public void onAccessibilityEvent(AccessibilityEvent event) { - Log.v(TAG, "onAccessibilityEvent: state=" + state + " event=" + event); - BoundsAssistant.performAssistance(event); - if (state == STATE_INACTIVE) - return; - AccessibilityNodeInfo root = getRootInActiveWindow(); - if (root == null) { - Log.v(TAG, "root = null"); - } - Action action = nextAction(); - if (action == null) { - onActionPerformed(true); - } else { - Log.i(TAG, "perform action:" + action); - if (action.perform(root)) { - state++; - } else if (!action.performUtilSucceed()) { - onActionPerformed(false); - } - } - - } - - private void onActionPerformed(boolean succeed) { - state = STATE_INACTIVE; - synchronized (actions) { - actions.clear(); - } - DroidRuntime.getRuntime().notifyActionPerformed(succeed); - } - - private Action nextAction() { - synchronized (actions) { - if (state >= actions.size()) { - return null; - } - return actions.get(state); - } - } - - @Override - public void onInterrupt() { - - } - - @Override - public void onServiceConnected() { - // FIXME: 2017/2/12 有时在无障碍中开启服务后这里不会调用服务也不会运行,安卓的BUG??? - Log.v(TAG, "onServiceConnected"); - } - - @Override - public void onCreate() { - super.onCreate(); - Log.v(TAG, "onCreate"); - instance = this; - } - - public static void disable() { - if (instance != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - instance.disableSelf(); - } else { - AccessibilityServiceUtils.goToAccessibilitySetting(App.getApp()); - } - } - - public static boolean isEnable() { - return AccessibilityServiceUtils.isAccessibilityServiceEnabled(App.getApp(), ActionPerformService.class); - } -} diff --git a/app/src/main/java/com/stardust/scriptdroid/droid/runtime/action/GetTextAction.java b/app/src/main/java/com/stardust/scriptdroid/droid/runtime/action/GetTextAction.java new file mode 100644 index 00000000..26fc858e --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/droid/runtime/action/GetTextAction.java @@ -0,0 +1,37 @@ +package com.stardust.scriptdroid.droid.runtime.action; + +import android.view.accessibility.AccessibilityNodeInfo; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by Stardust on 2017/2/14. + */ + +public class GetTextAction extends Action { + + public static List result; + + @Override + public boolean perform(AccessibilityNodeInfo root) { + List texts = new ArrayList<>(); + getText(root, texts); + result = texts; + return true; + } + + private void getText(AccessibilityNodeInfo nodeInfo, List texts) { + CharSequence text = nodeInfo.getText(); + if (text != null && text.length() != 0) { + texts.add(text.toString()); + } + for (int i = 0; i < nodeInfo.getChildCount(); i++) { + AccessibilityNodeInfo child = nodeInfo.getChild(i); + if (child != null) { + getText(child, texts); + child.recycle(); + } + } + } +} diff --git a/app/src/main/java/com/stardust/scriptdroid/droid/script/DuktapeJavaScriptEngine.java b/app/src/main/java/com/stardust/scriptdroid/droid/script/DuktapeJavaScriptEngine.java index b4ce7dc6..f3d63058 100644 --- a/app/src/main/java/com/stardust/scriptdroid/droid/script/DuktapeJavaScriptEngine.java +++ b/app/src/main/java/com/stardust/scriptdroid/droid/script/DuktapeJavaScriptEngine.java @@ -11,6 +11,8 @@ import java.io.StringReader; import java.util.HashMap; import java.util.Hashtable; import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; /** * Created by Stardust on 2017/1/27. @@ -70,7 +72,7 @@ public class DuktapeJavaScriptEngine implements JavaScriptEngine { public void removeAndStop(Thread thread) { synchronized (mThreadDuktapeEngineMap) { DuktapeEngine engine = mThreadDuktapeEngineMap.remove(thread); - stop(engine, thread); + forceStop(engine, thread); } } @@ -84,14 +86,21 @@ public class DuktapeJavaScriptEngine implements JavaScriptEngine { } } - private void stop(DuktapeEngine engine, Thread thread) { - if (engine != null) - engine.destory(); + + private void forceStop(final DuktapeEngine engine, Thread thread) { try { thread.interrupt(); } catch (Exception e) { e.printStackTrace(); } + if (engine != null) { + new Timer().schedule(new TimerTask() { + @Override + public void run() { + engine.destory(); + } + }, 1000); + } } private void add(DuktapeEngine duktapeEngine, Thread thread) { @@ -110,7 +119,7 @@ public class DuktapeJavaScriptEngine implements JavaScriptEngine { int n; synchronized (mThreadDuktapeEngineMap) { for (Map.Entry entry : mThreadDuktapeEngineMap.entrySet()) { - stop(entry.getValue(), entry.getKey()); + forceStop(entry.getValue(), entry.getKey()); } n = mThreadDuktapeEngineMap.size(); mThreadDuktapeEngineMap.clear(); diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/AssistModeSwitchNotification.java b/app/src/main/java/com/stardust/scriptdroid/external/notification/bounds_assist/BoundsAssistSwitchNotification.java similarity index 63% rename from app/src/main/java/com/stardust/scriptdroid/ui/AssistModeSwitchNotification.java rename to app/src/main/java/com/stardust/scriptdroid/external/notification/bounds_assist/BoundsAssistSwitchNotification.java index 4e4cd4e0..1248d000 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/AssistModeSwitchNotification.java +++ b/app/src/main/java/com/stardust/scriptdroid/external/notification/bounds_assist/BoundsAssistSwitchNotification.java @@ -1,4 +1,4 @@ -package com.stardust.scriptdroid.ui; +package com.stardust.scriptdroid.external.notification.bounds_assist; import android.app.Notification; import android.app.NotificationManager; @@ -7,9 +7,8 @@ import android.preference.PreferenceManager; import android.support.v4.app.NotificationCompat; import com.stardust.scriptdroid.App; -import com.stardust.scriptdroid.AssistModeSwitchService; import com.stardust.scriptdroid.R; -import com.stardust.scriptdroid.droid.assist.BoundsAssistant; +import com.stardust.scriptdroid.bounds_assist.BoundsAssistant; import com.stardust.util.StateObserver; @@ -17,36 +16,35 @@ import com.stardust.util.StateObserver; * Created by Stardust on 2017/2/2. */ -public class AssistModeSwitchNotification { +public class BoundsAssistSwitchNotification { private static final int NOTIFY_ID = 11126; - public static final String KEY_ASSIST_MODE_NOTIFICATION = "KEY_ASSIST_MODE_NOTIFICATION"; + public static final String KEY_BOUNDS_ASSIST_SWITCH_NOTIFICATION_ENABLE = "KEY_BOUNDS_ASSIST_SWITCH_NOTIFICATION_ENABLE"; private static boolean enable = false; - private static Notification notification; public static boolean isEnable() { return enable; } static { - App.getStateObserver().register(KEY_ASSIST_MODE_NOTIFICATION, new StateObserver.OnBooleanStateChangedListener() { + App.getStateObserver().register(KEY_BOUNDS_ASSIST_SWITCH_NOTIFICATION_ENABLE, new StateObserver.OnStateChangedListener() { @Override - public void onStateChanged(Boolean newState) { + public void onStateChanged(boolean newState) { setEnable(newState); } @Override - public void initState(Boolean state) { + public void initState(boolean state) { enable = state; if (enable) { showNotification(); } } }); - App.getStateObserver().register(BoundsAssistant.KEY_ASSIST_MODE_ENABLE, new StateObserver.OnBooleanStateChangedListener() { + App.getStateObserver().register(BoundsAssistant.KEY_BOUNDS_ASSIST_ENABLE, new StateObserver.OnStateChangedListener() { @Override - public void onStateChanged(Boolean newState) { + public void onStateChanged(boolean newState) { if (enable) { setEnable(false); setEnable(true); @@ -54,17 +52,17 @@ public class AssistModeSwitchNotification { } @Override - public void initState(Boolean state) { + public void initState(boolean state) { } }); } public static void setEnable(boolean enable) { - if (AssistModeSwitchNotification.enable == enable) + if (BoundsAssistSwitchNotification.enable == enable) return; - AssistModeSwitchNotification.enable = enable; - PreferenceManager.getDefaultSharedPreferences(App.getApp()).edit().putBoolean(KEY_ASSIST_MODE_NOTIFICATION, enable).apply(); + BoundsAssistSwitchNotification.enable = enable; + PreferenceManager.getDefaultSharedPreferences(App.getApp()).edit().putBoolean(KEY_BOUNDS_ASSIST_SWITCH_NOTIFICATION_ENABLE, enable).apply(); if (enable) { showNotification(); } else { @@ -74,14 +72,14 @@ public class AssistModeSwitchNotification { private static void showNotification() { - notification = new NotificationCompat.Builder(App.getApp()) + Notification notification = new NotificationCompat.Builder(App.getApp()) .setAutoCancel(false) .setSmallIcon(R.drawable.ic_robot_head) - .setDeleteIntent(AssistModeSwitchService.getDeletePendingIntent()) + .setDeleteIntent(BoundsAssistSwitchNotificationHandleService.getDeletePendingIntent()) .setContentText(BoundsAssistant.isAssistModeEnable() ? App.getApp().getString(R.string.text_assist_mode_enabled) : App.getApp().getString(R.string.text_assist_mode_disabled)) - .setContentIntent(AssistModeSwitchService.getStartIntent()) + .setContentIntent(BoundsAssistSwitchNotificationHandleService.getStartIntent()) .build(); showNotification(notification); } diff --git a/app/src/main/java/com/stardust/scriptdroid/AssistModeSwitchService.java b/app/src/main/java/com/stardust/scriptdroid/external/notification/bounds_assist/BoundsAssistSwitchNotificationHandleService.java similarity index 65% rename from app/src/main/java/com/stardust/scriptdroid/AssistModeSwitchService.java rename to app/src/main/java/com/stardust/scriptdroid/external/notification/bounds_assist/BoundsAssistSwitchNotificationHandleService.java index 8d0fbdc2..d3c081c3 100644 --- a/app/src/main/java/com/stardust/scriptdroid/AssistModeSwitchService.java +++ b/app/src/main/java/com/stardust/scriptdroid/external/notification/bounds_assist/BoundsAssistSwitchNotificationHandleService.java @@ -1,4 +1,4 @@ -package com.stardust.scriptdroid; +package com.stardust.scriptdroid.external.notification.bounds_assist; import android.app.PendingIntent; import android.app.Service; @@ -6,17 +6,18 @@ import android.content.Intent; import android.os.IBinder; import android.support.annotation.Nullable; -import com.stardust.scriptdroid.droid.assist.BoundsAssistant; +import com.stardust.scriptdroid.App; +import com.stardust.scriptdroid.bounds_assist.BoundsAssistant; -import static com.stardust.scriptdroid.ui.AssistModeSwitchNotification.KEY_ASSIST_MODE_NOTIFICATION; +import static com.stardust.scriptdroid.external.notification.bounds_assist.BoundsAssistSwitchNotification.KEY_BOUNDS_ASSIST_SWITCH_NOTIFICATION_ENABLE; /** * Created by Stardust on 2017/2/2. */ -public class AssistModeSwitchService extends Service { +public class BoundsAssistSwitchNotificationHandleService extends Service { - private static final String EXTRA_INTENT_VALID = "intentValid"; + private static final String EXTRA_INTENT_VALID = "BoundsAssistSwitchNotificationHandleService.intentValid"; private static final String EXTRA_ACTION = "action"; private static final int ACTION_TOGGLE_ASSIST_MODE = 1; @@ -24,7 +25,7 @@ public class AssistModeSwitchService extends Service { public static PendingIntent getStartIntent() { - Intent intent = new Intent(App.getApp(), AssistModeSwitchService.class) + Intent intent = new Intent(App.getApp(), BoundsAssistSwitchNotificationHandleService.class) .putExtra(EXTRA_INTENT_VALID, true) .putExtra(EXTRA_ACTION, ACTION_TOGGLE_ASSIST_MODE); return PendingIntent.getService(App.getApp(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); @@ -32,7 +33,7 @@ public class AssistModeSwitchService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { - boolean intentValid = intent.getBooleanExtra("intentValid", false); + boolean intentValid = intent.getBooleanExtra(EXTRA_INTENT_VALID, false); if (intentValid) { performAction(intent.getIntExtra(EXTRA_ACTION, 0)); } @@ -46,7 +47,7 @@ public class AssistModeSwitchService extends Service { BoundsAssistant.setAssistModeEnable(!BoundsAssistant.isAssistModeEnable()); break; case ACTION_CANCEL_ASSIST_MODE_NOTIFICATION: - App.getStateObserver().setState(KEY_ASSIST_MODE_NOTIFICATION, false); + App.getStateObserver().setState(KEY_BOUNDS_ASSIST_SWITCH_NOTIFICATION_ENABLE, false); break; } } @@ -58,7 +59,7 @@ public class AssistModeSwitchService extends Service { } public static PendingIntent getDeletePendingIntent() { - Intent deleteIntent = new Intent(App.getApp(), AssistModeSwitchService.class) + Intent deleteIntent = new Intent(App.getApp(), BoundsAssistSwitchNotificationHandleService.class) .putExtra(EXTRA_INTENT_VALID, true) .putExtra(EXTRA_ACTION, ACTION_CANCEL_ASSIST_MODE_NOTIFICATION); return PendingIntent.getService(App.getApp(), 0, deleteIntent, PendingIntent.FLAG_ONE_SHOT); diff --git a/app/src/main/java/com/stardust/scriptdroid/external/notification/record/ActionRecordNotificationHandleService.java b/app/src/main/java/com/stardust/scriptdroid/external/notification/record/ActionRecordNotificationHandleService.java new file mode 100644 index 00000000..15d8089e --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/external/notification/record/ActionRecordNotificationHandleService.java @@ -0,0 +1,123 @@ +package com.stardust.scriptdroid.external.notification.record; + +import android.app.PendingIntent; +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; +import android.support.annotation.Nullable; +import android.widget.Toast; + +import com.stardust.scriptdroid.App; +import com.stardust.scriptdroid.R; +import com.stardust.scriptdroid.record.AccessibilityRecorderDelegate; +import com.stardust.scriptdroid.service.AccessibilityWatchDogService; +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 ActionRecordNotificationHandleService extends Service { + + + private static final String EXTRA_INTENT_VALID = "ActionRecordNotificationHandleService.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; + + public static PendingIntent getStartOrPauseIntent() { + Intent intent = new Intent(App.getApp(), ActionRecordNotificationHandleService.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(), ActionRecordNotificationHandleService.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(), ActionRecordNotificationHandleService.class) + .putExtra(EXTRA_INTENT_VALID, true) + .putExtra(EXTRA_ACTION, ACTION_DELETE); + return PendingIntent.getService(App.getApp(), ACTION_DELETE, 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(); + break; + case ACTION_START_OR_PAUSE: + startOrPauseRecord(); + break; + case ACTION_DELETE: + stopRecordIfNeeded(); + } + collapseNotificationBar(); + } + + private void collapseNotificationBar() { + sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); + } + + private void stopRecordIfNeeded() { + if (AccessibilityRecorderDelegate.getInstance().getState() != STOPPED) { + stopRecord(); + } + } + + private void startOrPauseRecord() { + int state = AccessibilityRecorderDelegate.getInstance().getState(); + if (state == PAUSED) { + AccessibilityRecorderDelegate.getInstance().resumeRecord(); + ActionRecordSwitchView.getInstance().setState(RECORDING); + } else if (state == RECORDING) { + AccessibilityRecorderDelegate.getInstance().pauseRecord(); + ActionRecordSwitchView.getInstance().setState(PAUSED); + } else { + //state == STOPPED + if (AccessibilityWatchDogService.getInstance() == null) { + Toast.makeText(this, R.string.text_need_enable_accessibility_service, Toast.LENGTH_SHORT).show(); + return; + } + AccessibilityRecorderDelegate.getInstance().startRecord(); + ActionRecordSwitchView.getInstance().setState(RECORDING); + Toast.makeText(this, R.string.text_start_record, Toast.LENGTH_SHORT).show(); + } + } + + private void stopRecord() { + if (AccessibilityRecorderDelegate.getInstance().getState() != STOPPED) { + String script = AccessibilityRecorderDelegate.getInstance().stopRecord(); + ActionRecordSwitchView.getInstance().setState(STOPPED); + MainActivity.onActionRecordStopped(this, script); + } else { + Toast.makeText(App.getApp(), R.string.text_not_recording, Toast.LENGTH_SHORT).show(); + } + } + + @Nullable + @Override + public IBinder onBind(Intent intent) { + return null; + } +} diff --git a/app/src/main/java/com/stardust/scriptdroid/external/notification/record/ActionRecordSwitchNotification.java b/app/src/main/java/com/stardust/scriptdroid/external/notification/record/ActionRecordSwitchNotification.java new file mode 100644 index 00000000..6cf13fd0 --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/external/notification/record/ActionRecordSwitchNotification.java @@ -0,0 +1,36 @@ +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; + +/** + * 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(ActionRecordNotificationHandleService.getDeleteIntent()) + .setCustomContentView(ActionRecordSwitchView.getInstance()); + } + showNotification(builder.build()); + } + + private static void showNotification(Notification notification) { + NotificationManager notificationManager = (NotificationManager) App.getApp().getSystemService(Context.NOTIFICATION_SERVICE); + notificationManager.notify(NOTIFY_ID, notification); + } +} diff --git a/app/src/main/java/com/stardust/scriptdroid/external/notification/record/ActionRecordSwitchView.java b/app/src/main/java/com/stardust/scriptdroid/external/notification/record/ActionRecordSwitchView.java new file mode 100644 index 00000000..f59a1a0e --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/external/notification/record/ActionRecordSwitchView.java @@ -0,0 +1,54 @@ +package com.stardust.scriptdroid.external.notification.record; + +import android.widget.RemoteViews; + +import com.stardust.scriptdroid.App; +import com.stardust.scriptdroid.R; + +/** + * Created by Stardust on 2017/2/14. + */ + +public class ActionRecordSwitchView extends RemoteViews { + + private static ActionRecordSwitchView instance; + + public static final int STOPPED = 0; + public static final int PAUSED = 1; + public static final int RECORDING = 2; + + public static ActionRecordSwitchView getInstance() { + if (instance == null) { + instance = new ActionRecordSwitchView(); + } + return instance; + } + + private ActionRecordSwitchView() { + super(App.getApp().getPackageName(), R.layout.remote_views_record_switch); + setUpOnClick(); + } + + public void setState(int state) { + switch (state) { + case 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: + 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: + 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(); + } + + private void setUpOnClick() { + setOnClickPendingIntent(R.id.stop, ActionRecordNotificationHandleService.getStopIntent()); + setOnClickPendingIntent(R.id.start_or_pause, ActionRecordNotificationHandleService.getStartOrPauseIntent()); + } +} diff --git a/app/src/main/java/com/stardust/scriptdroid/shortcut/Shortcut.java b/app/src/main/java/com/stardust/scriptdroid/external/shortcut/Shortcut.java similarity index 98% rename from app/src/main/java/com/stardust/scriptdroid/shortcut/Shortcut.java rename to app/src/main/java/com/stardust/scriptdroid/external/shortcut/Shortcut.java index 937cab59..b82d7eca 100644 --- a/app/src/main/java/com/stardust/scriptdroid/shortcut/Shortcut.java +++ b/app/src/main/java/com/stardust/scriptdroid/external/shortcut/Shortcut.java @@ -1,4 +1,4 @@ -package com.stardust.scriptdroid.shortcut; +package com.stardust.scriptdroid.external.shortcut; import android.content.Context; import android.content.Intent; diff --git a/app/src/main/java/com/stardust/scriptdroid/ShortcutActivity.java b/app/src/main/java/com/stardust/scriptdroid/external/shortcut/ShortcutActivity.java similarity index 96% rename from app/src/main/java/com/stardust/scriptdroid/ShortcutActivity.java rename to app/src/main/java/com/stardust/scriptdroid/external/shortcut/ShortcutActivity.java index e97e3b4f..ad651dc7 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ShortcutActivity.java +++ b/app/src/main/java/com/stardust/scriptdroid/external/shortcut/ShortcutActivity.java @@ -1,18 +1,17 @@ -package com.stardust.scriptdroid; +package com.stardust.scriptdroid.external.shortcut; import android.app.Activity; import android.os.Build; import android.os.Bundle; import android.text.TextUtils; -import android.view.accessibility.AccessibilityNodeInfo; import android.widget.Toast; +import com.stardust.scriptdroid.R; import com.stardust.scriptdroid.droid.Droid; import java.io.File; import java.util.LinkedList; import java.util.List; -import java.util.function.BooleanSupplier; import static android.Manifest.permission.READ_EXTERNAL_STORAGE; import static android.content.pm.PackageManager.PERMISSION_GRANTED; diff --git a/app/src/main/java/com/stardust/scriptdroid/tile/BoundsAssistEnableTileService.java b/app/src/main/java/com/stardust/scriptdroid/external/tile/BoundsAssistEnableTileService.java similarity index 86% rename from app/src/main/java/com/stardust/scriptdroid/tile/BoundsAssistEnableTileService.java rename to app/src/main/java/com/stardust/scriptdroid/external/tile/BoundsAssistEnableTileService.java index e176a18c..6c1f2104 100644 --- a/app/src/main/java/com/stardust/scriptdroid/tile/BoundsAssistEnableTileService.java +++ b/app/src/main/java/com/stardust/scriptdroid/external/tile/BoundsAssistEnableTileService.java @@ -1,11 +1,11 @@ -package com.stardust.scriptdroid.tile; +package com.stardust.scriptdroid.external.tile; import android.os.Build; import android.service.quicksettings.Tile; import android.service.quicksettings.TileService; import android.support.annotation.RequiresApi; -import com.stardust.scriptdroid.droid.assist.BoundsAssistant; +import com.stardust.scriptdroid.bounds_assist.BoundsAssistant; /** * Created by Stardust on 2017/1/26. diff --git a/app/src/main/java/com/stardust/scriptdroid/file/FileChooser.java b/app/src/main/java/com/stardust/scriptdroid/file/FileChooser.java deleted file mode 100644 index d10d0989..00000000 --- a/app/src/main/java/com/stardust/scriptdroid/file/FileChooser.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.stardust.scriptdroid.file; - -import android.app.Activity; -import android.content.ActivityNotFoundException; -import android.content.ContentResolver; -import android.content.Intent; -import android.net.Uri; - -import com.stardust.scriptdroid.R; - -import java.io.FileNotFoundException; -import java.io.InputStream; - -import static android.app.Activity.RESULT_OK; - -/** - * Created by Stardust on 2017/1/23. - */ - -public class FileChooser { - - public interface FileManagerNotFoundHandler { - void handle(ActivityNotFoundException e, String mimeType); - } - - public interface OnFileChoseListener { - void onFileChose(InputStream inputStream); - } - - private static final int FILE_CHOOSE = 1209; - private Activity mActivity; - - private OnFileChoseListener mOnFileChoseListener; - - public FileChooser(Activity activity) { - mActivity = activity; - } - - public void setOnFileChoseListener(OnFileChoseListener onFileChoseListener) { - mOnFileChoseListener = onFileChoseListener; - } - - - public void startFileManagerToChoose(String mimeType, FileManagerNotFoundHandler handler) { - Intent intent = new Intent(Intent.ACTION_GET_CONTENT); - intent.setType(mimeType); - intent.addCategory(Intent.CATEGORY_OPENABLE); - try { - mActivity.startActivityForResult(Intent.createChooser(intent, mActivity.getString(R.string.text_choose_file)), FILE_CHOOSE); - } catch (ActivityNotFoundException ex) { - handler.handle(ex, mimeType); - } - } - - public void onActivityResult(int requestCode, int resultCode, Intent data) { - if (requestCode == FILE_CHOOSE && resultCode == RESULT_OK) { - Uri uri = data.getData(); - ContentResolver cr = mActivity.getContentResolver(); - try { - InputStream inputStream = cr.openInputStream(uri); - mOnFileChoseListener.onFileChose(inputStream); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } - } - } -} diff --git a/app/src/main/java/com/stardust/scriptdroid/file/FileUtils.java b/app/src/main/java/com/stardust/scriptdroid/file/FileUtils.java index 9b0c5f7c..a6aea5e2 100644 --- a/app/src/main/java/com/stardust/scriptdroid/file/FileUtils.java +++ b/app/src/main/java/com/stardust/scriptdroid/file/FileUtils.java @@ -176,4 +176,26 @@ public class FileUtils { } + public static boolean writeString(String path, String text) { + return writeString(new File(path), text); + } + + public static boolean writeString(File file, String text) { + try { + return writeString(new FileOutputStream(file), text); + } catch (FileNotFoundException e) { + e.printStackTrace(); + return false; + } + } + + public static boolean writeString(OutputStream outputStream, String text) { + try { + outputStream.write(text.getBytes()); + return true; + } catch (IOException e) { + e.printStackTrace(); + return false; + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/stardust/scriptdroid/file/SampleFileTool.java b/app/src/main/java/com/stardust/scriptdroid/file/SampleFileManager.java similarity index 93% rename from app/src/main/java/com/stardust/scriptdroid/file/SampleFileTool.java rename to app/src/main/java/com/stardust/scriptdroid/file/SampleFileManager.java index c6ff9157..de7b97ba 100644 --- a/app/src/main/java/com/stardust/scriptdroid/file/SampleFileTool.java +++ b/app/src/main/java/com/stardust/scriptdroid/file/SampleFileManager.java @@ -16,7 +16,7 @@ import java.util.Map; /** * Created by Stardust on 2017/1/30. */ -public class SampleFileTool { +public class SampleFileManager { private static final Map SAMPLES = new MapEntries<>(new LinkedHashMap()) .entry("sample_open_running_services.js", R.string.text_sample_open_running_services) @@ -27,9 +27,9 @@ public class SampleFileTool { .entry("sample_alipay_scan.js", R.string.text_sample_alipay_scan) .map(); - private static SampleFileTool instance = new SampleFileTool(); + private static SampleFileManager instance = new SampleFileManager(); - public static SampleFileTool getInstance() { + public static SampleFileManager getInstance() { return instance; } diff --git a/app/src/main/java/com/stardust/scriptdroid/record/AccessibilityRecorderDelegate.java b/app/src/main/java/com/stardust/scriptdroid/record/AccessibilityRecorderDelegate.java new file mode 100644 index 00000000..94031788 --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/record/AccessibilityRecorderDelegate.java @@ -0,0 +1,95 @@ +package com.stardust.scriptdroid.record; + +import android.accessibilityservice.AccessibilityService; +import android.view.accessibility.AccessibilityEvent; + +import com.stardust.scriptdroid.service.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(event); + checkTimeOut(); + } + return false; + } + + private void checkTimeOut() { + if (System.currentTimeMillis() - mRecordStartMillis > RECORD_TIME_OUT) { + stopRecord(); + } + } + +} diff --git a/app/src/main/java/com/stardust/scriptdroid/record/ActionRecorder.java b/app/src/main/java/com/stardust/scriptdroid/record/ActionRecorder.java new file mode 100644 index 00000000..218106b5 --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/record/ActionRecorder.java @@ -0,0 +1,102 @@ +package com.stardust.scriptdroid.record; + +import android.os.Build; +import android.util.SparseArray; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityNodeInfo; + +import com.stardust.util.SparseArrayEntries; + +import static com.stardust.scriptdroid.bounds_assist.BoundsAssistant.boundsToString; +import static com.stardust.scriptdroid.bounds_assist.BoundsAssistant.getBoundsInScreen; + + +/** + * Created by Stardust on 2017/2/14. + */ + +public class ActionRecorder { + + private static final SparseArray CONVERTER_MAP = new SparseArrayEntries() + .entry(AccessibilityEvent.TYPE_VIEW_CLICKED, new DoUtilSucceedConverter("click")) + .entry(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED, new DoUtilSucceedConverter("longClick")) + .entry(AccessibilityEvent.TYPE_VIEW_SCROLLED, new DoOnceConverter("//scroll???")) + .sparseArray(); + + static { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + CONVERTER_MAP.put(AccessibilityEvent.TYPE_VIEW_CONTEXT_CLICKED, new DoOnceConverter("contextClick")); + } + } + + private StringBuilder mScript = new StringBuilder(); + private boolean mFirstAction = true; + + public void record(AccessibilityEvent event) { + EventToScriptConverter converter = CONVERTER_MAP.get(event.getEventType()); + if (converter != null) { + if (mFirstAction) { + mFirstAction = false; + return; + } + converter.onAccessibilityEvent(event, mScript); + mScript.append("\n"); + } + } + + public String getScript() { + return mScript.toString(); + } + + public void onResume() { + mFirstAction = true; + } + + interface EventToScriptConverter { + + void onAccessibilityEvent(AccessibilityEvent event, StringBuilder sb); + } + + private static abstract class BoundsEventConverter implements EventToScriptConverter { + + @Override + public void onAccessibilityEvent(AccessibilityEvent event, StringBuilder sb) { + AccessibilityNodeInfo source = event.getSource(); + String bounds = boundsToString(getBoundsInScreen(source)); + source.recycle(); + onAccessibilityEvent(event, bounds, sb); + } + + protected abstract void onAccessibilityEvent(AccessibilityEvent event, String bounds, StringBuilder sb); + + } + + private static class DoOnceConverter extends BoundsEventConverter { + + private String mActionFunction; + + DoOnceConverter(String actionFunction) { + mActionFunction = actionFunction; + } + + @Override + protected void onAccessibilityEvent(AccessibilityEvent event, String bounds, StringBuilder sb) { + sb.append(mActionFunction).append(bounds).append(";"); + } + } + + private static class DoUtilSucceedConverter extends BoundsEventConverter { + + private String mActionFunction; + + DoUtilSucceedConverter(String actionFunction) { + mActionFunction = actionFunction; + } + + @Override + protected void onAccessibilityEvent(AccessibilityEvent event, String bounds, StringBuilder sb) { + sb.append("while(!").append(mActionFunction).append(bounds).append(");"); + } + } + +} diff --git a/app/src/main/java/com/stardust/scriptdroid/service/AccessibilityDelegate.java b/app/src/main/java/com/stardust/scriptdroid/service/AccessibilityDelegate.java new file mode 100644 index 00000000..cc26462f --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/service/AccessibilityDelegate.java @@ -0,0 +1,14 @@ +package com.stardust.scriptdroid.service; + +import android.accessibilityservice.AccessibilityService; +import android.view.accessibility.AccessibilityEvent; + +/** + * Created by Stardust on 2017/2/14. + */ + +public interface AccessibilityDelegate { + + boolean onAccessibilityEvent(AccessibilityService service, AccessibilityEvent event); + +} diff --git a/app/src/main/java/com/stardust/scriptdroid/service/AccessibilityWatchDogService.java b/app/src/main/java/com/stardust/scriptdroid/service/AccessibilityWatchDogService.java new file mode 100644 index 00000000..ce68959b --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/service/AccessibilityWatchDogService.java @@ -0,0 +1,99 @@ +package com.stardust.scriptdroid.service; + +import android.accessibilityservice.AccessibilityService; +import android.os.Build; +import android.util.Log; +import android.view.accessibility.AccessibilityEvent; + +import com.stardust.scriptdroid.App; +import com.stardust.view.accessibility.AccessibilityServiceUtils; + +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; + +/** + * Created by Stardust on 2017/2/14. + */ + +public class AccessibilityWatchDogService extends AccessibilityService { + + private static final String TAG = "AccessibilityWatchDog"; + + private static final SortedMap mDelegates = new TreeMap<>(); + private static AccessibilityWatchDogService instance; + + public static void addDelegate(AccessibilityDelegate delegate, int uniquePriority) { + synchronized (mDelegates) { + mDelegates.put(uniquePriority, delegate); + } + } + + public static boolean containsPriority(int priority) { + synchronized (mDelegates) { + return mDelegates.containsKey(priority); + } + } + + public static AccessibilityDelegate getDelegate(int priority) { + synchronized (mDelegates) { + return mDelegates.get(priority); + } + } + + public static void addDelegateIfNeeded(int priority, Class delegateClass) { + try { + addDelegateIfNeeded(priority, delegateClass.newInstance()); + } catch (InstantiationException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + public static void addDelegateIfNeeded(int priority, AccessibilityDelegate delegate) { + synchronized (mDelegates) { + if (!mDelegates.containsKey(priority)) { + mDelegates.put(priority, delegate); + } + } + } + + public static boolean isEnable() { + return AccessibilityServiceUtils.isAccessibilityServiceEnabled(App.getApp(), AccessibilityWatchDogService.class); + } + + public static AccessibilityWatchDogService getInstance() { + return instance; + } + + @Override + public synchronized void onAccessibilityEvent(AccessibilityEvent event) { + Log.v(TAG, "onAccessibilityEvent: " + event); + synchronized (mDelegates) { + for (Map.Entry entry : mDelegates.entrySet()) { + if (entry.getValue().onAccessibilityEvent(this, event)) + break; + } + } + } + + @Override + public void onInterrupt() { + } + + @Override + protected void onServiceConnected() { + super.onServiceConnected(); + // FIXME: 2017/2/12 有时在无障碍中开启服务后这里不会调用服务也不会运行,安卓的BUG??? + Log.v(TAG, "onServiceConnected"); + instance = this; + } + + public static void disable() { + if (instance != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + instance.disableSelf(); + } else { + AccessibilityServiceUtils.goToAccessibilitySetting(App.getApp()); + } + } + +} diff --git a/app/src/main/java/com/stardust/scriptdroid/tool/IntentTool.java b/app/src/main/java/com/stardust/scriptdroid/tool/IntentTool.java index ca466657..0e23a223 100644 --- a/app/src/main/java/com/stardust/scriptdroid/tool/IntentTool.java +++ b/app/src/main/java/com/stardust/scriptdroid/tool/IntentTool.java @@ -47,4 +47,5 @@ public class IntentTool { .putExtra(Intent.EXTRA_TEXT, text) .setType("text/plain")); } + } diff --git a/app/src/main/java/com/stardust/scriptdroid/BaseActivity.java b/app/src/main/java/com/stardust/scriptdroid/ui/BaseActivity.java similarity index 97% rename from app/src/main/java/com/stardust/scriptdroid/BaseActivity.java rename to app/src/main/java/com/stardust/scriptdroid/ui/BaseActivity.java index 392966aa..ddd5a6dd 100644 --- a/app/src/main/java/com/stardust/scriptdroid/BaseActivity.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/BaseActivity.java @@ -1,4 +1,4 @@ -package com.stardust.scriptdroid; +package com.stardust.scriptdroid.ui; import android.os.Build; import android.os.Bundle; @@ -9,6 +9,8 @@ import android.support.v7.widget.Toolbar; import android.view.View; +import com.stardust.scriptdroid.R; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; diff --git a/app/src/main/java/com/stardust/scriptdroid/droid/ConsoleActivity.java b/app/src/main/java/com/stardust/scriptdroid/ui/console/ConsoleActivity.java similarity index 95% rename from app/src/main/java/com/stardust/scriptdroid/droid/ConsoleActivity.java rename to app/src/main/java/com/stardust/scriptdroid/ui/console/ConsoleActivity.java index 91ac6910..37be7626 100644 --- a/app/src/main/java/com/stardust/scriptdroid/droid/ConsoleActivity.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/console/ConsoleActivity.java @@ -1,4 +1,4 @@ -package com.stardust.scriptdroid.droid; +package com.stardust.scriptdroid.ui.console; import android.content.Context; import android.graphics.Color; @@ -10,7 +10,7 @@ import android.view.MenuItem; import android.widget.TextView; import com.jraska.console.Console; -import com.stardust.scriptdroid.BaseActivity; +import com.stardust.scriptdroid.ui.BaseActivity; import com.stardust.scriptdroid.R; /** diff --git a/app/src/main/java/com/stardust/scriptdroid/EditActivity.java b/app/src/main/java/com/stardust/scriptdroid/ui/edit/EditActivity.java similarity index 95% rename from app/src/main/java/com/stardust/scriptdroid/EditActivity.java rename to app/src/main/java/com/stardust/scriptdroid/ui/edit/EditActivity.java index 162c835e..b02cb855 100644 --- a/app/src/main/java/com/stardust/scriptdroid/EditActivity.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/edit/EditActivity.java @@ -1,4 +1,4 @@ -package com.stardust.scriptdroid; +package com.stardust.scriptdroid.ui.edit; import android.content.Context; import android.content.Intent; @@ -18,12 +18,14 @@ import com.jecelyin.editor.v2.common.SaveListener; import com.jecelyin.editor.v2.ui.EditorDelegate; import com.jecelyin.editor.v2.view.EditorView; import com.jecelyin.editor.v2.view.menu.MenuDef; +import com.stardust.scriptdroid.Pref; +import com.stardust.scriptdroid.R; import com.stardust.scriptdroid.droid.Droid; -import com.stardust.scriptdroid.editor920.Editor920Activity; -import com.stardust.scriptdroid.ui.AssistClipListRecyclerView; -import com.stardust.scriptdroid.ui.EditSideMenuFragment; -import com.stardust.scriptdroid.ui.FunctionListRecyclerView; -import com.stardust.scriptdroid.widget.ToolbarMenuItem; +import com.stardust.scriptdroid.ui.edit.sidemenu.AssistClipListRecyclerView; +import com.stardust.scriptdroid.ui.edit.sidemenu.EditSideMenuFragment; +import com.stardust.scriptdroid.ui.edit.sidemenu.FunctionListRecyclerView; +import com.stardust.scriptdroid.ui.edit.editor920.Editor920Activity; +import com.stardust.widget.ToolbarMenuItem; import com.stardust.util.SparseArrayEntries; import com.stardust.view.ViewBinder; import com.stardust.view.ViewBinding; diff --git a/app/src/main/java/com/stardust/scriptdroid/EditAndRunIntentActivity.java b/app/src/main/java/com/stardust/scriptdroid/ui/edit/EditAndRunIntentActivity.java similarity index 61% rename from app/src/main/java/com/stardust/scriptdroid/EditAndRunIntentActivity.java rename to app/src/main/java/com/stardust/scriptdroid/ui/edit/EditAndRunIntentActivity.java index 87ab924c..9c786e44 100644 --- a/app/src/main/java/com/stardust/scriptdroid/EditAndRunIntentActivity.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/edit/EditAndRunIntentActivity.java @@ -1,12 +1,13 @@ -package com.stardust.scriptdroid; +package com.stardust.scriptdroid.ui.edit; import android.content.Intent; import android.os.Bundle; import android.support.annotation.Nullable; import android.text.TextUtils; +import android.widget.Toast; -import com.stardust.scriptdroid.BaseActivity; -import com.stardust.scriptdroid.EditActivity; +import com.stardust.scriptdroid.ui.BaseActivity; +import com.stardust.scriptdroid.R; /** * Created by Stardust on 2017/2/2. @@ -17,7 +18,12 @@ public class EditAndRunIntentActivity extends BaseActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - handleIntent(); + try { + handleIntent(); + } catch (Exception e) { + e.printStackTrace(); + Toast.makeText(this, R.string.edit_and_run_handle_intent_error, Toast.LENGTH_LONG).show(); + } } private void handleIntent() { diff --git a/app/src/main/java/com/stardust/scriptdroid/ImportIntentActivity.java b/app/src/main/java/com/stardust/scriptdroid/ui/edit/ImportIntentActivity.java similarity index 90% rename from app/src/main/java/com/stardust/scriptdroid/ImportIntentActivity.java rename to app/src/main/java/com/stardust/scriptdroid/ui/edit/ImportIntentActivity.java index 40d85391..e9efc9de 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ImportIntentActivity.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/edit/ImportIntentActivity.java @@ -1,4 +1,4 @@ -package com.stardust.scriptdroid; +package com.stardust.scriptdroid.ui.edit; import android.content.Intent; import android.os.Bundle; @@ -7,8 +7,11 @@ import android.support.annotation.Nullable; import android.text.TextUtils; import com.afollestad.materialdialogs.MaterialDialog; +import com.stardust.scriptdroid.ui.BaseActivity; +import com.stardust.scriptdroid.R; import com.stardust.scriptdroid.droid.script.file.ScriptFile; import com.stardust.scriptdroid.droid.script.file.SharedPrefScriptFileList; +import com.stardust.scriptdroid.ui.main.MainActivity; import java.io.File; diff --git a/app/src/main/java/com/stardust/scriptdroid/editor920/Editor920Activity.java b/app/src/main/java/com/stardust/scriptdroid/ui/edit/editor920/Editor920Activity.java similarity index 96% rename from app/src/main/java/com/stardust/scriptdroid/editor920/Editor920Activity.java rename to app/src/main/java/com/stardust/scriptdroid/ui/edit/editor920/Editor920Activity.java index 6cb40c7e..c8e464ab 100644 --- a/app/src/main/java/com/stardust/scriptdroid/editor920/Editor920Activity.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/edit/editor920/Editor920Activity.java @@ -1,4 +1,4 @@ -package com.stardust.scriptdroid.editor920; +package com.stardust.scriptdroid.ui.edit.editor920; import android.support.annotation.NonNull; diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/AssistClipListRecyclerView.java b/app/src/main/java/com/stardust/scriptdroid/ui/edit/sidemenu/AssistClipListRecyclerView.java similarity index 94% rename from app/src/main/java/com/stardust/scriptdroid/ui/AssistClipListRecyclerView.java rename to app/src/main/java/com/stardust/scriptdroid/ui/edit/sidemenu/AssistClipListRecyclerView.java index d353d9b4..25a60c2c 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/AssistClipListRecyclerView.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/edit/sidemenu/AssistClipListRecyclerView.java @@ -1,4 +1,4 @@ -package com.stardust.scriptdroid.ui; +package com.stardust.scriptdroid.ui.edit.sidemenu; import android.bug.WrapContentLinearLayoutManager; import android.content.Context; @@ -11,9 +11,9 @@ import android.view.ViewGroup; import android.widget.TextView; import com.stardust.scriptdroid.R; -import com.stardust.scriptdroid.droid.assist.BoundsAssistClipList; -import com.stardust.scriptdroid.droid.assist.SharedPrefBoundsAssistClipList; -import com.stardust.scriptdroid.widget.ExpandableRecyclerView; +import com.stardust.scriptdroid.bounds_assist.BoundsAssistClipList; +import com.stardust.scriptdroid.bounds_assist.SharedPrefBoundsAssistClipList; +import com.stardust.widget.ExpandableRecyclerView; /** * Created by Stardust on 2017/2/4. diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/EditSideMenuFragment.java b/app/src/main/java/com/stardust/scriptdroid/ui/edit/sidemenu/EditSideMenuFragment.java similarity index 81% rename from app/src/main/java/com/stardust/scriptdroid/ui/EditSideMenuFragment.java rename to app/src/main/java/com/stardust/scriptdroid/ui/edit/sidemenu/EditSideMenuFragment.java index 53de771e..58b8a9ab 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/EditSideMenuFragment.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/edit/sidemenu/EditSideMenuFragment.java @@ -1,4 +1,4 @@ -package com.stardust.scriptdroid.ui; +package com.stardust.scriptdroid.ui.edit.sidemenu; import android.content.Intent; import android.os.Bundle; @@ -10,14 +10,15 @@ import android.view.View; import android.view.ViewGroup; import com.stardust.scriptdroid.App; -import com.stardust.scriptdroid.DocumentActivity; +import com.stardust.scriptdroid.ui.help.DocumentActivity; import com.stardust.scriptdroid.R; -import com.stardust.scriptdroid.droid.ConsoleActivity; -import com.stardust.scriptdroid.droid.assist.BoundsAssistant; +import com.stardust.scriptdroid.ui.console.ConsoleActivity; +import com.stardust.scriptdroid.bounds_assist.BoundsAssistant; +import com.stardust.scriptdroid.external.notification.bounds_assist.BoundsAssistSwitchNotification; import com.stardust.view.ViewBinder; import com.stardust.view.ViewBinding; -import static com.stardust.scriptdroid.ui.AssistModeSwitchNotification.KEY_ASSIST_MODE_NOTIFICATION; +import static com.stardust.scriptdroid.external.notification.bounds_assist.BoundsAssistSwitchNotification.KEY_BOUNDS_ASSIST_SWITCH_NOTIFICATION_ENABLE; /** * Created by Stardust on 2017/2/4. @@ -72,14 +73,14 @@ public class EditSideMenuFragment extends com.stardust.app.Fragment { private void syncSwitchState() { mAssistServiceSwitch.setChecked(BoundsAssistant.isAssistModeEnable()); - mAssistServiceNotificationSwitch.setChecked(AssistModeSwitchNotification.isEnable()); + mAssistServiceNotificationSwitch.setChecked(BoundsAssistSwitchNotification.isEnable()); } private void setUpSwitchCompat() { mAssistServiceSwitch = $(R.id.sw_assist_service); mAssistServiceNotificationSwitch = $(R.id.sw_assist_service_notification); - App.getStateObserver().register(BoundsAssistant.KEY_ASSIST_MODE_ENABLE, mAssistServiceSwitch); - App.getStateObserver().register(KEY_ASSIST_MODE_NOTIFICATION, mAssistServiceNotificationSwitch); + App.getStateObserver().register(BoundsAssistant.KEY_BOUNDS_ASSIST_ENABLE, mAssistServiceSwitch); + App.getStateObserver().register(KEY_BOUNDS_ASSIST_SWITCH_NOTIFICATION_ENABLE, mAssistServiceNotificationSwitch); } @ViewBinding.Click(R.id.syntax_and_api) @@ -104,7 +105,7 @@ public class EditSideMenuFragment extends com.stardust.app.Fragment { @ViewBinding.Check(R.id.sw_assist_service_notification) private void setAssistServiceNotificationEnable(boolean enable) { - AssistModeSwitchNotification.setEnable(enable); + BoundsAssistSwitchNotification.setEnable(enable); } @ViewBinding.Click(R.id.assist_service_notification) diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/FunctionListRecyclerView.java b/app/src/main/java/com/stardust/scriptdroid/ui/edit/sidemenu/FunctionListRecyclerView.java similarity index 97% rename from app/src/main/java/com/stardust/scriptdroid/ui/FunctionListRecyclerView.java rename to app/src/main/java/com/stardust/scriptdroid/ui/edit/sidemenu/FunctionListRecyclerView.java index d205dadd..b54d1828 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/FunctionListRecyclerView.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/edit/sidemenu/FunctionListRecyclerView.java @@ -1,4 +1,4 @@ -package com.stardust.scriptdroid.ui; +package com.stardust.scriptdroid.ui.edit.sidemenu; import android.bug.WrapContentLinearLayoutManager; import android.content.Context; @@ -13,7 +13,7 @@ import android.widget.TextView; import com.stardust.scriptdroid.App; import com.stardust.scriptdroid.R; import com.stardust.scriptdroid.file.FileUtils; -import com.stardust.scriptdroid.widget.ExpandableRecyclerView; +import com.stardust.widget.ExpandableRecyclerView; import java.text.Collator; import java.util.ArrayList; diff --git a/app/src/main/java/com/stardust/scriptdroid/ErrorReportActivity.java b/app/src/main/java/com/stardust/scriptdroid/ui/error/ErrorReportActivity.java similarity index 97% rename from app/src/main/java/com/stardust/scriptdroid/ErrorReportActivity.java rename to app/src/main/java/com/stardust/scriptdroid/ui/error/ErrorReportActivity.java index f2344df9..ef011c8b 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ErrorReportActivity.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/error/ErrorReportActivity.java @@ -1,4 +1,4 @@ -package com.stardust.scriptdroid; +package com.stardust.scriptdroid.ui.error; import android.content.ClipData; import android.content.ClipboardManager; @@ -13,6 +13,8 @@ import android.widget.Toast; import com.afollestad.materialdialogs.DialogAction; import com.afollestad.materialdialogs.MaterialDialog; +import com.stardust.scriptdroid.ui.BaseActivity; +import com.stardust.scriptdroid.R; import java.util.Timer; import java.util.TimerTask; diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/error/IssueReportActivity.java b/app/src/main/java/com/stardust/scriptdroid/ui/error/IssueReportActivity.java new file mode 100644 index 00000000..f7c90523 --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/ui/error/IssueReportActivity.java @@ -0,0 +1,131 @@ +package com.stardust.scriptdroid.ui.error; + +import android.os.Bundle; +import android.support.design.widget.FloatingActionButton; +import android.support.v7.widget.Toolbar; +import android.view.View; +import android.widget.EditText; +import android.widget.Toast; + +import com.heinrichreimersoftware.androidissuereporter.IssueReporterActivity; +import com.heinrichreimersoftware.androidissuereporter.model.github.GithubTarget; +import com.stardust.scriptdroid.R; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * Created by Stardust on 2017/2/13. + */ + +public class IssueReportActivity extends IssueReporterActivity { + + + private boolean mCrash = false; + private Method mReportIssue, mValidateInput; + private boolean mReportFailed = false; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + handleIntent(); + setUpToobar(); + hookSendClick(); + } + + private void hookSendClick() { + FloatingActionButton send = (FloatingActionButton) this.findViewById(com.heinrichreimersoftware.androidissuereporter.R.id.air_buttonSend); + send.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + try { + reportIssue(); + } catch (Exception e) { + mReportFailed = true; + e.printStackTrace(); + finish(); + } + } + }); + } + + private void setUpToobar() { + getSupportActionBar().setTitle(R.string.text_issue_report); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + Toolbar toolbar = (Toolbar) findViewById(R.id.air_toolbar); + toolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); + } + + private void handleIntent() { + 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); + mCrash = true; + } + } + + private boolean validateInput() { + if (mValidateInput == null) { + try { + mValidateInput = IssueReporterActivity.class.getDeclaredMethod("validateInput"); + mValidateInput.setAccessible(true); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } + } + try { + return mValidateInput != null && (Boolean) mValidateInput.invoke(this); + } catch (IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + return false; + } + + private void reportIssue() { + if (mReportIssue == null) { + try { + mReportIssue = IssueReporterActivity.class.getDeclaredMethod("reportIssue"); + mReportIssue.setAccessible(true); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } + } + try { + mReportIssue.invoke(this); + } catch (IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + } + + @Override + public void finish() { + if (mCrash) { + if (!mReportFailed) { + Toast.makeText(IssueReportActivity.this, R.string.text_report_succeed, Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(IssueReportActivity.this, R.string.text_report_fail, Toast.LENGTH_SHORT).show(); + } + finishAffinity(); + + } else { + super.finish(); + } + } + + @Override + protected GithubTarget getTarget() { + return new GithubTarget("hyb1996", "NoRootScriptDroid"); + } + + @Override + protected String getGuestToken() { + return "f32d789662645640ff22e240b80f5d76117181a1"; + } + +} diff --git a/app/src/main/java/com/stardust/scriptdroid/DocumentActivity.java b/app/src/main/java/com/stardust/scriptdroid/ui/help/DocumentActivity.java similarity index 88% rename from app/src/main/java/com/stardust/scriptdroid/DocumentActivity.java rename to app/src/main/java/com/stardust/scriptdroid/ui/help/DocumentActivity.java index 11162c53..d8ce9ad2 100644 --- a/app/src/main/java/com/stardust/scriptdroid/DocumentActivity.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/help/DocumentActivity.java @@ -1,11 +1,13 @@ -package com.stardust.scriptdroid; +package com.stardust.scriptdroid.ui.help; import android.os.Bundle; import android.support.v7.widget.Toolbar; import android.view.View; +import com.stardust.scriptdroid.ui.BaseActivity; +import com.stardust.scriptdroid.R; import com.stardust.scriptdroid.file.FileUtils; -import com.stardust.view.MarkdownView; +import com.stardust.widget.MarkdownView; /** * Created by Stardust on 2017/2/1. diff --git a/app/src/main/java/com/stardust/scriptdroid/MainActivity.java b/app/src/main/java/com/stardust/scriptdroid/ui/main/MainActivity.java similarity index 68% rename from app/src/main/java/com/stardust/scriptdroid/MainActivity.java rename to app/src/main/java/com/stardust/scriptdroid/ui/main/MainActivity.java index 5e763ef2..439d7cbf 100644 --- a/app/src/main/java/com/stardust/scriptdroid/MainActivity.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/main/MainActivity.java @@ -1,8 +1,10 @@ -package com.stardust.scriptdroid; +package com.stardust.scriptdroid.ui.main; import android.Manifest; import android.annotation.SuppressLint; import android.content.BroadcastReceiver; +import android.content.ClipData; +import android.content.ClipboardManager; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -16,32 +18,41 @@ import android.support.v7.widget.Toolbar; import android.text.InputType; import android.view.View; import android.widget.TextView; +import android.widget.Toast; import com.afollestad.materialdialogs.DialogAction; import com.afollestad.materialdialogs.MaterialDialog; import com.afollestad.materialdialogs.folderselector.FileChooserDialog; import com.stardust.app.NotRemindAgainDialog; -import com.stardust.scriptdroid.droid.runtime.action.ActionPerformService; +import com.stardust.scriptdroid.BuildConfig; +import com.stardust.scriptdroid.R; +import com.stardust.scriptdroid.droid.runtime.action.ActionPerformAccessibilityDelegate; import com.stardust.scriptdroid.droid.script.file.ScriptFile; import com.stardust.scriptdroid.droid.script.file.ScriptFileList; import com.stardust.scriptdroid.droid.script.file.SharedPrefScriptFileList; +import com.stardust.scriptdroid.external.notification.record.ActionRecordSwitchNotification; import com.stardust.scriptdroid.file.FileUtils; -import com.stardust.scriptdroid.file.SampleFileTool; +import com.stardust.scriptdroid.file.SampleFileManager; +import com.stardust.scriptdroid.service.AccessibilityWatchDogService; import com.stardust.scriptdroid.tool.BackPressedHandler; -import com.stardust.scriptdroid.ui.ScriptFileOperation; -import com.stardust.scriptdroid.ui.ScriptListRecyclerView; -import com.stardust.scriptdroid.ui.SlideMenuFragment; -import com.stardust.scriptdroid.ui.SlidingUpPanel; +import com.stardust.scriptdroid.ui.BaseActivity; +import com.stardust.scriptdroid.ui.main.operation.ScriptFileOperation; +import com.stardust.scriptdroid.ui.settings.SettingsActivity; import com.stardust.view.ViewBinder; import com.stardust.view.ViewBinding; import com.stardust.view.accessibility.AccessibilityServiceUtils; +import com.stardust.widget.SlidingUpPanel; import java.io.File; public class MainActivity extends BaseActivity implements FileChooserDialog.FileCallback { + private static final String EXTRA_ACTION = "EXTRA_ACTION"; + public static final String ACTION_NOTIFY_SCRIPT_LIST_CHANGE = "ACTION_NOTIFY_SCRIPT_LIST_CHANGE"; + private static final String ACTION_ON_ACTION_RECORD_STOPPED = "ACTION_ON_ACTION_RECORD_STOPPED"; + private static final String ARGUMENT_SCRIPT = "ARGUMENT_SCRIPT"; private SlidingUpPanel mAddFilePanel; private ScriptListRecyclerView mScriptListRecyclerView; @@ -55,6 +66,7 @@ public class MainActivity extends BaseActivity implements FileChooserDialog.File setUpUI(); checkPermissions(); registerReceivers(); + handleIntent(getIntent()); } private void registerReceivers() { @@ -68,7 +80,7 @@ public class MainActivity extends BaseActivity implements FileChooserDialog.File } private void goToAccessibilityPermissionSettingIfDisabled() { - if (!AccessibilityServiceUtils.isAccessibilityServiceEnabled(this, ActionPerformService.class)) { + if (!AccessibilityServiceUtils.isAccessibilityServiceEnabled(this, ActionPerformAccessibilityDelegate.class)) { new NotRemindAgainDialog.Builder(this, "goToAccessibilityPermissionSettingIfDisabled") .title(R.string.text_alert) .content(R.string.explain_accessibility_permission) @@ -142,19 +154,29 @@ public class MainActivity extends BaseActivity implements FileChooserDialog.File @ViewBinding.Click(R.id.create_new_file) private void createScriptFile() { + createScriptFileForScript(null); + } + + + private void createScriptFileForScript(final String script) { new MaterialDialog.Builder(this).title(R.string.text_name) .inputType(InputType.TYPE_CLASS_TEXT) .input(getString(R.string.text_please_input_name), "", new MaterialDialog.InputCallback() { @Override public void onInput(@NonNull MaterialDialog dialog, CharSequence input) { String path = ScriptFile.DEFAULT_FOLDER + input + ".js"; - MainActivity.this.createScriptFile(input.toString(), path); + MainActivity.this.createScriptFile(input.toString(), path, script); } }).show(); } - private void createScriptFile(String name, String path) { + private void createScriptFile(String name, String path, String script) { if (FileUtils.createFileIfNotExists(path)) { + if (script != null) { + if (!FileUtils.writeString(path, script)) { + Snackbar.make(mDrawerLayout, R.string.text_file_write_fail, Snackbar.LENGTH_LONG).show(); + } + } addScriptFile(name, path); new ScriptFileOperation.Edit().operate(mScriptListRecyclerView, mScriptFileList, mScriptFileList.size() - 1); } else { @@ -170,6 +192,16 @@ public class MainActivity extends BaseActivity implements FileChooserDialog.File .show(); } + @ViewBinding.Click(R.id.record) + private void startScriptRecord() { + if (AccessibilityWatchDogService.getInstance() == null) { + Snackbar.make(mDrawerLayout, R.string.text_need_enable_accessibility_service, Snackbar.LENGTH_SHORT).show(); + return; + } + ActionRecordSwitchNotification.showOrUpdateNotification(); + Snackbar.make(mDrawerLayout, R.string.hint_start_record, Snackbar.LENGTH_SHORT).show(); + } + @ViewBinding.Click(R.id.setting) private void startSettingActivity() { startActivity(new Intent(this, SettingsActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); @@ -184,7 +216,7 @@ public class MainActivity extends BaseActivity implements FileChooserDialog.File public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if (requestCode == PERMISSION_REQUEST_CODE && grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - SampleFileTool.getInstance().copySampleScriptFileIfNeeded(); + SampleFileManager.getInstance().copySampleScriptFileIfNeeded(); mScriptListRecyclerView.getAdapter().notifyDataSetChanged(); } } @@ -194,6 +226,42 @@ public class MainActivity extends BaseActivity implements FileChooserDialog.File addScriptFile(file.getPath()); } + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + handleIntent(intent); + } + + private void handleIntent(Intent intent) { + String action = intent.getStringExtra(EXTRA_ACTION); + if (action == null) + return; + switch (action) { + case ACTION_ON_ACTION_RECORD_STOPPED: + handleRecordedScript(intent.getStringExtra(ARGUMENT_SCRIPT)); + break; + } + } + + private void handleRecordedScript(final String script) { + new MaterialDialog.Builder(this) + .title(R.string.text_recorded) + .items(getString(R.string.text_new_file), getString(R.string.text_copy_to_clip)) + .itemsCallback(new MaterialDialog.ListCallback() { + @Override + public void onSelection(MaterialDialog dialog, View itemView, int position, CharSequence text) { + if (position == 0) { + createScriptFileForScript(script); + } else { + ((ClipboardManager) getSystemService(CLIPBOARD_SERVICE)) + .setPrimaryClip(ClipData.newPlainText("script", script)); + Toast.makeText(MainActivity.this, R.string.text_already_copy_to_clip, Toast.LENGTH_SHORT).show(); + } + } + }) + .show(); + + } private BackPressedHandler mBackPressedHandler = new BackPressedHandler.DoublePressExit(this); @@ -214,6 +282,14 @@ public class MainActivity extends BaseActivity implements FileChooserDialog.File unregisterReceiver(mReceiver); } + public static void onActionRecordStopped(Context context, String script) { + Intent intent = new Intent(context, MainActivity.class) + .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP) + .putExtra(EXTRA_ACTION, ACTION_ON_ACTION_RECORD_STOPPED) + .putExtra(ARGUMENT_SCRIPT, script); + context.startActivity(intent); + } + private class Receiver extends BroadcastReceiver { @Override diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/ScriptListRecyclerView.java b/app/src/main/java/com/stardust/scriptdroid/ui/main/ScriptListRecyclerView.java similarity index 95% rename from app/src/main/java/com/stardust/scriptdroid/ui/ScriptListRecyclerView.java rename to app/src/main/java/com/stardust/scriptdroid/ui/main/ScriptListRecyclerView.java index 1be60a6e..160c68b4 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/ScriptListRecyclerView.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/main/ScriptListRecyclerView.java @@ -1,4 +1,4 @@ -package com.stardust.scriptdroid.ui; +package com.stardust.scriptdroid.ui.main; import android.content.Context; import android.os.Environment; @@ -16,11 +16,13 @@ import com.afollestad.materialdialogs.MaterialDialog; 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.ui.main.operation.ScriptFileOperation; +import com.stardust.scriptdroid.ui.main.operation.ScriptFileOperationPopupMenu; import com.stardust.scriptdroid.tool.ClassTool; import static com.stardust.scriptdroid.tool.ViewTool.$; -import static com.stardust.scriptdroid.ui.ScriptFileOperation.*; +import static com.stardust.scriptdroid.ui.main.operation.ScriptFileOperation.*; /** * Created by Stardust on 2017/1/23. diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/SlideMenuFragment.java b/app/src/main/java/com/stardust/scriptdroid/ui/main/SlideMenuFragment.java similarity index 77% rename from app/src/main/java/com/stardust/scriptdroid/ui/SlideMenuFragment.java rename to app/src/main/java/com/stardust/scriptdroid/ui/main/SlideMenuFragment.java index 59a7ae86..f3a5a1cd 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/SlideMenuFragment.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/main/SlideMenuFragment.java @@ -1,4 +1,4 @@ -package com.stardust.scriptdroid.ui; +package com.stardust.scriptdroid.ui.main; import android.content.Intent; import android.os.Bundle; @@ -12,17 +12,18 @@ import android.view.ViewGroup; import com.stardust.app.Fragment; import com.stardust.scriptdroid.App; -import com.stardust.scriptdroid.DocumentActivity; import com.stardust.scriptdroid.R; -import com.stardust.scriptdroid.droid.ConsoleActivity; +import com.stardust.scriptdroid.bounds_assist.BoundsAssistant; import com.stardust.scriptdroid.droid.Droid; -import com.stardust.scriptdroid.droid.assist.BoundsAssistant; -import com.stardust.scriptdroid.droid.runtime.action.ActionPerformService; +import com.stardust.scriptdroid.external.notification.bounds_assist.BoundsAssistSwitchNotification; +import com.stardust.scriptdroid.service.AccessibilityWatchDogService; +import com.stardust.scriptdroid.ui.console.ConsoleActivity; +import com.stardust.scriptdroid.ui.help.DocumentActivity; import com.stardust.view.ViewBinder; import com.stardust.view.ViewBinding; import com.stardust.view.accessibility.AccessibilityServiceUtils; -import static com.stardust.scriptdroid.ui.AssistModeSwitchNotification.KEY_ASSIST_MODE_NOTIFICATION; +import static com.stardust.scriptdroid.external.notification.bounds_assist.BoundsAssistSwitchNotification.KEY_BOUNDS_ASSIST_SWITCH_NOTIFICATION_ENABLE; /** * Created by Stardust on 2017/1/30. @@ -59,19 +60,19 @@ public class SlideMenuFragment extends Fragment { mAutoOperateServiceSwitch.postDelayed(new Runnable() { @Override public void run() { - mAutoOperateServiceSwitch.setChecked(ActionPerformService.isEnable()); + mAutoOperateServiceSwitch.setChecked(AccessibilityWatchDogService.isEnable()); } }, 450); mAssistServiceSwitch.setChecked(BoundsAssistant.isAssistModeEnable()); - mAssistServiceNotificationSwitch.setChecked(AssistModeSwitchNotification.isEnable()); + mAssistServiceNotificationSwitch.setChecked(BoundsAssistSwitchNotification.isEnable()); } private void setUpSwitchCompat() { mAutoOperateServiceSwitch = $(R.id.sw_auto_operate_service); mAssistServiceSwitch = $(R.id.sw_assist_service); mAssistServiceNotificationSwitch = $(R.id.sw_assist_service_notification); - App.getStateObserver().register(BoundsAssistant.KEY_ASSIST_MODE_ENABLE, mAssistServiceSwitch); - App.getStateObserver().register(KEY_ASSIST_MODE_NOTIFICATION, mAssistServiceNotificationSwitch); + App.getStateObserver().register(BoundsAssistant.KEY_BOUNDS_ASSIST_ENABLE, mAssistServiceSwitch); + App.getStateObserver().register(KEY_BOUNDS_ASSIST_SWITCH_NOTIFICATION_ENABLE, mAssistServiceNotificationSwitch); } @@ -92,10 +93,10 @@ public class SlideMenuFragment extends Fragment { @ViewBinding.Check(R.id.sw_auto_operate_service) private void setAutoOperateServiceEnable(boolean enable) { - if (enable && !ActionPerformService.isEnable()) { + if (enable && !AccessibilityWatchDogService.isEnable()) { AccessibilityServiceUtils.goToAccessibilitySetting(getContext()); - } else if (!enable && ActionPerformService.isEnable()) { - ActionPerformService.disable(); + } else if (!enable && AccessibilityWatchDogService.isEnable()) { + AccessibilityWatchDogService.disable(); } } @@ -111,7 +112,7 @@ public class SlideMenuFragment extends Fragment { @ViewBinding.Check(R.id.sw_assist_service_notification) private void setAssistServiceNotificationEnable(boolean enable) { - AssistModeSwitchNotification.setEnable(enable); + BoundsAssistSwitchNotification.setEnable(enable); } @ViewBinding.Click(R.id.assist_service_notification) diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/ScriptFileOperation.java b/app/src/main/java/com/stardust/scriptdroid/ui/main/operation/ScriptFileOperation.java similarity index 95% rename from app/src/main/java/com/stardust/scriptdroid/ui/ScriptFileOperation.java rename to app/src/main/java/com/stardust/scriptdroid/ui/main/operation/ScriptFileOperation.java index 6b8aa56d..906e64ed 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/ScriptFileOperation.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/main/operation/ScriptFileOperation.java @@ -1,4 +1,4 @@ -package com.stardust.scriptdroid.ui; +package com.stardust.scriptdroid.ui.main.operation; import android.content.Context; import android.content.Intent; @@ -8,12 +8,13 @@ import android.support.design.widget.Snackbar; import com.afollestad.materialdialogs.MaterialDialog; import com.stardust.scriptdroid.App; -import com.stardust.scriptdroid.EditActivity; +import com.stardust.scriptdroid.ui.edit.EditActivity; import com.stardust.scriptdroid.R; -import com.stardust.scriptdroid.ShortcutActivity; +import com.stardust.scriptdroid.external.shortcut.ShortcutActivity; import com.stardust.scriptdroid.droid.script.file.ScriptFile; import com.stardust.scriptdroid.droid.script.file.ScriptFileList; -import com.stardust.scriptdroid.shortcut.Shortcut; +import com.stardust.scriptdroid.external.shortcut.Shortcut; +import com.stardust.scriptdroid.ui.main.ScriptListRecyclerView; import java.util.ArrayList; import java.util.List; diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/ScriptFileOperationPopupMenu.java b/app/src/main/java/com/stardust/scriptdroid/ui/main/operation/ScriptFileOperationPopupMenu.java similarity index 98% rename from app/src/main/java/com/stardust/scriptdroid/ui/ScriptFileOperationPopupMenu.java rename to app/src/main/java/com/stardust/scriptdroid/ui/main/operation/ScriptFileOperationPopupMenu.java index 5a180705..95d8ec53 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/ScriptFileOperationPopupMenu.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/main/operation/ScriptFileOperationPopupMenu.java @@ -1,4 +1,4 @@ -package com.stardust.scriptdroid.ui; +package com.stardust.scriptdroid.ui.main.operation; import android.content.Context; import android.graphics.drawable.ColorDrawable; diff --git a/app/src/main/java/com/stardust/scriptdroid/AboutActivity.java b/app/src/main/java/com/stardust/scriptdroid/ui/settings/AboutActivity.java similarity index 79% rename from app/src/main/java/com/stardust/scriptdroid/AboutActivity.java rename to app/src/main/java/com/stardust/scriptdroid/ui/settings/AboutActivity.java index b689292f..abee66e3 100644 --- a/app/src/main/java/com/stardust/scriptdroid/AboutActivity.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/settings/AboutActivity.java @@ -1,16 +1,21 @@ -package com.stardust.scriptdroid; +package com.stardust.scriptdroid.ui.settings; import android.annotation.SuppressLint; import android.content.ClipData; import android.content.ClipboardManager; import android.os.Bundle; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v7.widget.Toolbar; import android.view.View; import android.widget.TextView; import android.widget.Toast; +import com.afollestad.materialdialogs.DialogAction; import com.afollestad.materialdialogs.MaterialDialog; +import com.stardust.scriptdroid.ui.BaseActivity; +import com.stardust.scriptdroid.BuildConfig; +import com.stardust.scriptdroid.R; import com.stardust.scriptdroid.tool.IntentTool; import com.stardust.view.ViewBinder; import com.stardust.view.ViewBinding; @@ -23,6 +28,8 @@ import moe.feng.alipay.zerosdk.AlipayZeroSdk; public class AboutActivity extends BaseActivity { + private int mLolClickCount = 0; + @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -61,6 +68,7 @@ public class AboutActivity extends BaseActivity { @ViewBinding.Click(R.id.qq) private void openQQToChatWithMe() { + Toast.makeText(this, R.string.text_qq_group_id_copied, Toast.LENGTH_SHORT).show(); String qq = getString(R.string.qq); IntentTool.goToQQ(this, qq); } @@ -99,7 +107,19 @@ public class AboutActivity extends BaseActivity { @ViewBinding.Click(R.id.icon) private void lol() { + mLolClickCount++; Toast.makeText(this, R.string.text_lll, Toast.LENGTH_LONG).show(); + if (mLolClickCount >= 5) { + new MaterialDialog.Builder(this) + .title("Crash Test") + .positiveText("Crash") + .onPositive(new MaterialDialog.SingleButtonCallback() { + @Override + public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) { + throw new RuntimeException("Crash Test"); + } + }).show(); + } } @ViewBinding.Click(R.id.developer) diff --git a/app/src/main/java/com/stardust/scriptdroid/SettingsActivity.java b/app/src/main/java/com/stardust/scriptdroid/ui/settings/SettingsActivity.java similarity index 74% rename from app/src/main/java/com/stardust/scriptdroid/SettingsActivity.java rename to app/src/main/java/com/stardust/scriptdroid/ui/settings/SettingsActivity.java index 9ed0a72a..6d48b335 100644 --- a/app/src/main/java/com/stardust/scriptdroid/SettingsActivity.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/settings/SettingsActivity.java @@ -1,5 +1,7 @@ -package com.stardust.scriptdroid; +package com.stardust.scriptdroid.ui.settings; +import android.content.ClipData; +import android.content.ClipboardManager; import android.content.Intent; import android.os.Bundle; import android.preference.Preference; @@ -9,7 +11,11 @@ import android.support.v7.widget.Toolbar; import android.view.View; import android.widget.Toast; -import com.stardust.scriptdroid.file.SampleFileTool; +import com.stardust.scriptdroid.R; +import com.stardust.scriptdroid.file.SampleFileManager; +import com.stardust.scriptdroid.ui.BaseActivity; +import com.stardust.scriptdroid.ui.error.IssueReportActivity; +import com.stardust.scriptdroid.ui.main.MainActivity; import com.stardust.util.MapEntries; import java.util.Map; @@ -66,7 +72,7 @@ public class SettingsActivity extends BaseActivity { .entry(getString(R.string.text_re_import_samples), new Runnable() { @Override public void run() { - int failCount = SampleFileTool.getInstance().copySampleScriptFile(); + int failCount = SampleFileManager.getInstance().copySampleScriptFile(); if (failCount <= 0) { Toast.makeText(getActivity(), R.string.text_re_import_succeed, Toast.LENGTH_SHORT).show(); notifyScriptListChanged(); @@ -74,6 +80,19 @@ public class SettingsActivity extends BaseActivity { Toast.makeText(getActivity(), R.string.text_fail, Toast.LENGTH_SHORT).show(); } }) + .entry(getString(R.string.text_issue_report), new Runnable() { + @Override + public void run() { + startActivity(new Intent(getActivity(), IssueReportActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); + } + }) + .entry(getString(R.string.text_join_qq_group), new Runnable() { + @Override + public void run() { + ((ClipboardManager) getActivity().getSystemService(CLIPBOARD_SERVICE)).setPrimaryClip(ClipData.newPlainText("qq", "556928653")); + Toast.makeText(getActivity(), R.string.text_qq_group_id_copied, Toast.LENGTH_SHORT).show(); + } + }) .entry(getString(R.string.text_about), new Runnable() { @Override public void run() { diff --git a/app/src/main/java/com/stardust/util/StateObserver.java b/app/src/main/java/com/stardust/util/StateObserver.java index eb60f56b..35aa469a 100644 --- a/app/src/main/java/com/stardust/util/StateObserver.java +++ b/app/src/main/java/com/stardust/util/StateObserver.java @@ -15,30 +15,18 @@ import java.util.concurrent.CopyOnWriteArrayList; public class StateObserver { - public interface OnStateChangedListener { + public interface OnStateChangedListener { - void onStateChanged(T newState); + void onStateChanged(boolean newState); - void initState(T state); + void initState(boolean state); } - public static abstract class SimpleOnStateChangedListener implements OnStateChangedListener { + public static abstract class SimpleOnStateChangedListener implements OnStateChangedListener { @Override - public void initState(T state) { - onStateChanged(state); - } - } - - public interface OnBooleanStateChangedListener extends OnStateChangedListener { - - } - - public static abstract class SimpleOnBooleanStateChangedListener implements OnBooleanStateChangedListener { - - @Override - public void initState(Boolean state) { + public void initState(boolean state) { onStateChanged(state); } } @@ -53,9 +41,9 @@ public class StateObserver { public void register(final String key, SwitchCompat switchCompat) { final WeakReference switchCompatWeakReference = new WeakReference<>(switchCompat); - register(key, new SimpleOnBooleanStateChangedListener() { + register(key, new SimpleOnStateChangedListener() { @Override - public void onStateChanged(Boolean newState) { + public void onStateChanged(boolean newState) { if (switchCompatWeakReference.get() != null) { switchCompatWeakReference.get().setChecked(newState); } else { @@ -65,10 +53,8 @@ public class StateObserver { }); } - public void register(String key, OnStateChangedListener listener) { - T initialState = readState(key, listener); - if (initialState != null) - listener.initState(initialState); + public void register(String key, OnStateChangedListener listener) { + initState(key, listener); synchronized (mKeyStateListenersMap) { List listeners = getListenerListOrCreateIfNotExists(key); listeners.add(listener); @@ -76,7 +62,7 @@ public class StateObserver { } - private void unregister(String key, OnStateChangedListener stateChangedListener) { + private void unregister(String key, OnStateChangedListener stateChangedListener) { synchronized (mKeyStateListenersMap) { List listeners = mKeyStateListenersMap.get(key); if (listeners == null) { @@ -86,15 +72,13 @@ public class StateObserver { } } - public void setState(String key, T state) { + public void setState(String key, boolean state) { synchronized (mKeyStateListenersMap) { List listeners = mKeyStateListenersMap.get(key); if (listeners == null || listeners.isEmpty()) return; - if (listeners.get(0) instanceof OnBooleanStateChangedListener) { - mSharedPreferences.edit().putBoolean(key, (Boolean) state).apply(); - notifyBooleanStateChanged(listeners, (Boolean) state); - } + mSharedPreferences.edit().putBoolean(key, state).apply(); + notifyBooleanStateChanged(listeners, state); } } @@ -104,12 +88,10 @@ public class StateObserver { } } - @SuppressWarnings("unchecked") - protected T readState(String key, OnStateChangedListener listener) { - if (listener instanceof OnBooleanStateChangedListener) { - return mSharedPreferences.contains(key) ? (T) Boolean.valueOf(mSharedPreferences.getBoolean(key, false)) : null; + private void initState(String key, OnStateChangedListener listener) { + if (mSharedPreferences.contains(key)) { + listener.initState(mSharedPreferences.getBoolean(key, false)); } - return null; } private List getListenerListOrCreateIfNotExists(String key) { diff --git a/app/src/main/java/com/stardust/util/function/ArrayOptional.java b/app/src/main/java/com/stardust/util/function/ArrayOptional.java deleted file mode 100644 index f0d74de6..00000000 --- a/app/src/main/java/com/stardust/util/function/ArrayOptional.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.stardust.util.function; - -/** - * Created by Stardust on 2017/1/24. - */ - -public class ArrayOptional { -} diff --git a/app/src/main/java/com/stardust/util/function/Domino.java b/app/src/main/java/com/stardust/util/function/Domino.java deleted file mode 100644 index a19c0c16..00000000 --- a/app/src/main/java/com/stardust/util/function/Domino.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.stardust.util.function; - -/** - * Created by Stardust on 2017/1/26. - */ - -public class Domino { -} diff --git a/app/src/main/java/com/stardust/util/function/FunctionTool.java b/app/src/main/java/com/stardust/util/function/FunctionTool.java deleted file mode 100644 index 914f3002..00000000 --- a/app/src/main/java/com/stardust/util/function/FunctionTool.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.stardust.util.function; - -import android.support.annotation.RequiresApi; - -import java.util.Optional; -import java.util.function.Consumer; - -/** - * Created by Stardust on 2017/1/24. - */ - -public class FunctionTool { - - -} diff --git a/app/src/main/java/com/stardust/util/function/ListTool.java b/app/src/main/java/com/stardust/util/function/ListTool.java deleted file mode 100644 index 6e311d04..00000000 --- a/app/src/main/java/com/stardust/util/function/ListTool.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.stardust.util.function; - -import java.util.ArrayList; -import java.util.List; - -/** - * Created by Stardust on 2017/1/26. - */ - -public class ListTool { - - @FunctionalInterface - public interface ChildSupplier { - T getChild(int i); - } - - public static List toList(ChildSupplier supplier, int size) { - ArrayList arrayList = new ArrayList(size); - for (int i = 0; i < size - 1; i++) { - arrayList.add(supplier.getChild(i)); - } - return arrayList; - } -} diff --git a/app/src/main/java/com/stardust/scriptdroid/widget/ExpandableRecyclerView.java b/app/src/main/java/com/stardust/widget/ExpandableRecyclerView.java similarity index 99% rename from app/src/main/java/com/stardust/scriptdroid/widget/ExpandableRecyclerView.java rename to app/src/main/java/com/stardust/widget/ExpandableRecyclerView.java index a2c5bcac..b8c130cc 100644 --- a/app/src/main/java/com/stardust/scriptdroid/widget/ExpandableRecyclerView.java +++ b/app/src/main/java/com/stardust/widget/ExpandableRecyclerView.java @@ -1,4 +1,4 @@ -package com.stardust.scriptdroid.widget; +package com.stardust.widget; import android.content.Context; import android.support.annotation.Nullable; diff --git a/app/src/main/java/com/stardust/view/MarkdownView.java b/app/src/main/java/com/stardust/widget/MarkdownView.java similarity index 98% rename from app/src/main/java/com/stardust/view/MarkdownView.java rename to app/src/main/java/com/stardust/widget/MarkdownView.java index bb94c9e0..83ab3222 100644 --- a/app/src/main/java/com/stardust/view/MarkdownView.java +++ b/app/src/main/java/com/stardust/widget/MarkdownView.java @@ -1,4 +1,4 @@ -package com.stardust.view; +package com.stardust.widget; import android.content.Context; import android.os.Build; diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/SlidingUpPanel.java b/app/src/main/java/com/stardust/widget/SlidingUpPanel.java similarity index 98% rename from app/src/main/java/com/stardust/scriptdroid/ui/SlidingUpPanel.java rename to app/src/main/java/com/stardust/widget/SlidingUpPanel.java index 60cb63e0..366efac0 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/SlidingUpPanel.java +++ b/app/src/main/java/com/stardust/widget/SlidingUpPanel.java @@ -1,4 +1,4 @@ -package com.stardust.scriptdroid.ui; +package com.stardust.widget; import android.annotation.TargetApi; import android.content.Context; diff --git a/app/src/main/java/com/stardust/scriptdroid/widget/ToolbarMenuItem.java b/app/src/main/java/com/stardust/widget/ToolbarMenuItem.java similarity index 98% rename from app/src/main/java/com/stardust/scriptdroid/widget/ToolbarMenuItem.java rename to app/src/main/java/com/stardust/widget/ToolbarMenuItem.java index d4cee21b..526d3c4a 100644 --- a/app/src/main/java/com/stardust/scriptdroid/widget/ToolbarMenuItem.java +++ b/app/src/main/java/com/stardust/widget/ToolbarMenuItem.java @@ -1,4 +1,4 @@ -package com.stardust.scriptdroid.widget; +package com.stardust.widget; import android.annotation.TargetApi; import android.content.Context; diff --git a/app/src/main/res/drawable/btn_selector.xml b/app/src/main/res/drawable/btn_selector.xml new file mode 100644 index 00000000..4522c99d --- /dev/null +++ b/app/src/main/res/drawable/btn_selector.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_pause_gray_48dp.png b/app/src/main/res/drawable/ic_pause_gray_48dp.png new file mode 100644 index 00000000..f4511e63 Binary files /dev/null and b/app/src/main/res/drawable/ic_pause_gray_48dp.png differ diff --git a/app/src/main/res/drawable/ic_pause_grey600_48dp.png b/app/src/main/res/drawable/ic_pause_grey600_48dp.png new file mode 100644 index 00000000..dc9d1740 Binary files /dev/null and b/app/src/main/res/drawable/ic_pause_grey600_48dp.png differ diff --git a/app/src/main/res/drawable/ic_play_arrow_black_48dp.png b/app/src/main/res/drawable/ic_play_arrow_black_48dp.png new file mode 100644 index 00000000..f208795f Binary files /dev/null and b/app/src/main/res/drawable/ic_play_arrow_black_48dp.png differ diff --git a/app/src/main/res/drawable/ic_play_arrow_gray_48dp.png b/app/src/main/res/drawable/ic_play_arrow_gray_48dp.png new file mode 100644 index 00000000..308ef810 Binary files /dev/null and b/app/src/main/res/drawable/ic_play_arrow_gray_48dp.png differ diff --git a/app/src/main/res/drawable/ic_play_arrow_grey600_48dp.png b/app/src/main/res/drawable/ic_play_arrow_grey600_48dp.png new file mode 100644 index 00000000..bcffe663 Binary files /dev/null and b/app/src/main/res/drawable/ic_play_arrow_grey600_48dp.png differ diff --git a/app/src/main/res/drawable/ic_stop_black_36dp.png b/app/src/main/res/drawable/ic_stop_black_36dp.png new file mode 100644 index 00000000..75f47c1b Binary files /dev/null and b/app/src/main/res/drawable/ic_stop_black_36dp.png differ diff --git a/app/src/main/res/drawable/ic_stop_grey600_48dp.png b/app/src/main/res/drawable/ic_stop_grey600_48dp.png new file mode 100644 index 00000000..e65afc8b Binary files /dev/null and b/app/src/main/res/drawable/ic_stop_grey600_48dp.png differ diff --git a/app/src/main/res/drawable/ic_stop_white_36pt.png b/app/src/main/res/drawable/ic_stop_white_36pt.png new file mode 100644 index 00000000..dfff26ce Binary files /dev/null and b/app/src/main/res/drawable/ic_stop_white_36pt.png differ diff --git a/app/src/main/res/drawable/ic_video_record.png b/app/src/main/res/drawable/ic_video_record.png new file mode 100644 index 00000000..7fa29e20 Binary files /dev/null and b/app/src/main/res/drawable/ic_video_record.png differ diff --git a/app/src/main/res/layout/activity_console.xml b/app/src/main/res/layout/activity_console.xml index 63f49626..ec382631 100644 --- a/app/src/main/res/layout/activity_console.xml +++ b/app/src/main/res/layout/activity_console.xml @@ -22,7 +22,7 @@ diff --git a/app/src/main/res/layout/activity_document.xml b/app/src/main/res/layout/activity_document.xml index d3588f4c..b7dd0018 100644 --- a/app/src/main/res/layout/activity_document.xml +++ b/app/src/main/res/layout/activity_document.xml @@ -26,7 +26,7 @@ - + tools:context=".ui.edit.EditActivity"> - - - - + tools:context=".ui.main.MainActivity"> - @@ -107,9 +107,35 @@ + + + + + + + + + - + diff --git a/app/src/main/res/layout/content_main.xml b/app/src/main/res/layout/content_main.xml index f7053878..b0b2123e 100644 --- a/app/src/main/res/layout/content_main.xml +++ b/app/src/main/res/layout/content_main.xml @@ -7,11 +7,11 @@ android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" - tools:context="com.stardust.scriptdroid.MainActivity" + tools:context=".ui.main.MainActivity" tools:showIn="@layout/activity_main"> - diff --git a/app/src/main/res/layout/fragment_edit_side_menu.xml b/app/src/main/res/layout/fragment_edit_side_menu.xml index cdf80b5d..43656582 100644 --- a/app/src/main/res/layout/fragment_edit_side_menu.xml +++ b/app/src/main/res/layout/fragment_edit_side_menu.xml @@ -116,12 +116,12 @@ - - diff --git a/app/src/main/res/layout/remote_views_record_switch.xml b/app/src/main/res/layout/remote_views_record_switch.xml new file mode 100644 index 00000000..0d06f376 --- /dev/null +++ b/app/src/main/res/layout/remote_views_record_switch.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/script_file_operation_popup_menu_content.xml b/app/src/main/res/layout/script_file_operation_popup_menu_content.xml index b7dff679..d5497aff 100644 --- a/app/src/main/res/layout/script_file_operation_popup_menu_content.xml +++ b/app/src/main/res/layout/script_file_operation_popup_menu_content.xml @@ -8,7 +8,7 @@ \ No newline at end of file diff --git a/app/src/main/res/menu/menu_main.xml b/app/src/main/res/menu/menu_main.xml index 158eefea..ae9a1e4a 100644 --- a/app/src/main/res/menu/menu_main.xml +++ b/app/src/main/res/menu/menu_main.xml @@ -1,6 +1,6 @@ + tools:context=".ui.main.MainActivity"> diff --git a/app/src/main/res/raw/document.md b/app/src/main/res/raw/document.md index bfc151c8..f0d6f222 100644 --- a/app/src/main/res/raw/document.md +++ b/app/src/main/res/raw/document.md @@ -25,6 +25,18 @@ * `notStopped` 若当前脚本处于运行状态时返回`true`, 否则返回`false`。对于某些循环, 例如`while(true)`,请用`while(notStopped())`代替,以免死循环造成的脚本无法正常停止。 * `isStoppd` 若当前脚本处于停止状态时返回`true`, 否则返回`false`。 * `shell(cmd, root=false)` 执行shell命令cmd, 其中参数root表示是否以root权限执行,默认为false。例如`shell("input keyevent 26", true); //锁屏`。 +* `getTexts()` 获取屏幕上的文字列表, 返回一个java.util.List。例如: + +``` +launchApp("微信"); +while(!click("通讯录")); +var texts = getTexts(); +for(var i = 0; i < texts.size(); i++){ + log(texts.get(i)); +} +openConsole(); +``` + ###四、全局变量 * `context` ApplicationContext,参见安卓[android.content.Context](https://developer.android.com/reference/android/content/Context.html) > 这里的context由于是ApplicationContext,是不可见的,不能用于dialog和其他UI相关。如果要显示弹窗或者视图,请启动UI模式(代码的第一行为`"ui";`既可)并使用activity代替。 diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml new file mode 100644 index 00000000..989696d8 --- /dev/null +++ b/app/src/main/res/values-zh/strings.xml @@ -0,0 +1,36 @@ + + 错误报告 + + 问题 + 登录 + + 标题 + 描述 + 设备信息 + + 使用Github账号发送 + 使用Email发送 + 匿名发送 + 用户名 + 密码 + 邮箱 + 联系邮箱 (选填) + + 请输入问题 + 请输入详细描述 + 请输入有效的Github用户名 + 请输入正确的密码 + 请输入邮箱 + + 正在上传到GitHub… + 无法发送错误报告 + 错误的用户名或密码 + 无效的access token. 请联系软件开发者. + Issues不可用,请联系软件开发者. + 未知错误 + OK + + 描述至少要 %d 个字. + 描述至少要 %d 个字. + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9687e2a5..e40a415b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -99,4 +99,20 @@ Bug Report 提交失败 提交成功 + 无法处理文件 + Crash + 问题反馈 + 录制脚本 + 在通知栏中开始录制 + 开始录制 + 停止录制 + 录制未开始 + 暂停录制 + 继续录制 + 录制结束 + 复制到剪贴板 + 文件写入失败 + 需要打开\"自动操作服务“才能录制脚本 + 加入QQ交流群 + 已复制群号到剪贴板 diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index b688da75..3090281e 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -11,6 +11,12 @@ + + + + diff --git a/app/src/test/java/com/stardust/scriptdroid/ExampleUnitTest.java b/app/src/test/java/com/stardust/scriptdroid/ExampleUnitTest.java index 86168640..18923ec6 100644 --- a/app/src/test/java/com/stardust/scriptdroid/ExampleUnitTest.java +++ b/app/src/test/java/com/stardust/scriptdroid/ExampleUnitTest.java @@ -2,6 +2,11 @@ package com.stardust.scriptdroid; import org.junit.Test; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + /** * Example local unit test, which will execute on the development machine (host). * @@ -9,7 +14,70 @@ import org.junit.Test; */ public class ExampleUnitTest { @Test - public void testStack() throws Exception { + public void testSync() throws Exception { + final Sync sync = new Sync(); + //sync.print(11); + add(sync, 11, 123); + //Thread.sleep(1); + sync.print(11); + add(sync, 11, 456); + sync.print(11); + } + private void add(final Sync sync, final int key, final int i) { + new Thread(new Runnable() { + @Override + public void run() { + sync.add(key, i); + } + }).start(); + } + + private static class Sync { + + private final Map> mMap = new TreeMap<>(); + + Sync() { + for (int i = 0; i < 10; i++) { + List list = new ArrayList<>(); + for (int j = 0; j < 10; j++) { + list.add(j * i); + } + mMap.put(i, list); + } + } + + public Sync add(int key, int i) { + synchronized (mMap) { + List list = ensureList(key); + list.add(i); + System.out.println("add:" + key + " " + i); + } + return this; + } + + private List ensureList(int key) { + List list = mMap.get(key); + if (list == null) { + list = new ArrayList<>(); + mMap.put(key, list); + } + return list; + } + + public void print(int key) { + synchronized (mMap) { + List list = mMap.get(key); + System.out.print(key + ":"); + if (list == null) { + System.out.print("null"); + } else { + for (Integer i : list) { + System.out.print(i + " "); + } + } + System.out.println(); + } + } } } \ No newline at end of file