add: LICENSE, ui mode

This commit is contained in:
hyb1996
2017-02-05 20:57:04 +08:00
parent 407066027e
commit 13142d14a7
52 changed files with 732 additions and 215 deletions

View File

@@ -76,6 +76,7 @@
<activity android:name=".AboutActivity"/>
<activity android:name=".SettingsActivity"/>
<activity android:name=".ErrorReportActivity"/>
<activity android:name=".droid.script.ScriptExecuteActivity"/>
<service android:name=".AssistModeSwitchService"/>

View File

@@ -19,21 +19,11 @@ var launchApp = function(appName){
droid.launchApp(appName);
}
var text = function(str){
return droid.text(str);
}
var bounds = function(left, top, right, bottom){
return droid.bounds(left, top, right, bottom);
}
function performAction(action, args){
if(args.length == 4){
return action(bounds(args[0], args[1], args[2], args[3]));
return action(droid.bounds(args[0], args[1], args[2], args[3]));
}else{
return action(text(args[0]));
return action(droid.text(args[0]));
}
}
@@ -49,17 +39,9 @@ var longClick = function(a, b, c, d){
}, arguments);
}
var scrollAllUp = function(){
droid.scrollAllUp();
}
var scrollAllDown = function(){
droid.scrollAllDown();
}
var scrollUp = function(a, b, c, d){
if(arguments.length == 0)
return scrollAllUp();
return droid.scrollAllUp();
return performAction(function(target){
return droid.scrollUp(target);
}, arguments);
@@ -67,7 +49,7 @@ var scrollUp = function(a, b, c, d){
var scrollDown = function(a, b, c, d){
if(arguments.length == 0)
return scrollAllDown();
return droid.scrollAllDown();
return performAction(function(target){
return droid.scrollDown(target);
}, arguments);
@@ -95,10 +77,6 @@ var editable = function(i){
return droid.editable(i);
}
var setText = function(target, str){
return droid.setText(target, str);
}
var input = function(a, b){
if(arguments.length == 1){
return droid.setText(editable(-1), a);
@@ -111,9 +89,11 @@ var sleep = function(millis){
droid.sleep(millis);
}
var isStopped = function(){
return droid.isStopped();
}
importClass("java.lang.Runnable");
var notStopped = function(){
return !isStopped();
}
var ui = function(action){
droid.ui(new Runnable(action));
}

View File

@@ -0,0 +1,22 @@
"ui";
importClass("android.widget.EditText");
importClass("android.widget.Button");
importClass("android.widget.LinearLayout");
importClass("android.view.View.OnClickListener");
importClass("android.content.Intent");
importClass("android.net.Uri");
var qq = new EditText(activity);
qq.setHint("请输入QQ号");
var btnOk = new Button(activity);
btnOk.setText("确定");
var container = new LinearLayout(activity);
container.addView(qq);
container.addView(btnOk);
activity.setContentView(container);
btnOk.setOnClickListener(new OnClickListener(function(view){
activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("mqqwpa://im/chat?chat_type=wpa&uin=" + qq.getText())));
activity.finish();
}));

View File

@@ -1,4 +0,0 @@
toast("大姐姐好")
for(var i = 0; i < 10; i++){
toast("大姐姐今年有" + i + "块钱~");
}

View File

@@ -0,0 +1,13 @@
launch("com.tencent.mobileqq");
toast("请打开一个聊天窗口");
toast("出现红包时将会自动拆开并关闭");
while(!isStopped()){
if(click("点击拆开")){
//拆开红包后尝试10次关闭红包页面
for(var i = 0; i < 10; i++){
sleep(300);
if(click("关闭"))
break;
}
}
}

View File

@@ -1,7 +1,17 @@
"ui";
importClass("com.afollestad.materialdialogs.MaterialDialog.Builder");
importClass("com.afollestad.materialdialogs.MaterialDialog.InputCallback");
importClass("android.content.DialogInterface.OnDismissListener");
new Builder(context)
.title("请输入算式")
.content("测试")
new Builder(activity)
.title("简单计算器")
.input("请输入算式", "1+1", new InputCallback(function(dialog, input){
eval("var ans = (" + input + ")");
toast(ans);
}))
.positiveText("计算")
.dismissListener(new OnDismissListener(function(dialog){
activity.finish();
}))
.show();

View File

@@ -28,7 +28,12 @@ public class NotRemindAgainDialog extends MaterialDialog {
private boolean mRemind;
public Builder(@NonNull Context context) {
this(context, null);
}
public Builder(Context context, String key) {
super(context);
mKeyRemind = key;
readRemindStatus();
checkBoxPrompt(context.getString(R.string.text_do_not_remind_again), false, new CompoundButton.OnCheckedChangeListener() {
@Override
@@ -52,12 +57,13 @@ public class NotRemindAgainDialog extends MaterialDialog {
}
private void readRemindStatus() {
generatePreferenceKey();
generatePreferenceKeyIfNeeded();
mRemind = PreferenceManager.getDefaultSharedPreferences(getContext()).getBoolean(mKeyRemind, true);
}
private void generatePreferenceKey() {
mKeyRemind = md5(TextUtils.join("", Thread.currentThread().getStackTrace()));
private void generatePreferenceKeyIfNeeded() {
if (mKeyRemind == null)
mKeyRemind = md5(TextUtils.join("", Thread.currentThread().getStackTrace()));
}
}
}

View File

@@ -1,6 +1,8 @@
package com.stardust.scriptdroid;
import android.app.Activity;
import android.app.Application;
import android.os.Bundle;
import android.preference.PreferenceManager;
import com.stardust.util.CrashHandler;
@@ -14,6 +16,7 @@ public class App extends Application {
private static App instance;
private static StateObserver stateObserver;
private static Activity currentActivity;
public static App getApp() {
return instance;
@@ -26,8 +29,69 @@ public class App extends Application {
public void onCreate() {
super.onCreate();
Thread.currentThread().setUncaughtExceptionHandler(new CrashHandler(ErrorReportActivity.class));
Thread.setDefaultUncaughtExceptionHandler(new CrashHandler(ErrorReportActivity.class));
instance = this;
stateObserver = new StateObserver(PreferenceManager.getDefaultSharedPreferences(this));
registerActivityLifecycleCallbacks(new SimpleActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
currentActivity = activity;
}
@Override
public void onActivityPaused(Activity activity) {
currentActivity = null;
}
@Override
public void onActivityResumed(Activity activity) {
currentActivity = activity;
}
});
}
public static Activity currentActivity() {
return currentActivity;
}
private static class SimpleActivityLifecycleCallbacks implements ActivityLifecycleCallbacks {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
}
}

View File

@@ -6,7 +6,7 @@ import android.content.Intent;
import android.os.IBinder;
import android.support.annotation.Nullable;
import com.stardust.scriptdroid.droid.assist.Assistant;
import com.stardust.scriptdroid.droid.assist.BoundsAssistant;
import static com.stardust.scriptdroid.ui.AssistModeSwitchNotification.KEY_ASSIST_MODE_NOTIFICATION;
@@ -15,10 +15,18 @@ import static com.stardust.scriptdroid.ui.AssistModeSwitchNotification.KEY_ASSIS
*/
public class AssistModeSwitchService extends Service {
private static final String EXTRA_INTENT_VALID = "intentValid";
private static final String EXTRA_ACTION = "action";
private static final int ACTION_TOGGLE_ASSIST_MODE = 1;
private static final int ACTION_CANCEL_ASSIST_MODE_NOTIFICATION = 2;
public static PendingIntent getStartIntent() {
Intent intent = new Intent(App.getApp(), AssistModeSwitchService.class)
.putExtra("intentValid", true)
.putExtra("switch", "assistMode");
.putExtra(EXTRA_INTENT_VALID, true)
.putExtra(EXTRA_ACTION, ACTION_TOGGLE_ASSIST_MODE);
return PendingIntent.getService(App.getApp(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
@@ -26,19 +34,23 @@ public class AssistModeSwitchService extends Service {
public int onStartCommand(Intent intent, int flags, int startId) {
boolean intentValid = intent.getBooleanExtra("intentValid", false);
if (intentValid) {
String action = intent.getStringExtra("switch");
if (action != null) {
if (action.equals("assistMode")) {
Assistant.setAssistModeEnable(!Assistant.isAssistModeEnable());
} else {
App.getStateObserver().setState(KEY_ASSIST_MODE_NOTIFICATION, false);
}
}
performAction(intent.getIntExtra(EXTRA_ACTION, 0));
}
stopSelf();
return super.onStartCommand(intent, flags, startId);
}
private void performAction(int action) {
switch (action) {
case ACTION_TOGGLE_ASSIST_MODE:
BoundsAssistant.setAssistModeEnable(!BoundsAssistant.isAssistModeEnable());
break;
case ACTION_CANCEL_ASSIST_MODE_NOTIFICATION:
App.getStateObserver().setState(KEY_ASSIST_MODE_NOTIFICATION, false);
break;
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
@@ -47,8 +59,8 @@ public class AssistModeSwitchService extends Service {
public static PendingIntent getDeletePendingIntent() {
Intent deleteIntent = new Intent(App.getApp(), AssistModeSwitchService.class)
.putExtra("intentValid", true)
.putExtra("switch", "assistModeNotification");
.putExtra(EXTRA_INTENT_VALID, true)
.putExtra(EXTRA_ACTION, ACTION_CANCEL_ASSIST_MODE_NOTIFICATION);
return PendingIntent.getService(App.getApp(), 0, deleteIntent, PendingIntent.FLAG_ONE_SHOT);
}
}

View File

@@ -19,7 +19,6 @@ 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.droid.Droid;
import com.stardust.scriptdroid.droid.runtime.DroidRuntime;
import com.stardust.scriptdroid.editor920.Editor920Activity;
import com.stardust.scriptdroid.ui.AssistClipListRecyclerView;
import com.stardust.scriptdroid.ui.EditSideMenuFragment;
@@ -58,7 +57,6 @@ public class EditActivity extends Editor920Activity {
public void onCreate(Bundle b) {
super.onCreate(b);
DroidRuntime.setContext(this);
handleIntent();
setUpUI();
setUpEditor();

View File

@@ -6,6 +6,8 @@ import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;
import com.afollestad.materialdialogs.DialogAction;
@@ -20,22 +22,29 @@ import java.util.TimerTask;
public class ErrorReportActivity extends BaseActivity {
private static final String TAG = "ErrorReportActivity";
protected void onCreate(Bundle savedInstanceState) {
try {
super.onCreate(savedInstanceState);
setUpUI();
handleIntent();
} catch (Throwable throwable) {
throwable.printStackTrace();
Log.e(TAG, "", throwable);
}
}
private void handleIntent() {
String message = getIntent().getStringExtra("message");
final String errorDetail = getIntent().getStringExtra("error");
//showErrorMessage(message, errorDetail);
showErrorMessageByDialog(message, errorDetail);
}
private void showErrorMessageByDialog(String message, final String errorDetail) {
new MaterialDialog.Builder(this)
.content(message)
.title(R.string.text_crash)
.content(R.string.crash_feedback)
.positiveText(R.string.text_exit)
.negativeText(R.string.text_copy_debug_info)
.onPositive(new MaterialDialog.SingleButtonCallback() {
@@ -55,6 +64,10 @@ public class ErrorReportActivity extends BaseActivity {
.show();
}
private void showErrorMessage(String message, String errorDetail) {
((TextView) findViewById(R.id.error)).setText(message + "\n" + errorDetail);
}
private String getDeviceMessage() {
return "Android: " + Build.VERSION.SDK_INT + "\n";
}
@@ -86,13 +99,13 @@ public class ErrorReportActivity extends BaseActivity {
getSupportActionBar().setHomeButtonEnabled(false);
}
private void exit() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
finishAffinity();
} else {
finish();
}
@Override
public void onBackPressed() {
exit();
}
private void exit() {
finishAffinity();
}
}

View File

@@ -54,7 +54,7 @@ public class MainActivity extends BaseActivity implements FileChooserDialog.File
private void goToAccessibilityPermissionSettingIfDisabled() {
if (!AccessibilityServiceUtils.isAccessibilityServiceEnabled(this, ActionPerformService.class)) {
new NotRemindAgainDialog.Builder(this)
new NotRemindAgainDialog.Builder(this, "goToAccessibilityPermissionSettingIfDisabled")
.title(R.string.text_alert)
.content(R.string.explain_accessibility_permission)
.positiveText(R.string.text_go_to_setting)
@@ -62,7 +62,7 @@ public class MainActivity extends BaseActivity implements FileChooserDialog.File
.onPositive(new MaterialDialog.SingleButtonCallback() {
@Override
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
AccessibilityServiceUtils.goToPermissionSetting(MainActivity.this);
AccessibilityServiceUtils.goToAccessibilitySetting(MainActivity.this);
}
}).show();
}

View File

@@ -18,7 +18,9 @@ public class NonUiInitializer {
private static final Map<String, Integer> SAMPLES = new MapEntries<String, Integer>()
.entry("sample_open_wechat_moment.js", R.string.text_sample_open_what_moment)
.entry("sample_open_running_services.js", R.string.text_sample_open_running_services)
.entry("sample_hello_big_sister.js", R.string.text_sample_hello_big_sister)
.entry("sample_qq_hongbao.js", R.string.text_sample_qq_hongbao)
.entry("sample_simple_calculator.js", R.string.text_sample_simple_calculator)
.entry("sample_force_qq_chat.js", R.string.text_sample_for_qq_chat)
.map();
private static NonUiInitializer instance = new NonUiInitializer();
@@ -41,21 +43,25 @@ public class NonUiInitializer {
}
}
private void copySampleScriptFile() {
public int copySampleScriptFile() {
ScriptFileList list = SharedPrefScriptFileList.getInstance();
int succeedCount = 0;
int failCount = 0;
for (Map.Entry<String, Integer> entry : SAMPLES.entrySet()) {
String assetFile = entry.getKey();
String name = getContext().getString(entry.getValue());
String path = ScriptFile.DEFAULT_FOLDER + name + ".js";
if (FileUtils.copyAsset(assetFile, path)) {
list.add(new ScriptFile(name, path));
succeedCount++;
if (!list.containsPath(path)) {
if (FileUtils.copyAsset(assetFile, path)) {
list.add(new ScriptFile(name, path));
} else {
failCount++;
}
}
}
if (succeedCount > 0) {
if (failCount > 0) {
Pref.def().edit().putBoolean(Pref.SAMPLE_SCRIPTS_COPIED, true).apply();
}
return failCount;
}
}

View File

@@ -1,5 +1,6 @@
package com.stardust.scriptdroid;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
@@ -8,10 +9,28 @@ import android.preference.PreferenceManager;
*/
public class Pref {
private static final SharedPreferences DISPOSABLE_BOOLEAN = App.getApp().getSharedPreferences("DISPOSABLE_BOOLEAN", Context.MODE_PRIVATE);
public static final String SAMPLE_SCRIPTS_COPIED = "SAMPLE_SCRIPTS_COPIED";
public static SharedPreferences def() {
return PreferenceManager.getDefaultSharedPreferences(App.getApp());
}
public static boolean isFirstEnableAssistMode() {
return getDisposableBoolean("isFirstEnableAssistMode", true);
}
private static boolean getDisposableBoolean(String key, boolean defaultValue) {
boolean b = DISPOSABLE_BOOLEAN.getBoolean(key, defaultValue);
if (b == defaultValue) {
DISPOSABLE_BOOLEAN.edit().putBoolean(key, !defaultValue).apply();
}
return b;
}
public static boolean isFirstGoToAccessibilitySetting() {
return getDisposableBoolean("isFirstGoToAccessibilitySetting", true);
}
}

View File

@@ -7,6 +7,7 @@ import android.preference.PreferenceScreen;
import android.support.annotation.Nullable;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.Toast;
import com.stardust.util.MapEntries;
@@ -61,6 +62,16 @@ public class SettingsActivity extends BaseActivity {
public void onStart() {
super.onStart();
ACTION_MAP = new MapEntries<String, Runnable>()
.entry(getString(R.string.text_re_import_samples), new Runnable() {
@Override
public void run() {
int failCount = NonUiInitializer.getInstance().copySampleScriptFile();
if (failCount <= 0) {
Toast.makeText(getActivity(), R.string.text_re_import_succeed, Toast.LENGTH_SHORT).show();
} else
Toast.makeText(getActivity(), R.string.text_fail, Toast.LENGTH_SHORT).show();
}
})
.entry(getString(R.string.text_about), new Runnable() {
@Override
public void run() {

View File

@@ -1,10 +1,15 @@
package com.stardust.scriptdroid.droid;
import android.app.Activity;
import android.content.DialogInterface;
import com.afollestad.materialdialogs.MaterialDialog;
import com.stardust.scriptdroid.App;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.droid.runtime.DroidRuntime;
import com.stardust.scriptdroid.droid.script.DuktapeJavaScriptEngine;
import com.stardust.scriptdroid.droid.script.JavaScriptEngine;
import com.stardust.scriptdroid.droid.script.ScriptExecuteActivity;
import com.stardust.scriptdroid.file.FileUtils;
import java.io.File;
@@ -16,12 +21,14 @@ import java.io.FileNotFoundException;
public class Droid {
public static final String UI = "\"ui\";";
public interface OnRunFinishedListener {
void onRunFinished(Object result, Exception e);
}
private static final DroidRuntime RUNTIME = DroidRuntime.getRuntime();
private static final JavaScriptEngine JAVA_SCRIPT_ENGINE = new DuktapeJavaScriptEngine(RUNTIME);
public static final JavaScriptEngine JAVA_SCRIPT_ENGINE = new DuktapeJavaScriptEngine(RUNTIME);
private static final OnRunFinishedListener DEFAULT_LISTENER = new OnRunFinishedListener() {
@Override
public void onRunFinished(Object result, Exception e) {
@@ -33,7 +40,6 @@ public class Droid {
private static Droid instance = new Droid();
protected Droid() {
}
public static Droid getInstance() {
@@ -59,8 +65,13 @@ public class Droid {
}
public void runScript(final String script, OnRunFinishedListener listener, RunningConfig config) {
listener = listener == null ? DEFAULT_LISTENER : listener;
if (config.runInNewThread) {
new Thread(new RunScriptRunnable(script, listener, config)).start();
if (script.startsWith(UI)) {
ScriptExecuteActivity.runScript(script, listener, config);
} else {
new Thread(new RunScriptRunnable(script, listener, config)).start();
}
} else {
new RunScriptRunnable(script, listener, config).run();
}
@@ -72,11 +83,6 @@ public class Droid {
return JAVA_SCRIPT_ENGINE.stopAll();
}
public void ensureNotStopped() {
JAVA_SCRIPT_ENGINE.ensureNotStopped();
}
private void checkFile(File file) {
if (file == null) {
throw new NullPointerException("file = null");
@@ -95,8 +101,8 @@ public class Droid {
private final String mScript;
private OnRunFinishedListener mOnRunFinishedListener;
public RunScriptRunnable(String script, OnRunFinishedListener listener, RunningConfig config) {
mOnRunFinishedListener = listener == null ? DEFAULT_LISTENER : listener;
RunScriptRunnable(String script, OnRunFinishedListener listener, RunningConfig config) {
mOnRunFinishedListener = listener;
mScript = script;
}
@@ -108,5 +114,10 @@ public class Droid {
mOnRunFinishedListener.onRunFinished(null, e);
}
}
public RunScriptRunnable setActivity(Activity a) {
JAVA_SCRIPT_ENGINE.set("activity", Activity.class, a);
return this;
}
}
}

View File

@@ -4,7 +4,7 @@ package com.stardust.scriptdroid.droid.assist;
* Created by Stardust on 2017/2/4.
*/
public interface AssistClipList {
public interface BoundsAssistClipList {
interface OnClipChangedListener {
void onClipRemove(int position);

View File

@@ -6,29 +6,43 @@ import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Toast;
import com.afollestad.materialdialogs.MaterialDialog;
import com.stardust.scriptdroid.App;
import com.stardust.scriptdroid.Pref;
import com.stardust.scriptdroid.R;
/**
* Created by Stardust on 2017/2/4.
*/
public class Assistant {
public class BoundsAssistant {
public static final String KEY_ASSIST_MODE_ENABLE = "ASSIST_MODE_ENABLE";
private static boolean assistModeEnable;
private static AssistClipList assistClipList = SharedPrefAssistClipList.getInstance();
private static BoundsAssistClipList boundsAssistClipList = SharedPrefBoundsAssistClipList.getInstance();
public static boolean isAssistModeEnable() {
return assistModeEnable;
}
public static void setAssistModeEnable(boolean assistModeEnable) {
Assistant.assistModeEnable = assistModeEnable;
if (assistModeEnable && Pref.isFirstEnableAssistMode()) {
showAssistModeInfoDialog();
}
BoundsAssistant.assistModeEnable = assistModeEnable;
App.getStateObserver().setState(KEY_ASSIST_MODE_ENABLE, assistModeEnable);
}
private static void showAssistModeInfoDialog() {
new MaterialDialog.Builder(App.currentActivity())
.title(R.string.text_alert)
.content(R.string.assist_mode_notice)
.positiveText(R.string.ok)
.show();
}
public static void performAssistance(AccessibilityEvent event) {
if (!assistModeEnable) {
return;
@@ -53,7 +67,7 @@ public class Assistant {
private static void saveAndAlertBounds(Rect rect) {
String str = rect.toString().replace('-', ',').replace(" ", "").substring(4);
assistClipList.add(str);
boundsAssistClipList.add(str);
Toast.makeText(App.getApp(), str, Toast.LENGTH_SHORT).show();
}

View File

@@ -15,24 +15,24 @@ import java.util.List;
* Created by Stardust on 2017/2/4.
*/
public class SharedPrefAssistClipList implements AssistClipList {
public class SharedPrefBoundsAssistClipList implements BoundsAssistClipList {
private static final Gson GSON = new Gson();
private static SharedPrefAssistClipList instance = new SharedPrefAssistClipList(App.getApp());
private static SharedPrefBoundsAssistClipList instance = new SharedPrefBoundsAssistClipList(App.getApp());
private OnClipChangedListener mOnClipChangedListener;
public static SharedPrefAssistClipList getInstance() {
public static SharedPrefBoundsAssistClipList getInstance() {
return instance;
}
private static final int MAX_SIZE = 10;
private static final String SHARED_PREF_NAME = "SharedPrefAssistClipList";
private static final String SHARED_PREF_NAME = "SharedPrefBoundsAssistClipList";
private SharedPreferences mSharedPreferences;
private List<String> mAssistClipList = new LinkedList<>();
public SharedPrefAssistClipList(Context context) {
public SharedPrefBoundsAssistClipList(Context context) {
mSharedPreferences = context.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE);
readFromSharedPref();
}

View File

@@ -1,6 +1,5 @@
package com.stardust.scriptdroid.droid.runtime;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -12,7 +11,6 @@ import android.widget.Toast;
import com.afollestad.materialdialogs.MaterialDialog;
import com.stardust.scriptdroid.App;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.droid.Droid;
import com.stardust.scriptdroid.droid.runtime.action.Action;
import com.stardust.scriptdroid.droid.runtime.action.ActionFactory;
import com.stardust.scriptdroid.droid.runtime.action.ActionPerformService;
@@ -21,6 +19,8 @@ import com.stardust.scriptdroid.droid.runtime.api.IDroidRuntime;
import java.util.List;
;
/**
* Created by Stardust on 2017/1/27.
*/
@@ -29,21 +29,15 @@ public class DroidRuntime implements IDroidRuntime {
private static final String TAG = "DroidRuntime";
private static DroidRuntime runtime = new DroidRuntime();
private static Context context;
private final Object mLock = new Object();
private boolean mActionPerformResult;
private boolean mActionPerformResultUpToDate;
private Handler mUIHandler;
public static DroidRuntime getRuntime() {
return runtime;
}
public static void setContext(Context context) {
DroidRuntime.context = context;
}
protected DroidRuntime() {
mUIHandler = new Handler(App.getApp().getMainLooper());
}
@@ -143,25 +137,20 @@ public class DroidRuntime implements IDroidRuntime {
private boolean performAction(Action action) {
if (ActionPerformService.getInstance() == null) {
toast(App.getApp().getString(R.string.text_no_accessibility_permission));
throw new PermissionDeniedException(App.getApp().getString(R.string.text_no_accessibility_permission));
throw new ScriptStopException(App.getApp().getString(R.string.text_no_accessibility_permission));
}
ensureNotStopped();
ActionPerformService.setAction(action);
synchronized (mLock) {
try {
mLock.wait();
} catch (InterruptedException e) {
throw new PermissionDeniedException("已停止运行");
ActionPerformService.setActions(ActionPerformService.NO_ACTION);
throw new ScriptStopException(App.getApp().getString(R.string.text_script_stopped), e);
}
}
return mActionPerformResult;
}
private void ensureNotStopped() {
Droid.getInstance().ensureNotStopped();
}
@Override
public void toast(final String text) {
mUIHandler.post(new Runnable() {
@@ -172,18 +161,48 @@ public class DroidRuntime implements IDroidRuntime {
});
}
@Override
public void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
throw new ScriptStopException(e);
}
}
@Override
public boolean isStopped() {
return Thread.currentThread().isInterrupted();
}
@Override
public void stop() {
Thread.interrupted();
}
@Override
public MaterialDialog.Builder dialog() {
return new Builder();
if (App.currentActivity() == null) {
Toast.makeText(App.getApp(), R.string.text_cannot_create_dialog_when_app_invisible, Toast.LENGTH_SHORT).show();
throw new ScriptStopException(App.getApp().getString(R.string.text_cannot_create_dialog_when_app_invisible));
}
return new MaterialDialog.Builder(App.currentActivity()) {
public MaterialDialog show() {
mUIHandler.post(new Runnable() {
@Override
public void run() {
superShow();
}
});
return null;
}
private void superShow() {
super.show();
}
};
}
public void notifyActionPerformed(boolean succeed) {
@@ -193,16 +212,4 @@ public class DroidRuntime implements IDroidRuntime {
}
}
public class Builder extends MaterialDialog.Builder {
public Builder() {
super(DroidRuntime.context);
}
public MaterialDialog show(final MaterialDialog.Builder dialog) {
return null;
}
}
}

View File

@@ -1,10 +0,0 @@
package com.stardust.scriptdroid.droid.runtime;
/**
* Created by Stardust on 2017/1/29.
*/
public class PermissionDeniedException extends RuntimeException {
public PermissionDeniedException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,24 @@
package com.stardust.scriptdroid.droid.runtime;
/**
* Created by Stardust on 2017/1/29.
*/
public class ScriptStopException extends RuntimeException {
public ScriptStopException(String message, Throwable cause) {
super(message, cause);
}
public ScriptStopException(String message) {
super(message);
}
public ScriptStopException() {
}
public ScriptStopException(Throwable cause) {
super(cause);
}
}

View File

@@ -7,7 +7,7 @@ import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import com.stardust.scriptdroid.App;
import com.stardust.scriptdroid.droid.assist.Assistant;
import com.stardust.scriptdroid.droid.assist.BoundsAssistant;
import com.stardust.scriptdroid.droid.runtime.DroidRuntime;
import com.stardust.view.accessibility.AccessibilityServiceUtils;
@@ -53,7 +53,7 @@ public class ActionPerformService extends AccessibilityService {
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
Log.v(TAG, "onAccessibilityEvent: state=" + state + " event=" + event);
Assistant.performAssistance(event);
BoundsAssistant.performAssistance(event);
if (state == STATE_INACTIVE)
return;
AccessibilityNodeInfo root = getRootInActiveWindow();
@@ -103,8 +103,12 @@ public class ActionPerformService extends AccessibilityService {
}
public static void disable() {
if (instance != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
instance.disableSelf();
if (instance != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
instance.disableSelf();
} else {
AccessibilityServiceUtils.goToAccessibilitySetting(App.getApp());
}
}
}

View File

@@ -42,5 +42,9 @@ public interface IDroidRuntime {
void sleep(long millis);
boolean isStopped();
void stop();
MaterialDialog.Builder dialog();
}

View File

@@ -3,7 +3,7 @@ package com.stardust.scriptdroid.droid.script;
import com.efurture.script.JSTransformer;
import com.furture.react.DuktapeEngine;
import com.stardust.scriptdroid.App;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.droid.Droid;
import com.stardust.scriptdroid.droid.runtime.api.IDroidRuntime;
import java.io.IOException;
@@ -34,7 +34,6 @@ public class DuktapeJavaScriptEngine implements JavaScriptEngine {
public DuktapeJavaScriptEngine(IDroidRuntime runtime) {
setRuntime(runtime);
}
private void setRuntime(IDroidRuntime runtime) {
@@ -50,13 +49,15 @@ public class DuktapeJavaScriptEngine implements JavaScriptEngine {
try {
result = duktapeEngine.execute(JSTransformer.parse(new StringReader(script)));
} catch (IOException e) {
remove(Thread.currentThread());
removeAndStop(Thread.currentThread());
throw e;
}
remove(Thread.currentThread());
if (!script.startsWith(Droid.UI))
removeAndDestroy(Thread.currentThread());
return result;
}
private void init(DuktapeEngine duktapeEngine) {
duktapeEngine.put("context", App.getApp());
duktapeEngine.execute(INIT_SCRIPT);
@@ -66,13 +67,23 @@ public class DuktapeJavaScriptEngine implements JavaScriptEngine {
}
private void remove(Thread thread) {
public void removeAndStop(Thread thread) {
synchronized (mThreadDuktapeEngineMap) {
DuktapeEngine engine = mThreadDuktapeEngineMap.remove(thread);
stop(engine, thread);
}
}
@Override
public void removeAndDestroy(Thread thread) {
synchronized (mThreadDuktapeEngineMap) {
DuktapeEngine engine = mThreadDuktapeEngineMap.remove(thread);
if (engine != null)
engine.destory();
}
}
private void stop(DuktapeEngine engine, Thread thread) {
if (engine != null)
engine.destory();
@@ -107,10 +118,4 @@ public class DuktapeJavaScriptEngine implements JavaScriptEngine {
return n;
}
@Override
public void ensureNotStopped() {
if (!mThreadDuktapeEngineMap.containsKey(Thread.currentThread())) {
throw new RuntimeException(App.getApp().getString(R.string.text_script_stopped));
}
}
}

View File

@@ -17,7 +17,7 @@ public interface JavaScriptEngine {
int stopAll();
void ensureNotStopped();
void removeAndDestroy(Thread thread);
class Init {
public static final String INIT_SCRIPT = readInitScript();

View File

@@ -0,0 +1,59 @@
package com.stardust.scriptdroid.droid.script;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import com.stardust.scriptdroid.App;
import com.stardust.scriptdroid.droid.Droid;
import com.stardust.scriptdroid.droid.RunningConfig;
import static com.stardust.scriptdroid.droid.Droid.JAVA_SCRIPT_ENGINE;
/**
* Created by Stardust on 2017/2/5.
*/
public class ScriptExecuteActivity extends Activity {
private static String script;
private static Droid.OnRunFinishedListener onRunFinishedListener;
private static RunningConfig runningConfig;
private Object mResult;
public static void runScript(String script, Droid.OnRunFinishedListener listener, RunningConfig config) {
ScriptExecuteActivity.script = script;
ScriptExecuteActivity.onRunFinishedListener = listener;
ScriptExecuteActivity.runningConfig = config;
App.getApp().startActivity(new Intent(App.getApp(), ScriptExecuteActivity.class));
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
runScript();
}
private void runScript() {
JAVA_SCRIPT_ENGINE.set("activity", Activity.class, this);
try {
mResult = JAVA_SCRIPT_ENGINE.execute(script);
} catch (Exception e) {
onRunFinishedListener.onRunFinished(null, e);
finish();
}
}
@Override
public void finish() {
onRunFinishedListener.onRunFinished(mResult, null);
super.finish();
}
@Override
protected void onDestroy() {
super.onDestroy();
JAVA_SCRIPT_ENGINE.removeAndDestroy(Thread.currentThread());
}
}

View File

@@ -25,4 +25,5 @@ public abstract class ScriptFileList {
}
public abstract boolean containsPath(String path);
}

View File

@@ -89,6 +89,11 @@ public class SharedPrefScriptFileList extends ScriptFileList {
return mScriptPath.size();
}
@Override
public boolean containsPath(String path) {
return mScriptPath.contains(path);
}
protected void syncWithSharedPref() {
SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putString(SP_KEY_SCRIPT_NAME, GSON.toJson(mScriptName));

View File

@@ -5,7 +5,7 @@ import android.service.quicksettings.Tile;
import android.service.quicksettings.TileService;
import android.support.annotation.RequiresApi;
import com.stardust.scriptdroid.droid.assist.Assistant;
import com.stardust.scriptdroid.droid.assist.BoundsAssistant;
/**
* Created by Stardust on 2017/1/26.
@@ -15,12 +15,12 @@ import com.stardust.scriptdroid.droid.assist.Assistant;
public class BoundsAssistEnableTileService extends TileService {
public void onClick() {
Assistant.setAssistModeEnable(!Assistant.isAssistModeEnable());
BoundsAssistant.setAssistModeEnable(!BoundsAssistant.isAssistModeEnable());
updateTile();
}
private void updateTile() {
getQsTile().setState(Assistant.isAssistModeEnable() ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE);
getQsTile().setState(BoundsAssistant.isAssistModeEnable() ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE);
getQsTile().updateTile();
}

View File

@@ -11,8 +11,8 @@ import android.view.ViewGroup;
import android.widget.TextView;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.droid.assist.AssistClipList;
import com.stardust.scriptdroid.droid.assist.SharedPrefAssistClipList;
import com.stardust.scriptdroid.droid.assist.BoundsAssistClipList;
import com.stardust.scriptdroid.droid.assist.SharedPrefBoundsAssistClipList;
import com.stardust.scriptdroid.widget.ExpandableRecyclerView;
/**
@@ -25,7 +25,7 @@ public class AssistClipListRecyclerView extends ExpandableRecyclerView {
void onClick(String clip, int position);
}
private AssistClipList mAssistClipList = SharedPrefAssistClipList.getInstance();
private BoundsAssistClipList mBoundsAssistClipList = SharedPrefBoundsAssistClipList.getInstance();
private OnClipClickListener mOnClipClickListener;
public AssistClipListRecyclerView(Context context) {
@@ -55,7 +55,7 @@ public class AssistClipListRecyclerView extends ExpandableRecyclerView {
}
}
});
mAssistClipList.setOnClipChangedListener(new AssistClipList.OnClipChangedListener() {
mBoundsAssistClipList.setOnClipChangedListener(new BoundsAssistClipList.OnClipChangedListener() {
@Override
public void onClipRemove(int position) {
getAdapter().notifyItemRemoved(position);
@@ -82,7 +82,7 @@ public class AssistClipListRecyclerView extends ExpandableRecyclerView {
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
//防止因mAssistClipList持有OnClipChangedListener引用从而导致这个RecyclerView及其Context被引用内存泄漏
mAssistClipList.setOnClipChangedListener(null);
mBoundsAssistClipList.setOnClipChangedListener(null);
}
private class Adapter extends ExpandableRecyclerView.DefaultTitleAdapter {
@@ -100,12 +100,12 @@ public class AssistClipListRecyclerView extends ExpandableRecyclerView {
@Override
protected void onBindChildViewHolder(RecyclerView.ViewHolder holder, int position) {
ChildViewHolder viewHolder = (ChildViewHolder) holder;
viewHolder.mTextView.setText(mAssistClipList.get(position));
viewHolder.mTextView.setText(mBoundsAssistClipList.get(position));
}
@Override
protected int getChildItemCount() {
return mAssistClipList.size();
return mBoundsAssistClipList.size();
}
@Override

View File

@@ -9,7 +9,7 @@ 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.Assistant;
import com.stardust.scriptdroid.droid.assist.BoundsAssistant;
import com.stardust.util.StateObserver;
@@ -44,7 +44,7 @@ public class AssistModeSwitchNotification {
}
}
});
App.getStateObserver().register(Assistant.KEY_ASSIST_MODE_ENABLE, new StateObserver.OnBooleanStateChangedListener() {
App.getStateObserver().register(BoundsAssistant.KEY_ASSIST_MODE_ENABLE, new StateObserver.OnBooleanStateChangedListener() {
@Override
public void onStateChanged(Boolean newState) {
if (enable) {
@@ -78,7 +78,7 @@ public class AssistModeSwitchNotification {
.setAutoCancel(false)
.setSmallIcon(R.drawable.ic_robot_head)
.setDeleteIntent(AssistModeSwitchService.getDeletePendingIntent())
.setContentText(Assistant.isAssistModeEnable() ?
.setContentText(BoundsAssistant.isAssistModeEnable() ?
App.getApp().getString(R.string.text_assist_mode_enabled) :
App.getApp().getString(R.string.text_assist_mode_disabled))
.setContentIntent(AssistModeSwitchService.getStartIntent())

View File

@@ -12,7 +12,7 @@ import android.view.ViewGroup;
import com.stardust.scriptdroid.App;
import com.stardust.scriptdroid.DocumentActivity;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.droid.assist.Assistant;
import com.stardust.scriptdroid.droid.assist.BoundsAssistant;
import com.stardust.view.ViewBinder;
import com.stardust.view.ViewBinding;
@@ -70,14 +70,14 @@ public class EditSideMenuFragment extends com.stardust.app.Fragment {
}
private void syncSwitchState() {
mAssistServiceSwitch.setChecked(Assistant.isAssistModeEnable());
mAssistServiceSwitch.setChecked(BoundsAssistant.isAssistModeEnable());
mAssistServiceNotificationSwitch.setChecked(AssistModeSwitchNotification.isEnable());
}
private void setUpSwitchCompat() {
mAssistServiceSwitch = $(R.id.sw_assist_service);
mAssistServiceNotificationSwitch = $(R.id.sw_assist_service_notification);
App.getStateObserver().register(Assistant.KEY_ASSIST_MODE_ENABLE, mAssistServiceSwitch);
App.getStateObserver().register(BoundsAssistant.KEY_ASSIST_MODE_ENABLE, mAssistServiceSwitch);
App.getStateObserver().register(KEY_ASSIST_MODE_NOTIFICATION, mAssistServiceNotificationSwitch);
}
@@ -88,7 +88,7 @@ public class EditSideMenuFragment extends com.stardust.app.Fragment {
@ViewBinding.Check(R.id.sw_assist_service)
private void setAssistServiceEnable(boolean enable) {
Assistant.setAssistModeEnable(enable);
BoundsAssistant.setAssistModeEnable(enable);
}
@ViewBinding.Click(R.id.assist_service)

View File

@@ -15,7 +15,10 @@ import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.file.FileUtils;
import com.stardust.scriptdroid.widget.ExpandableRecyclerView;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
@@ -91,7 +94,7 @@ public class FunctionListRecyclerView extends ExpandableRecyclerView {
Adapter() {
setIcon(R.drawable.ic_function_mathematical_green);
setTitle(R.string.text_function);
setTitle(R.string.text_common_function);
}
@Override
@@ -136,6 +139,12 @@ public class FunctionListRecyclerView extends ExpandableRecyclerView {
String[] str = f.split(" ");
FUNCTION_LIST.add(new Function(str[0], str[1]));
}
final Comparator cmp = Collator.getInstance();
Collections.sort(FUNCTION_LIST, new Comparator<Function>() {
@Override
public int compare(Function f1, Function f2) {
return cmp.compare(f1.description, f2.description);
}
});
}
}

View File

@@ -15,7 +15,7 @@ import com.stardust.scriptdroid.App;
import com.stardust.scriptdroid.DocumentActivity;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.droid.Droid;
import com.stardust.scriptdroid.droid.assist.Assistant;
import com.stardust.scriptdroid.droid.assist.BoundsAssistant;
import com.stardust.scriptdroid.droid.runtime.action.ActionPerformService;
import com.stardust.view.ViewBinder;
import com.stardust.view.ViewBinding;
@@ -60,7 +60,7 @@ public class SlideMenuFragment extends Fragment {
mAutoOperateServiceSwitch.setChecked(ActionPerformService.isEnable());
}
}, 450);
mAssistServiceSwitch.setChecked(Assistant.isAssistModeEnable());
mAssistServiceSwitch.setChecked(BoundsAssistant.isAssistModeEnable());
mAssistServiceNotificationSwitch.setChecked(AssistModeSwitchNotification.isEnable());
}
@@ -68,7 +68,7 @@ public class SlideMenuFragment extends Fragment {
mAutoOperateServiceSwitch = $(R.id.sw_auto_operate_service);
mAssistServiceSwitch = $(R.id.sw_assist_service);
mAssistServiceNotificationSwitch = $(R.id.sw_assist_service_notification);
App.getStateObserver().register(Assistant.KEY_ASSIST_MODE_ENABLE, mAssistServiceSwitch);
App.getStateObserver().register(BoundsAssistant.KEY_ASSIST_MODE_ENABLE, mAssistServiceSwitch);
App.getStateObserver().register(KEY_ASSIST_MODE_NOTIFICATION, mAssistServiceNotificationSwitch);
}
@@ -85,7 +85,7 @@ public class SlideMenuFragment extends Fragment {
@ViewBinding.Check(R.id.sw_auto_operate_service)
private void setAutoOperateServiceEnable(boolean enable) {
if (enable && !ActionPerformService.isEnable()) {
AccessibilityServiceUtils.goToPermissionSetting(getContext());
AccessibilityServiceUtils.goToAccessibilitySetting(getContext());
} else if (!enable && ActionPerformService.isEnable()) {
ActionPerformService.disable();
}
@@ -93,7 +93,7 @@ public class SlideMenuFragment extends Fragment {
@ViewBinding.Check(R.id.sw_assist_service)
private void setAssistServiceEnable(boolean enable) {
Assistant.setAssistModeEnable(enable);
BoundsAssistant.setAssistModeEnable(enable);
}
@ViewBinding.Click(R.id.assist_service)

View File

@@ -80,11 +80,15 @@ public class ExpandableRecyclerView extends RecyclerView {
}
public void expand() {
if (mExpanded)
return;
mExpanded = true;
((Adapter) getAdapter()).notifyExpanded();
}
public void collapse() {
if (!mExpanded)
return;
mExpanded = false;
((Adapter) getAdapter()).notifyCollapsed();
}
@@ -95,17 +99,11 @@ public class ExpandableRecyclerView extends RecyclerView {
public void notifyExpanded() {
notifyItemChanged(0);
int n = getItemCount();
for (int i = 1; i < n; i++) {
notifyItemInserted(i);
}
notifyItemRangeInserted(1, getChildItemCount());
}
public void notifyCollapsed() {
int n = getChildItemCount();
for (int i = 0; i < n; i++) {
notifyItemRemoved(1);
}
notifyItemRangeRemoved(1, getChildItemCount());
notifyItemChanged(0);
}

View File

@@ -25,8 +25,7 @@ public class CrashHandler implements UncaughtExceptionHandler {
public void uncaughtException(Thread thread, Throwable ex) {
try {
Log.e("CrashHandler", "Uncaught Exception!!!");
ex.printStackTrace();
Log.e(TAG, "Uncaught Exception", ex);
String t = App.getApp().getString(R.string.sorry_for_crash) + ex.toString();
Intent intent = new Intent(App.getApp(), this.mErrorReportClass);
intent.putExtra("message", t);

View File

@@ -4,10 +4,10 @@ import android.content.SharedPreferences;
import android.support.v7.widget.SwitchCompat;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
/**
* Created by Stardust on 2017/2/3.
@@ -70,7 +70,10 @@ public class StateObserver {
if (initialState != null)
listener.initState(initialState);
synchronized (mKeyStateListenersMap) {
getListenerListOrCreateIfNotExists(key).add(listener);
List<OnStateChangedListener> listeners = getListenerListOrCreateIfNotExists(key);
synchronized (listener) {
listeners.add(listener);
}
}
}
@@ -81,19 +84,25 @@ public class StateObserver {
if (listeners == null) {
return;
}
listeners.remove(stateChangedListener);
synchronized (listeners) {
listeners.remove(stateChangedListener);
}
}
}
public <T> void setState(String key, T state) {
synchronized (mKeyStateListenersMap) {
List<OnStateChangedListener> listeners = mKeyStateListenersMap.get(key);
if (listeners == null || listeners.isEmpty()) {
if (listeners == null)
return;
}
if (listeners.get(0) instanceof OnBooleanStateChangedListener) {
mSharedPreferences.edit().putBoolean(key, (Boolean) state).apply();
notifyBooleanStateChanged(listeners, (Boolean) state);
synchronized (listeners) {
if (listeners.isEmpty()) {
return;
}
if (listeners.get(0) instanceof OnBooleanStateChangedListener) {
mSharedPreferences.edit().putBoolean(key, (Boolean) state).apply();
notifyBooleanStateChanged(listeners, (Boolean) state);
}
}
}
}
@@ -115,7 +124,7 @@ public class StateObserver {
private List<OnStateChangedListener> getListenerListOrCreateIfNotExists(String key) {
List<OnStateChangedListener> listeners = mKeyStateListenersMap.get(key);
if (listeners == null) {
listeners = new Vector<>();
listeners = new ArrayList<>();
mKeyStateListenersMap.put(key, listeners);
}
return listeners;

View File

@@ -40,8 +40,10 @@ public class ViewBinder {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
try {
method.invoke(o, isChecked);
} catch (IllegalAccessException | InvocationTargetException e) {
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
});

View File

@@ -5,6 +5,10 @@ import android.content.Context;
import android.content.Intent;
import android.provider.Settings;
import android.text.TextUtils;
import android.widget.Toast;
import com.stardust.scriptdroid.Pref;
import com.stardust.scriptdroid.R;
/**
* Created by Stardust on 2017/1/26.
@@ -12,7 +16,10 @@ import android.text.TextUtils;
public class AccessibilityServiceUtils {
public static void goToPermissionSetting(Context context) {
public static void goToAccessibilitySetting(Context context) {
if (Pref.isFirstGoToAccessibilitySetting()) {
Toast.makeText(context, context.getString(R.string.text_please_choose) + context.getString(R.string.app_name), Toast.LENGTH_LONG).show();
}
context.startActivity(new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS));
}

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
@@ -20,4 +21,13 @@
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
<TextView
android:id="@+id/error"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
android:scrollbars="vertical"
android:textColor="@android:color/secondary_text_light"
android:textSize="16sp"
tools:text="错误"/>
</LinearLayout>

View File

@@ -40,7 +40,7 @@
android:layout_height="20dp"
android:layout_alignParentLeft="true"
android:layout_margin="16dp"
android:src="@drawable/ic_service_green"/>
android:src="@drawable/ic_robot_head_green"/>
<TextView
android:layout_width="wrap_content"

View File

@@ -74,7 +74,7 @@
android:layout_height="20dp"
android:layout_alignParentLeft="true"
android:layout_margin="16dp"
android:src="@drawable/ic_service_green"/>
android:src="@drawable/ic_robot_head_green"/>
<TextView
android:layout_width="wrap_content"

View File

@@ -4,21 +4,31 @@
###二、自动操作函数
**自动操作的函数都需要开启"自动操作服务"才能执行,否则执行到相应函数时脚本会停止运行。**
* `click(text)` 点击文本text所在的区域并返回是否点击成功。当前界面没有出现该文本或者该文本所在区域不可点击时返回false。例如`click("发现")`,是点击"发现"。如果要点击"发现"直至点击成功可以用`while(!click("发现"))`
> 文本所在区域指的是,从文本处向寻找,直至发现一个可点击的部件为止。
* `click(left, top, bottom, right)` 点击与长方形范围严格匹配的区域并返回是否点击成功。其中left为长方形左边与屏幕左边的像素距离top为上边与屏幕上边的像素距离right为右边与**屏幕左边**的像素距离, bottom为下边与**屏幕下边**的距离。区域严格匹配,至于要确定要点击的区域在屏幕上的左边位置,可以在侧拉菜单开启"脚本辅助"或者安卓7.0以上在通知栏点击"修改"添加脚本辅助快捷设定图标),之后每次点击或长按事件都会提示这次点击或长按的区域并自动保存,可以在编辑器中插入。
> 文本所在区域指的是,从文本处向其父视图寻找,直至发现一个可点击的部件为止。
* `click(left, top, bottom, right)`
> 有些按钮或者部件是图标而不是文字例如发送朋友圈的照相机图标以及QQ下方的消息、联系人、动态图标这时不能通过`click(text)`来点击只能通过描述图标所在的区域来点击。left, bottom, top, right描述的就是点击的区域。至于要定位点击的区域可以在侧拉菜单开启"点击区域辅助"或者安卓7.0以上在通知栏点击"修改"添加点击区域辅助快捷设定图标),之后每次点击或长按都会提示这次点击或长按的区域并自动保存,可以在编辑器的右侧拉菜单中插入。
点击与长方形范围严格匹配的区域并返回是否点击成功。其中left为长方形左边与屏幕左边的像素距离top为上边与屏幕上边的像素距离right为右边与**屏幕左边**的像素距离, bottom为下边与**屏幕上边**的距离。区域严格匹配。
> 以下的longClick、select、scrollUp、scrollDown的参数均与click类似不再赘述。
* `longClick` 长按
* `select` 选择
* `scrollUp` 上滑。不加参数时会寻找"最大"的可滑动的控件滑,例如微信消息列表等。
* `scrollUp` 上滑。不加参数时会寻找"最大"的可滑动的控件滑,例如微信消息列表等。
* `scrollDown` 下滑。不加参数时与scrollUp类似。
* `input(string)` 把所有输入框的文本都置为string
* `input(text)` 把所有输入框的文本都置为text。例如input("测试")
* `input(i, text)` 把第i个输入框的文本设为text。i从0开始。
###三、其他函数
* `sleep(n)` 暂停执行n**毫秒**时间。
* `toast(string)` 显示提示文本。
* `toast(text)` 显示提示文本。
* `launch(packageName)` 运行包名为packageName的应用。例如launch("com.tencent.mm")是运行微信应用包名可以通过一些工具获取获取通过函数launchApp代替
* `launch(packageName, className)` 运行包名为packageName类名(Activity)为className的应用。
* `launchApp(appName)` 运存应用名称为appName的应用。例如launchApp("QQ")。不同应用名称可能相同,这时只运行其中某一个应用。
###四、在脚本中调用安卓
* `notStopped` 若当前脚本处于运行状态时返回`true`, 否则返回`false`。对于某些循环, 例如`while(true)`,请用`while(notStopped())`代替,以免死循环造成的脚本无法正常停止。
* `isStoppd` 若当前脚本处于停止状态时返回`true`, 否则返回`false`
###四、全局变量
* `context` ApplicationContext参见安卓[android.content.Context](https://developer.android.com/reference/android/content/Context.html)
> 这里的context由于是ApplicationContext是不可见的不能用于dialog和其他UI相关。如果要显示弹窗或者视图请启动UI模式代码的第一行为`"ui";`既可并使用activity代替。
* `activity` UI模式下会启动一个Activity来运行脚本并在UI线程下运行。可通过该变量来获取该activity。
###五、在脚本中调用Java
使用importClass来引入要使用的库例如:
```javascript
importClass("android.view.View.OnClickListener")

View File

@@ -1,9 +1,11 @@
click 点击
longClick 长按
scrollUp 上滑
scrollDown 下滑
toast 提示
launch 运行
launchApp 运行应用
select 选择
input 输入
sleep 暂停运行
sleep 暂停运行
notStopped 非暂停

View File

@@ -30,5 +30,11 @@
<copyright>Copyright (c) 2015 zzhoujay</copyright>
<license>MIT License</license>
</notice>
<notice>
<name>Alipay ZeroSdk</name>
<copyright>Copyright 2016 Fung Go (fython)</copyright>
<url>https://github.com/fython/AlipayZeroSdk</url>
<license>Apache Software License 2.0</license>
</notice>
</notices>

View File

@@ -51,17 +51,16 @@
<string name="text_email">邮箱</string>
<string name="my_github">https://github.com/hyb1996/NoRootScriptDroid</string>
<string name="share_app">[免Root脚本机器人]下载地址https://github.com/hyb1996/NoRootScriptDroid/releases</string>
<string name="text_assist_service">点击定位辅助服务</string>
<string name="text_assist_serivce_notification">通知栏显示点击定位开关</string>
<string name="text_assist_service_notification">通知栏显示点击定位开关</string>
<string name="text_assist_service">点击区域辅助服务</string>
<string name="text_assist_service_notification">通知栏点击区域辅助开关</string>
<string name="text_others">其他</string>
<string name="text_assist_mode_enabled">点击定位辅助服务已开启(点击关闭)</string>
<string name="text_assist_mode_disabled">点击定位辅助服务已关闭(点击开启)</string>
<string name="text_assist_mode_enabled">点击区域辅助服务已开启(点击关闭)</string>
<string name="text_assist_mode_disabled">点击区域辅助服务已关闭(点击开启)</string>
<string name="text_error_report">错误报告</string>
<string name="text_sample_hello_big_sister">大姐姐好</string>
<string name="text_sample_qq_hongbao">示例QQ自动抢红包</string>
<string name="text_press_again_to_exit">再按一次退出程序</string>
<string name="text_function">函数</string>
<string name="sorry_for_crash">\"很抱歉程序遇到未知错误,即将停止运行\\n错误代码\"</string>
<string name="text_common_function">常用函数</string>
<string name="sorry_for_crash">很抱歉(ಥ _ ಥ)程序遇到未知错误,即将停止运行\n错误代码</string>
<string name="text_no_running_script">没有正在运行的脚本</string>
<string name="text_already_stop_n_scripts">已停止%d个正在运行的脚本</string>
<string name="text_start_running">开始运行</string>
@@ -85,4 +84,13 @@
<string name="text_choose_email_app">请选择邮件应用</string>
<string name="text_assist_clip">点击定位剪贴板</string>
<string name="text_script_stopped">脚本已停止</string>
<string name="assist_mode_notice">\"点击区域辅助服务\"是在要点击的区域不是文本时使用的,参见\"语法与API\"。\"点击区域辅助服务\"只有在\"自动操作服务\"开启时才有效。</string>
<string name="text_please_choose">请选择</string>
<string name="text_crash">崩溃了o(≧口≦)o</string>
<string name="crash_feedback">点击\"退出\"退出程序(ಥ _ ಥ)或者复制调试信息反馈给开发者(≧∇≦)ノ</string>
<string name="text_cannot_create_dialog_when_app_invisible">无法在后台显示弹框,脚本已停止运行</string>
<string name="text_sample_for_qq_chat">示例QQ强制聊天</string>
<string name="text_re_import_samples">重新导入示例脚本文件</string>
<string name="text_re_import_succeed">导入成功,重新打开应用生效</string>
<string name="text_fail">失败</string>
</resources>

View File

@@ -1,6 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:title="@string/text_others">
<Preference
android:title="@string/text_re_import_samples"/>
</PreferenceCategory>
<PreferenceCategory
android:title="@string/text_about">