diff --git a/app-debug-20170127.apk b/app-debug-20170127.apk deleted file mode 100644 index 5dc4f304..00000000 Binary files a/app-debug-20170127.apk and /dev/null differ diff --git a/app/app20170205.apk b/app/app20170205.apk new file mode 100644 index 00000000..10da8c37 Binary files /dev/null and b/app/app20170205.apk differ diff --git a/app/build.gradle b/app/build.gradle index 5823e9c4..4e71c319 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -47,6 +47,7 @@ dependencies { compile('de.psdev.licensesdialog:licensesdialog:1.8.1') compile 'com.furture.react:DuktapeJava:1.1.0' compile 'com.zzhoujay.markdown:markdown:1.0.2' + compile 'moe.feng:AlipayZeroSdk:1.1' compile files('libs/JSTransformer.jar') diff --git a/app/src/main/java/com/stardust/scriptdroid/AboutActivity.java b/app/src/main/java/com/stardust/scriptdroid/AboutActivity.java index 58fcc3cb..f107f525 100644 --- a/app/src/main/java/com/stardust/scriptdroid/AboutActivity.java +++ b/app/src/main/java/com/stardust/scriptdroid/AboutActivity.java @@ -8,10 +8,13 @@ import android.support.v7.widget.Toolbar; import android.view.View; import android.widget.Toast; +import com.afollestad.materialdialogs.MaterialDialog; import com.stardust.scriptdroid.tool.IntentTool; import com.stardust.view.ViewBinder; import com.stardust.view.ViewBinding; +import moe.feng.alipay.zerosdk.AlipayZeroSdk; + /** * Created by Stardust on 2017/2/2. */ @@ -62,7 +65,22 @@ public class AboutActivity extends BaseActivity { @ViewBinding.Click(R.id.donate) private void showDonateMeDialog() { - + new MaterialDialog.Builder(this) + .title(R.string.donate) + .items("支付宝") + .itemsCallback(new MaterialDialog.ListCallback() { + @Override + public void onSelection(MaterialDialog dialog, View itemView, int position, CharSequence text) { + if (position == 0) { + if (AlipayZeroSdk.hasInstalledAlipayClient(AboutActivity.this)) { + AlipayZeroSdk.startAlipayClient(AboutActivity.this, "aex04370fwjf8angrv1te9e"); + } else { + Toast.makeText(AboutActivity.this, "未安装支付宝", Toast.LENGTH_SHORT).show(); + } + } + } + }) + .show(); } @ViewBinding.Click(R.id.share) @@ -72,12 +90,12 @@ public class AboutActivity extends BaseActivity { @ViewBinding.Click(R.id.icon) private void lol() { - Toast.makeText(this, "略略略", Toast.LENGTH_LONG).show(); + Toast.makeText(this, R.string.text_lll, Toast.LENGTH_LONG).show(); } @ViewBinding.Click(R.id.developer) private void hhh() { - Toast.makeText(this, "这是软件开发者(。・・)ノ", Toast.LENGTH_LONG).show(); + Toast.makeText(this, R.string.text_it_is_the_developer_of_app, Toast.LENGTH_LONG).show(); } private void setClipText(CharSequence label, CharSequence text) { diff --git a/app/src/main/java/com/stardust/scriptdroid/App.java b/app/src/main/java/com/stardust/scriptdroid/App.java index 39eef9df..f9a0e7b2 100644 --- a/app/src/main/java/com/stardust/scriptdroid/App.java +++ b/app/src/main/java/com/stardust/scriptdroid/App.java @@ -26,7 +26,7 @@ public class App extends Application { public void onCreate() { super.onCreate(); - Thread.setDefaultUncaughtExceptionHandler(new CrashHandler(ErrorReportActivity.class)); + Thread.currentThread().setUncaughtExceptionHandler(new CrashHandler(ErrorReportActivity.class)); instance = this; stateObserver = new StateObserver(PreferenceManager.getDefaultSharedPreferences(this)); } diff --git a/app/src/main/java/com/stardust/scriptdroid/AssistModeSwitchService.java b/app/src/main/java/com/stardust/scriptdroid/AssistModeSwitchService.java index c523d7c3..f9e43707 100644 --- a/app/src/main/java/com/stardust/scriptdroid/AssistModeSwitchService.java +++ b/app/src/main/java/com/stardust/scriptdroid/AssistModeSwitchService.java @@ -6,7 +6,7 @@ import android.content.Intent; import android.os.IBinder; import android.support.annotation.Nullable; -import com.stardust.scriptdroid.droid.runtime.action.ActionPerformService; +import com.stardust.scriptdroid.droid.assist.Assistant; import static com.stardust.scriptdroid.ui.AssistModeSwitchNotification.KEY_ASSIST_MODE_NOTIFICATION; @@ -29,7 +29,7 @@ public class AssistModeSwitchService extends Service { String action = intent.getStringExtra("switch"); if (action != null) { if (action.equals("assistMode")) { - ActionPerformService.setAssistModeEnable(!ActionPerformService.isAssistModeEnable()); + Assistant.setAssistModeEnable(!Assistant.isAssistModeEnable()); } else { App.getStateObserver().setState(KEY_ASSIST_MODE_NOTIFICATION, false); } diff --git a/app/src/main/java/com/stardust/scriptdroid/DocumentActivity.java b/app/src/main/java/com/stardust/scriptdroid/DocumentActivity.java index 5b9b7ee6..11162c53 100644 --- a/app/src/main/java/com/stardust/scriptdroid/DocumentActivity.java +++ b/app/src/main/java/com/stardust/scriptdroid/DocumentActivity.java @@ -31,7 +31,7 @@ public class DocumentActivity extends BaseActivity { markdownView.loadMarkdown(FileUtils.readString(getResources().openRawResource(R.raw.document))); } catch (Exception e) { e.printStackTrace(); - markdownView.setText("文档加载失败/(ㄒoㄒ)/~~"); + markdownView.setText(R.string.text_load_failed); } } diff --git a/app/src/main/java/com/stardust/scriptdroid/EditActivity.java b/app/src/main/java/com/stardust/scriptdroid/EditActivity.java index c5c5569b..86f2d2e8 100644 --- a/app/src/main/java/com/stardust/scriptdroid/EditActivity.java +++ b/app/src/main/java/com/stardust/scriptdroid/EditActivity.java @@ -5,13 +5,14 @@ import android.content.Intent; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.design.widget.Snackbar; +import android.support.v4.view.GravityCompat; +import android.support.v4.widget.DrawerLayout; import android.support.v7.widget.Toolbar; import android.util.SparseArray; import android.view.View; import com.afollestad.materialdialogs.DialogAction; import com.afollestad.materialdialogs.MaterialDialog; -import com.jecelyin.editor.v2.Pref; import com.jecelyin.editor.v2.common.Command; import com.jecelyin.editor.v2.common.SaveListener; import com.jecelyin.editor.v2.ui.EditorDelegate; @@ -20,6 +21,9 @@ 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; +import com.stardust.scriptdroid.ui.FunctionListRecyclerView; import com.stardust.scriptdroid.widget.ToolbarMenuItem; import com.stardust.util.SparseArrayEntries; import com.stardust.view.ViewBinder; @@ -33,6 +37,8 @@ import java.io.File; public class EditActivity extends Editor920Activity { + private static final String KEY_EDIT_ACTIVITY_FIRST_USE = "KEY_EDIT_ACTIVITY_FIRST_USE"; + public static void editFile(Context context, String path) { editFile(context, null, path); } @@ -46,6 +52,7 @@ public class EditActivity extends Editor920Activity { private String mName; private File mFile; private View mView; + private DrawerLayout mDrawerLayout; private EditorDelegate mEditorDelegate; private SparseArray mMenuMap; @@ -57,6 +64,24 @@ public class EditActivity extends Editor920Activity { setUpEditor(); } + @Override + protected void onStart() { + super.onStart(); + openDrawerIfFirstUse(); + } + + private void openDrawerIfFirstUse() { + if (Pref.def().getBoolean(KEY_EDIT_ACTIVITY_FIRST_USE, true)) { + mDrawerLayout.postDelayed(new Runnable() { + @Override + public void run() { + mDrawerLayout.openDrawer(GravityCompat.END); + } + }, 1000); + Pref.def().edit().putBoolean(KEY_EDIT_ACTIVITY_FIRST_USE, false).apply(); + } + } + private void handleIntent() { String path = getIntent().getStringExtra("path"); mName = getIntent().getStringExtra("name"); @@ -73,15 +98,35 @@ public class EditActivity extends Editor920Activity { private void setUpUI() { setTheme(R.style.EditorTheme); mView = View.inflate(this, R.layout.activity_edit, null); + mDrawerLayout = (DrawerLayout) mView.findViewById(R.id.drawer_layout); setContentView(mView); - initMenuItem(); + initSideMenuFragment(); setUpToolbar(); + initMenuItem(); ViewBinder.bind(this); } + private void initSideMenuFragment() { + EditSideMenuFragment.setFragment(EditActivity.this, R.id.fragment_edit_side_menu) + .setOnFunctionClickListener(new FunctionListRecyclerView.OnFunctionClickListener() { + @Override + public void onClick(FunctionListRecyclerView.Function function, int position) { + insertText(function.name); + mDrawerLayout.closeDrawer(GravityCompat.END); + } + }) + .setOnClipClickListener(new AssistClipListRecyclerView.OnClipClickListener() { + @Override + public void onClick(String clip, int position) { + insertText(clip); + mDrawerLayout.closeDrawer(GravityCompat.END); + } + }); + + } + private void setUpEditor() { if (mFile != null) { - Pref.getInstance(this).setReadOnly(false); mEditorDelegate = new EditorDelegate(0, mFile, 0, null); EditorView editorView = (EditorView) findViewById(R.id.editor); mEditorDelegate.setEditorView(editorView); @@ -127,7 +172,7 @@ public class EditActivity extends Editor920Activity { } private void run() { - Snackbar.make(mView, "开始运行", Snackbar.LENGTH_SHORT).show(); + Snackbar.make(mView, R.string.text_start_running, Snackbar.LENGTH_SHORT).show(); setMenuStatus(R.id.run, MenuDef.STATUS_DISABLED); Droid.getInstance().runScriptFile(mFile, new Droid.OnRunFinishedListener() { @Override @@ -137,7 +182,7 @@ public class EditActivity extends Editor920Activity { public void run() { setMenuStatus(R.id.run, MenuDef.STATUS_NORMAL); if (e != null) - Snackbar.make(mView, "错误: " + e.getMessage(), Snackbar.LENGTH_INDEFINITE).show(); + Snackbar.make(mView, getString(R.string.text_error) + ": " + e.getMessage(), Snackbar.LENGTH_INDEFINITE).show(); } }); } @@ -211,4 +256,8 @@ public class EditActivity extends Editor920Activity { .show(); } + @Override + public void doCommand(Command command) { + mEditorDelegate.doCommand(command); + } } diff --git a/app/src/main/java/com/stardust/scriptdroid/ErrorReportActivity.java b/app/src/main/java/com/stardust/scriptdroid/ErrorReportActivity.java index f4c1ff98..62cf892b 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ErrorReportActivity.java +++ b/app/src/main/java/com/stardust/scriptdroid/ErrorReportActivity.java @@ -36,8 +36,8 @@ public class ErrorReportActivity extends BaseActivity { final String errorDetail = getIntent().getStringExtra("error"); new MaterialDialog.Builder(this) .content(message) - .positiveText("退出") - .negativeText("复制调试信息") + .positiveText(R.string.text_exit) + .negativeText(R.string.text_copy_debug_info) .onPositive(new MaterialDialog.SingleButtonCallback() { @Override public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) { diff --git a/app/src/main/java/com/stardust/scriptdroid/MainActivity.java b/app/src/main/java/com/stardust/scriptdroid/MainActivity.java index b1bca0cb..e09f3d99 100644 --- a/app/src/main/java/com/stardust/scriptdroid/MainActivity.java +++ b/app/src/main/java/com/stardust/scriptdroid/MainActivity.java @@ -88,7 +88,7 @@ public class MainActivity extends BaseActivity implements FileChooserDialog.File private void setUpUI() { mDrawerLayout = (DrawerLayout) View.inflate(this, R.layout.activity_main, null); setContentView(mDrawerLayout); - SlideMenuFragment.init(this, R.id.fragment_slide_menu); + SlideMenuFragment.setFragment(this, R.id.fragment_slide_menu); mAddFilePanel = $(R.id.bottom_menu); setUpToolbar(); diff --git a/app/src/main/java/com/stardust/scriptdroid/droid/Droid.java b/app/src/main/java/com/stardust/scriptdroid/droid/Droid.java index 52f336f7..f9e989ec 100644 --- a/app/src/main/java/com/stardust/scriptdroid/droid/Droid.java +++ b/app/src/main/java/com/stardust/scriptdroid/droid/Droid.java @@ -1,5 +1,7 @@ package com.stardust.scriptdroid.droid; +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; @@ -24,7 +26,7 @@ public class Droid { @Override public void onRunFinished(Object result, Exception e) { if (e != null) { - RUNTIME.toast("错误: " + e.getMessage()); + RUNTIME.toast(App.getApp().getString(R.string.text_error) + ": " + e.getMessage()); } } }; @@ -59,7 +61,7 @@ public class Droid { public void runScript(final String script, OnRunFinishedListener listener, RunningConfig config) { if (config.runInNewThread) { new Thread(new RunScriptRunnable(script, listener, config)).start(); - }else { + } else { new RunScriptRunnable(script, listener, config).run(); } @@ -70,6 +72,11 @@ 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"); diff --git a/app/src/main/java/com/stardust/scriptdroid/droid/assist/AssistClipList.java b/app/src/main/java/com/stardust/scriptdroid/droid/assist/AssistClipList.java new file mode 100644 index 00000000..1dc779be --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/droid/assist/AssistClipList.java @@ -0,0 +1,25 @@ +package com.stardust.scriptdroid.droid.assist; + +/** + * Created by Stardust on 2017/2/4. + */ + +public interface AssistClipList { + + interface OnClipChangedListener { + void onClipRemove(int position); + + void onClipInsert(int position); + + void onChange(); + } + + int size(); + + String get(int i); + + void add(String clip); + + void setOnClipChangedListener(OnClipChangedListener listener); + +} diff --git a/app/src/main/java/com/stardust/scriptdroid/droid/assist/Assistant.java b/app/src/main/java/com/stardust/scriptdroid/droid/assist/Assistant.java new file mode 100644 index 00000000..c6297ca4 --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/droid/assist/Assistant.java @@ -0,0 +1,65 @@ +package com.stardust.scriptdroid.droid.assist; + +import android.graphics.Rect; +import android.preference.PreferenceManager; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityNodeInfo; +import android.widget.Toast; + +import com.stardust.scriptdroid.App; + + +/** + * Created by Stardust on 2017/2/4. + */ + +public class Assistant { + public static final String KEY_ASSIST_MODE_ENABLE = "ASSIST_MODE_ENABLE"; + + + private static boolean assistModeEnable; + private static AssistClipList assistClipList = SharedPrefAssistClipList.getInstance(); + + public static boolean isAssistModeEnable() { + return assistModeEnable; + } + + public static void setAssistModeEnable(boolean assistModeEnable) { + Assistant.assistModeEnable = assistModeEnable; + App.getStateObserver().setState(KEY_ASSIST_MODE_ENABLE, assistModeEnable); + } + + public static void performAssistance(AccessibilityEvent event) { + if (!assistModeEnable) { + return; + } + if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_CLICKED || event.getEventType() == AccessibilityEvent.TYPE_VIEW_LONG_CLICKED) { + AccessibilityNodeInfo nodeInfo = event.getSource(); + if (nodeInfo == null) { + return; + } + nodeInfo.refresh(); + Rect rect = getBoundsInScreen(nodeInfo); + saveAndAlertBounds(rect); + nodeInfo.recycle(); + } + } + + private 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); + assistClipList.add(str); + Toast.makeText(App.getApp(), str, Toast.LENGTH_SHORT).show(); + } + + + static { + assistModeEnable = PreferenceManager.getDefaultSharedPreferences(App.getApp()).getBoolean(KEY_ASSIST_MODE_ENABLE, false); + } + +} diff --git a/app/src/main/java/com/stardust/scriptdroid/droid/assist/SharedPrefAssistClipList.java b/app/src/main/java/com/stardust/scriptdroid/droid/assist/SharedPrefAssistClipList.java new file mode 100644 index 00000000..aeec9f82 --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/droid/assist/SharedPrefAssistClipList.java @@ -0,0 +1,89 @@ +package com.stardust.scriptdroid.droid.assist; + +import android.content.Context; +import android.content.SharedPreferences; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.stardust.scriptdroid.App; + +import java.lang.reflect.Type; +import java.util.LinkedList; +import java.util.List; + +/** + * Created by Stardust on 2017/2/4. + */ + +public class SharedPrefAssistClipList implements AssistClipList { + + private static final Gson GSON = new Gson(); + + + private static SharedPrefAssistClipList instance = new SharedPrefAssistClipList(App.getApp()); + private OnClipChangedListener mOnClipChangedListener; + + public static SharedPrefAssistClipList getInstance() { + return instance; + } + + private static final int MAX_SIZE = 10; + private static final String SHARED_PREF_NAME = "SharedPrefAssistClipList"; + private SharedPreferences mSharedPreferences; + private List mAssistClipList = new LinkedList<>(); + + public SharedPrefAssistClipList(Context context) { + mSharedPreferences = context.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE); + readFromSharedPref(); + } + + private void readFromSharedPref() { + Type type = new TypeToken>() { + }.getType(); + List l = GSON.fromJson(mSharedPreferences.getString(SHARED_PREF_NAME, ""), type); + if (l != null) + mAssistClipList.addAll(l); + } + + @Override + public synchronized int size() { + return mAssistClipList.size(); + } + + @Override + public synchronized String get(int i) { + return mAssistClipList.get(i); + } + + @Override + public synchronized void add(String clip) { + mAssistClipList.add(0, clip); + notifyInsert(); + if (mAssistClipList.size() > MAX_SIZE) { + mAssistClipList.remove(mAssistClipList.size() - 1); + notifyRemove(); + } + syncWithSharedPref(); + } + + private void notifyRemove() { + if (mOnClipChangedListener != null) + mOnClipChangedListener.onClipRemove(mAssistClipList.size()); + } + + private void notifyInsert() { + if (mOnClipChangedListener != null) { + mOnClipChangedListener.onClipInsert(0); + } + } + + @Override + public void setOnClipChangedListener(OnClipChangedListener listener) { + mOnClipChangedListener = listener; + } + + private void syncWithSharedPref() { + mSharedPreferences.edit().putString(SHARED_PREF_NAME, GSON.toJson(mAssistClipList)).apply(); + } + +} 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 33f1175b..dc734982 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 @@ -12,6 +12,7 @@ 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; @@ -32,6 +33,7 @@ public class DroidRuntime implements IDroidRuntime { private final Object mLock = new Object(); private boolean mActionPerformResult; + private boolean mActionPerformResultUpToDate; private Handler mUIHandler; public static DroidRuntime getRuntime() { @@ -143,17 +145,22 @@ public class DroidRuntime implements IDroidRuntime { toast(App.getApp().getString(R.string.text_no_accessibility_permission)); throw new PermissionDeniedException(App.getApp().getString(R.string.text_no_accessibility_permission)); } + ensureNotStopped(); ActionPerformService.setAction(action); synchronized (mLock) { try { mLock.wait(); } catch (InterruptedException e) { - e.printStackTrace(); + throw new PermissionDeniedException("已停止运行"); } } return mActionPerformResult; } + private void ensureNotStopped() { + Droid.getInstance().ensureNotStopped(); + } + @Override public void toast(final String text) { 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 index 0caccb08..b90764b0 100644 --- 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 @@ -1,17 +1,13 @@ package com.stardust.scriptdroid.droid.runtime.action; import android.accessibilityservice.AccessibilityService; -import android.content.ClipData; -import android.content.ClipboardManager; -import android.graphics.Rect; import android.os.Build; -import android.preference.PreferenceManager; import android.util.Log; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; -import android.widget.Toast; import com.stardust.scriptdroid.App; +import com.stardust.scriptdroid.droid.assist.Assistant; import com.stardust.scriptdroid.droid.runtime.DroidRuntime; import com.stardust.view.accessibility.AccessibilityServiceUtils; @@ -28,7 +24,6 @@ import java.util.List; public class ActionPerformService extends AccessibilityService { private static final String TAG = "ActionPerformService"; - public static final String KEY_ASSIST_MODE_ENABLE = "ASSIST_MODE_ENABLE"; private static ActionPerformService instance; @SuppressWarnings("unchecked") @@ -39,9 +34,6 @@ public class ActionPerformService extends AccessibilityService { public static final List actions = new ArrayList<>(); private static int state = STATE_INACTIVE; - private static boolean assistModeEnable = false; - - public static void setActions(Collection collection) { synchronized (actions) { actions.clear(); @@ -58,19 +50,10 @@ public class ActionPerformService extends AccessibilityService { return instance; } - public static boolean isAssistModeEnable() { - return assistModeEnable; - } - - public static void setAssistModeEnable(boolean assistModeEnable) { - ActionPerformService.assistModeEnable = assistModeEnable; - App.getStateObserver().setState(KEY_ASSIST_MODE_ENABLE, assistModeEnable); - } - @Override public void onAccessibilityEvent(AccessibilityEvent event) { Log.v(TAG, "onAccessibilityEvent: state=" + state + " event=" + event); - performAssistance(event); + Assistant.performAssistance(event); if (state == STATE_INACTIVE) return; AccessibilityNodeInfo root = getRootInActiveWindow(); @@ -108,27 +91,6 @@ public class ActionPerformService extends AccessibilityService { } } - private void performAssistance(AccessibilityEvent event) { - if (!assistModeEnable) { - return; - } - if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_CLICKED || event.getEventType() == AccessibilityEvent.TYPE_VIEW_LONG_CLICKED) { - AccessibilityNodeInfo nodeInfo = event.getSource(); - if (nodeInfo == null) { - return; - } - nodeInfo.refresh(); - Log.v(TAG, "click: " + nodeInfo); - Rect rect = new Rect(); - nodeInfo.getBoundsInScreen(rect); - String str = rect.toString().replace('-', ',').replace(" ", "").substring(4); - ClipboardManager manager = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE); - manager.setPrimaryClip(ClipData.newPlainText("", str)); - Toast.makeText(this, str, Toast.LENGTH_SHORT).show(); - nodeInfo.recycle(); - } - } - @Override public void onInterrupt() { @@ -140,10 +102,6 @@ public class ActionPerformService extends AccessibilityService { instance = this; } - static { - assistModeEnable = PreferenceManager.getDefaultSharedPreferences(App.getApp()).getBoolean(KEY_ASSIST_MODE_ENABLE, false); - } - public static void disable() { if (instance != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { instance.disableSelf(); 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 abf4f662..b7b97d65 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 @@ -1,18 +1,15 @@ package com.stardust.scriptdroid.droid.script; -import android.util.Pair; - 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.runtime.api.IDroidRuntime; import java.io.IOException; import java.io.StringReader; -import java.util.ArrayList; import java.util.HashMap; -import java.util.Iterator; -import java.util.List; +import java.util.Hashtable; import java.util.Map; /** @@ -22,7 +19,7 @@ import java.util.Map; public class DuktapeJavaScriptEngine implements JavaScriptEngine { - private final List> mDuktapeEngineList = new ArrayList<>(); + private final Map mThreadDuktapeEngineMap = new Hashtable<>(); private static final String INIT_SCRIPT; private Map mVariableMap = new HashMap<>(); @@ -53,10 +50,10 @@ public class DuktapeJavaScriptEngine implements JavaScriptEngine { try { result = duktapeEngine.execute(JSTransformer.parse(new StringReader(script))); } catch (IOException e) { - remove(duktapeEngine); + remove(Thread.currentThread()); throw e; } - remove(duktapeEngine); + remove(Thread.currentThread()); return result; } @@ -69,33 +66,26 @@ public class DuktapeJavaScriptEngine implements JavaScriptEngine { } - private void remove(DuktapeEngine duktapeEngine) { - duktapeEngine.destory(); - synchronized (mDuktapeEngineList) { - Iterator> iterator = mDuktapeEngineList.iterator(); - while (iterator.hasNext()) { - Pair pair = iterator.next(); - if (pair.first == duktapeEngine) { - stop(pair.first, pair.second); - } - iterator.remove(); - break; - } + private void remove(Thread thread) { + synchronized (mThreadDuktapeEngineMap) { + DuktapeEngine engine = mThreadDuktapeEngineMap.remove(thread); + stop(engine, thread); } } private void stop(DuktapeEngine engine, Thread thread) { + if (engine != null) + engine.destory(); try { thread.interrupt(); } catch (Exception e) { e.printStackTrace(); } - engine.destory(); } private void add(DuktapeEngine duktapeEngine, Thread thread) { - synchronized (mDuktapeEngineList) { - mDuktapeEngineList.add(0, new Pair<>(duktapeEngine, thread)); + synchronized (mThreadDuktapeEngineMap) { + mThreadDuktapeEngineMap.put(thread, duktapeEngine); } } @@ -107,14 +97,20 @@ public class DuktapeJavaScriptEngine implements JavaScriptEngine { @Override public int stopAll() { int n; - synchronized (mDuktapeEngineList) { - for (Pair pair : mDuktapeEngineList) { - stop(pair.first, pair.second); + synchronized (mThreadDuktapeEngineMap) { + for (Map.Entry entry : mThreadDuktapeEngineMap.entrySet()) { + stop(entry.getValue(), entry.getKey()); } - n = mDuktapeEngineList.size(); - mDuktapeEngineList.clear(); + n = mThreadDuktapeEngineMap.size(); + mThreadDuktapeEngineMap.clear(); } return n; } + @Override + public void ensureNotStopped() { + if (!mThreadDuktapeEngineMap.containsKey(Thread.currentThread())) { + throw new RuntimeException(App.getApp().getString(R.string.text_script_stopped)); + } + } } diff --git a/app/src/main/java/com/stardust/scriptdroid/droid/script/JavaScriptEngine.java b/app/src/main/java/com/stardust/scriptdroid/droid/script/JavaScriptEngine.java index 67270183..37ee0ea0 100644 --- a/app/src/main/java/com/stardust/scriptdroid/droid/script/JavaScriptEngine.java +++ b/app/src/main/java/com/stardust/scriptdroid/droid/script/JavaScriptEngine.java @@ -17,6 +17,8 @@ public interface JavaScriptEngine { int stopAll(); + void ensureNotStopped(); + class Init { public static final String INIT_SCRIPT = readInitScript(); diff --git a/app/src/main/java/com/stardust/scriptdroid/droid/script/file/ScriptFile.java b/app/src/main/java/com/stardust/scriptdroid/droid/script/file/ScriptFile.java index 70ab32aa..8630f25f 100644 --- a/app/src/main/java/com/stardust/scriptdroid/droid/script/file/ScriptFile.java +++ b/app/src/main/java/com/stardust/scriptdroid/droid/script/file/ScriptFile.java @@ -2,6 +2,8 @@ package com.stardust.scriptdroid.droid.script.file; import android.os.Environment; +import com.stardust.scriptdroid.App; +import com.stardust.scriptdroid.R; import com.stardust.scriptdroid.droid.Droid; import java.io.File; @@ -12,7 +14,7 @@ import java.io.File; public class ScriptFile { - public static final String DEFAULT_FOLDER = Environment.getExternalStorageDirectory() + "/脚本/"; + public static final String DEFAULT_FOLDER = Environment.getExternalStorageDirectory() + App.getApp().getString(R.string.folder_name); public String name; public String path; diff --git a/app/src/main/java/com/stardust/scriptdroid/editor920/Editor920Activity.java b/app/src/main/java/com/stardust/scriptdroid/editor920/Editor920Activity.java index 81a5c5a8..6cb40c7e 100644 --- a/app/src/main/java/com/stardust/scriptdroid/editor920/Editor920Activity.java +++ b/app/src/main/java/com/stardust/scriptdroid/editor920/Editor920Activity.java @@ -37,7 +37,6 @@ public class Editor920Activity extends IActivity { public void doCommand(Command command) { } - @Override public void openFile(String s, String s1, int i) { @@ -54,8 +53,10 @@ public class Editor920Activity extends IActivity { } @Override - public void insertText(CharSequence charSequence) { - + public void insertText(CharSequence text) { + Command c = new Command(Command.CommandEnum.INSERT_TEXT); + c.object = text; + doCommand(c); } @Override diff --git a/app/src/main/java/com/stardust/scriptdroid/file/FileChooser.java b/app/src/main/java/com/stardust/scriptdroid/file/FileChooser.java index 87f2f570..d10d0989 100644 --- a/app/src/main/java/com/stardust/scriptdroid/file/FileChooser.java +++ b/app/src/main/java/com/stardust/scriptdroid/file/FileChooser.java @@ -6,6 +6,8 @@ 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; @@ -44,7 +46,7 @@ public class FileChooser { intent.setType(mimeType); intent.addCategory(Intent.CATEGORY_OPENABLE); try { - mActivity.startActivityForResult(Intent.createChooser(intent, "选择一个文件"), FILE_CHOOSE); + mActivity.startActivityForResult(Intent.createChooser(intent, mActivity.getString(R.string.text_choose_file)), FILE_CHOOSE); } catch (ActivityNotFoundException ex) { handler.handle(ex, mimeType); } diff --git a/app/src/main/java/com/stardust/scriptdroid/shortcut/ShortcutHelper.java b/app/src/main/java/com/stardust/scriptdroid/shortcut/ShortcutHelper.java deleted file mode 100644 index e80ba7ff..00000000 --- a/app/src/main/java/com/stardust/scriptdroid/shortcut/ShortcutHelper.java +++ /dev/null @@ -1,418 +0,0 @@ -package com.stardust.scriptdroid.shortcut; - -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.ProviderInfo; -import android.content.pm.ResolveInfo; -import android.database.Cursor; -import android.graphics.Bitmap; -import android.net.Uri; -import android.os.Build; -import android.os.Parcelable; -import android.text.TextUtils; -import android.util.Log; - -import com.stardust.scriptdroid.R; - -import java.util.ArrayList; -import java.util.List; - -public class ShortcutHelper { - public final static String TAG = ShortcutHelper.class.getSimpleName(); - public static final String ACTION_DESKTOP_LINK = "com.scu.zqc.action.SHORTCUT"; - public static final String READ_SETTINGS = "com.android.launcher.permission.READ_SETTINGS"; - public static final String ACTION_INSTALL_SHORTCUT = "com.android.launcher.action.INSTALL_SHORTCUT"; - public static final String ACTION_UNINSTALL_SHORTCUT = "com.android.launcher.action.UNINSTALL_SHORTCUT"; - public static final String MAIN_ACTIVITY = "com.scu.shortcut.MainActivity"; - public static final String APP_STORE_URL = "http://m.app.so.com/?src=browser"; - public static final String EXTRA_DUPLICATE = "duplicate"; - - public static void addShortCut(final Context context, Bitmap src) { - String appStoreShortcutName = context.getString(R.string.app_name); - if (getIsAddShortCut(context, appStoreShortcutName)) { -// uninstallShortcut(context, appStoreShortcutName); - try { - int size = (int) context.getResources().getDimension(android.R.dimen.app_icon_size); - Bitmap scaledBitmap = Bitmap.createScaledBitmap(src, size, size, true); - createFavLinkShortCut(context, appStoreShortcutName, APP_STORE_URL, scaledBitmap, false, true); - } catch (Exception e) { - } - } - } - - public static boolean uninstallShortcut(Context context, String name, Intent shortCut) { - Intent intent = new Intent(ACTION_UNINSTALL_SHORTCUT); - intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortCut); - intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, name); - context.sendBroadcast(intent); - return true; - } - - public static boolean createFavLinkShortCut(Context context, String name, String url, Parcelable icon, - boolean isSendToQihooDesktop, boolean skipCheckExist) { - if (context == null || TextUtils.isEmpty(url) || TextUtils.isEmpty(name) || icon == null) { - return false; - } - // 先查询launcher页面是否已经生成其快捷方式 - if (getIsAddShortCut(context, name) && !skipCheckExist) { - return false; - } - - Intent shortcutIntent = getShortCutIntent(context, url, MAIN_ACTIVITY); - shortcutIntent.setAction(ACTION_DESKTOP_LINK); - shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - Intent installIntent = getInstallIntent(shortcutIntent, name, icon); - - // 将创建快捷方式的intent指定到桌面应用程序包来处理. - String deskPackageName = getLauncherPackageName(context); - if (null != deskPackageName && !TextUtils.isEmpty(deskPackageName)) { - installIntent.setPackage(deskPackageName); - } - - if (isSendToQihooDesktop) { - installIntent.putExtra("from", context.getPackageName()); - } - - context.sendBroadcast(installIntent); - return true; - } - - /** - * 获取正在运行桌面包名(注:存在多个桌面时且未指定默认桌面时,该方法返回Null,使用时需处理这个情况) - */ - public static String getLauncherPackageName(Context context) { - try { - final Intent intent = new Intent(Intent.ACTION_MAIN); - intent.addCategory(Intent.CATEGORY_HOME); - final ResolveInfo res = context.getPackageManager().resolveActivity(intent, 0); - if (res != null && res.activityInfo == null) { - // should not happen. A home is always installed, isn't it? - return null; - } - - if (res != null && ("android").equals(res.activityInfo.packageName)) { - // 有多个桌面程序存在,且未指定默认项时; - return null; - } else { - return res.activityInfo.packageName; - } - } catch (Exception e) { - - } - - return null; - } - - private static Intent getInstallIntent(Context context, Intent shortcutIntent, int name, int res) { - Intent intent = getInstallIntent(shortcutIntent, context.getString(name), null); - Parcelable icon = Intent.ShortcutIconResource.fromContext(context, res); - intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, icon); - return intent; - } - - private static Intent getInstallIntent(Intent shortcutIntent, String name, Parcelable iconResource) { - Intent intent = new Intent(ACTION_INSTALL_SHORTCUT); - intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); - - if (TextUtils.isEmpty(name)) { - if (Build.VERSION.SDK_INT < 11 || "SM-N9008V".equals(Build.MODEL)) { - intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, "添加"); - } else { - intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, "\t"); - } - } else { - intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, name); - } - if (iconResource != null) { - intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, iconResource); - } - intent.putExtra(EXTRA_DUPLICATE, false); - return intent; - } - - //判断应用是否安装 - public static boolean isPkgInstalled(Context c, String pkgName) { - PackageManager mPm = c.getPackageManager(); - if (mPm == null) { - return false; - } - PackageInfo pkginfo = null; - try { - pkginfo = mPm.getPackageInfo(pkgName, 0); - } catch (PackageManager.NameNotFoundException e) { - //e.printStackTrace(); - } - return pkginfo == null ? false : true; - } - - public static Intent getShortCutIntent(Context context, String action, String className) { - Intent shortcutIntent = new Intent(Intent.ACTION_MAIN); - if ("NX511J".equals(Build.MODEL)) { - shortcutIntent.setPackage(context.getPackageName()); - } else { - shortcutIntent.setClassName(context, className); - } - shortcutIntent.setData(Uri.parse(action)); - shortcutIntent.putExtra("value", "test"); - return shortcutIntent; - } - - public static boolean createShortCutWithIntentInSilence(Context context, String name, Intent shortCutIntent, Parcelable icon, boolean isSendToQihooDesktop) { - if (context == null || TextUtils.isEmpty(name) || icon == null) { - return false; - } - // 先查询launcher页面是否已经生成其快捷方式 - if (getIsAddShortCut(context, name)) { - return false; - } - Intent installIntent = getInstallIntent(shortCutIntent, name, icon); - // 将创建快捷方式的intent指定到桌面应用程序包来处理. - String deskPackageName = getLauncherPackageName(context); - if (null != deskPackageName && !TextUtils.isEmpty(deskPackageName)) { - installIntent.setPackage(deskPackageName); - } - if (isSendToQihooDesktop) { - installIntent.putExtra("from", context.getPackageName()); - } - context.sendBroadcast(installIntent); - return true; - } - - public static boolean createFavLinkShortCutWithShortcutIntent(Context context, String name, String url, Parcelable icon, - boolean isSendToQihooDesktop, boolean skipCheckExist, Intent shortcutIntent) { - - if (context == null || TextUtils.isEmpty(url) || TextUtils.isEmpty(name) || icon == null) { - return false; - } - - // 先查询launcher页面是否已经生成其快捷方式 - if (getIsAddShortCut(context, name) && !skipCheckExist) { - return false; - } - - Intent installIntent = getInstallIntent(shortcutIntent, name, icon); - - // 将创建快捷方式的intent指定到桌面应用程序包来处理. - String deskPackageName = getLauncherPackageName( - context); - - if (null != deskPackageName && !TextUtils.isEmpty(deskPackageName)) { - installIntent.setPackage(deskPackageName); - } - - if (isSendToQihooDesktop) { - installIntent.putExtra("from", context.getPackageName()); - } - - context.sendBroadcast(installIntent); - return true; - } - - public static boolean getIsAddShortCut(Context context, String name) { - // 如果只是按照title来比较是否存在的话可能存在重名应用,所以还需要根据intent这个字段一起判断。 - String intentTag = "com.scu.zqc"; - Cursor c = null; - try { - final ContentResolver cr = context.getContentResolver(); - String AUTHORITY = getAuthority(context); - Log.d(TAG, "AUTHORITY = " + AUTHORITY); - - if (null == AUTHORITY) { - AUTHORITY = getSuitableAuthority(context); - } - - final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/favorites?notify=true"); - c = cr.query(CONTENT_URI, new String[]{"title", "iconResource"}, - "title=? and intent like ?", new String[]{name, "%" + intentTag + "%"}, null); - - if (null != c && c.getCount() > 0) { - Log.d(TAG, "the shortCut of" + name + "has been created!"); - return true; - } else { - if (c != null) { - c.close(); - } - // 有的手机上需要用下面的方法才能获取到快捷方式是否存在 - AUTHORITY = getAuthorityFromPermission(context, READ_SETTINGS); - final Uri CONTENT_URI_AUTHORITY = Uri.parse("content://" + AUTHORITY + - "/favorites?notify=true"); - c = cr.query(CONTENT_URI_AUTHORITY, new String[]{"title", "iconResource"}, - "title=? and intent like ?", new String[]{name, "%" + intentTag + "%"}, null); - - if (null != c && c.getCount() > 0) { - Log.d(TAG, "the shortCut of" + name + "has been created!"); - return true; - } - } - } catch (Exception e) { - Log.e(TAG, "exception: " + e.getMessage()); - return getIsAddShortCutFromPermission(context, name); - } finally { - if (c != null) { - c.close(); - } - } - - return false; - } - - private static boolean getIsAddShortCutFromPermission(Context context, String name) { - Cursor c = null; - String intentTag = context.getPackageName(); - String AUTHORITY = getAuthorityFromPermission(context, READ_SETTINGS); - try { - final ContentResolver cr = context.getContentResolver(); - final Uri CONTENT_URI_AUTHORITY = Uri.parse("content://" + AUTHORITY + - "/favorites?notify=true"); - c = cr.query(CONTENT_URI_AUTHORITY, new String[]{"title", "iconResource"}, - "title=? and intent like ?", new String[]{name, "%" + intentTag + "%"}, null); - if (null != c && c.getCount() > 0) { - Log.d(TAG, "the shortCut of" + name + "has been created!"); - return true; - } - } catch (Exception e) { - // : handle exception - Log.e(TAG, "exception: " + e.getMessage()); - } finally { - if (null != c) { - c.close(); - } - } - - return false; - } - - /** - * 通过permission来找不同机型的Authority - * - * @return - */ - public static String getAuthority(Context context) { - String authority = ".launcher.settings"; - String authority2 = ".launcher2.settings"; - String authority3 = ".launcher3.settings"; - List packs = null; - try { - packs = context.getPackageManager().getInstalledPackages( - PackageManager.GET_PROVIDERS); - - for (PackageInfo pack : packs) { - ProviderInfo[] providers = pack.providers; - - if (null != providers) { - for (ProviderInfo provider : providers) { - if (!TextUtils.isEmpty(provider.authority) && (provider.authority.contains(authority) || - provider.authority.contains(authority2) || - provider.authority.contains(authority3))) { - return provider.authority; - } - } - } - } - } catch (OutOfMemoryError e) { - e.printStackTrace(); - packs = null; - } - return null; - } - - private static String getAuthorityFromPermission(Context context, - String permission) { - if (permission == null) { - return null; - } - try { - List packs = context.getPackageManager() - .getInstalledPackages(PackageManager.GET_PROVIDERS); - - if (packs != null) { - for (PackageInfo pack : packs) { - ProviderInfo[] providers = pack.providers; - - if (providers != null) { - for (ProviderInfo provider : providers) { - if (permission.equals(provider.readPermission)) { - return provider.authority; - } - - if (permission.equals(provider.writePermission)) { - return provider.authority; - } - } - } - } - } - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - - /** - * 获取合适的Authority访问launcher数据库
- * 优先级:".launcher3.settings" > ".launcher2.settings" > ".launcher.settings" > ".settings" - */ - public static String getSuitableAuthority(Context context) { - String AUTHORITY = null; - String authority = ".launcher.settings"; - String authority2 = ".launcher2.settings"; - String authority3 = ".launcher3.settings"; - String authority4 = ".settings"; - - List packs = context.getPackageManager().getInstalledPackages( - PackageManager.GET_PROVIDERS); - - List authorityList = new ArrayList(); - for (PackageInfo pack : packs) { - ProviderInfo[] providers = pack.providers; - - if (null != providers) { - for (ProviderInfo provider : providers) { - if (!TextUtils.isEmpty(provider.authority) && (provider.authority.contains(authority) - || provider.authority.contains(authority2) || - provider.authority.contains(authority3))) { - authorityList.add(provider.authority); - } - } - } - } - String AUTHORITY_TEMP_1 = null; - String AUTHORITY_TEMP_2 = null; - String AUTHORITY_TEMP_3 = null; - - for (String item : authorityList) { - if (item.contains(authority3) && TextUtils.isEmpty(AUTHORITY_TEMP_3)) { - AUTHORITY_TEMP_3 = item; - } else if (item.contains(authority2) && TextUtils.isEmpty(AUTHORITY_TEMP_2)) { - AUTHORITY_TEMP_2 = item; - } else if (item.contains(authority) && TextUtils.isEmpty(AUTHORITY_TEMP_1)) { - AUTHORITY_TEMP_1 = item; - } - } - if (!TextUtils.isEmpty(AUTHORITY_TEMP_3)) { - AUTHORITY = AUTHORITY_TEMP_3;//优先适配launcher3 - } else if (!TextUtils.isEmpty(AUTHORITY_TEMP_2)) { - AUTHORITY = AUTHORITY_TEMP_2; - } else if (!TextUtils.isEmpty(AUTHORITY_TEMP_1)) { - AUTHORITY = AUTHORITY_TEMP_1; - } - if (TextUtils.isEmpty(AUTHORITY)) { - for (PackageInfo pack : packs) { - ProviderInfo[] providers = pack.providers; - - if (null != providers) { - for (ProviderInfo provider : providers) { - if (!TextUtils.isEmpty(provider.authority) && provider.authority.endsWith(authority4)) { - return provider.authority; - } - } - } - } - } - return AUTHORITY; - } -} diff --git a/app/src/main/java/com/stardust/scriptdroid/tile/BoundsAssistEnableTileService.java b/app/src/main/java/com/stardust/scriptdroid/tile/BoundsAssistEnableTileService.java index 88478cc3..0c71789b 100644 --- a/app/src/main/java/com/stardust/scriptdroid/tile/BoundsAssistEnableTileService.java +++ b/app/src/main/java/com/stardust/scriptdroid/tile/BoundsAssistEnableTileService.java @@ -1,23 +1,26 @@ package com.stardust.scriptdroid.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.runtime.action.ActionPerformService; +import com.stardust.scriptdroid.droid.assist.Assistant; /** * Created by Stardust on 2017/1/26. */ +@RequiresApi(api = Build.VERSION_CODES.N) public class BoundsAssistEnableTileService extends TileService { public void onClick() { - ActionPerformService.setAssistModeEnable(!ActionPerformService.isAssistModeEnable()); + Assistant.setAssistModeEnable(!Assistant.isAssistModeEnable()); updateTile(); } private void updateTile() { - getQsTile().setState(ActionPerformService.isAssistModeEnable() ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE); + getQsTile().setState(Assistant.isAssistModeEnable() ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE); getQsTile().updateTile(); } 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 ce3fe1a3..ca466657 100644 --- a/app/src/main/java/com/stardust/scriptdroid/tool/IntentTool.java +++ b/app/src/main/java/com/stardust/scriptdroid/tool/IntentTool.java @@ -5,6 +5,8 @@ import android.content.Intent; import android.net.Uri; import android.support.annotation.Nullable; +import com.stardust.scriptdroid.R; + /** * Intent工具,用于Activity之间的跳转,调起其他应用程序等 */ @@ -28,7 +30,7 @@ public class IntentTool { intent.putExtra(Intent.EXTRA_SUBJECT, title); if (content != null) intent.putExtra(Intent.EXTRA_TEXT, content); - context.startActivity(Intent.createChooser(intent, "请选择邮件应用")); + context.startActivity(Intent.createChooser(intent, context.getString(R.string.text_choose_email_app))); } public static void goToMail(Context context, String sendTo) { diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/AssistClipListRecyclerView.java b/app/src/main/java/com/stardust/scriptdroid/ui/AssistClipListRecyclerView.java new file mode 100644 index 00000000..ffeb15ca --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/ui/AssistClipListRecyclerView.java @@ -0,0 +1,128 @@ +package com.stardust.scriptdroid.ui; + +import android.content.Context; +import android.support.annotation.Nullable; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +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.widget.ExpandableRecyclerView; + +/** + * Created by Stardust on 2017/2/4. + */ + +public class AssistClipListRecyclerView extends ExpandableRecyclerView { + + public interface OnClipClickListener { + void onClick(String clip, int position); + } + + private AssistClipList mAssistClipList = SharedPrefAssistClipList.getInstance(); + private OnClipClickListener mOnClipClickListener; + + public AssistClipListRecyclerView(Context context) { + super(context); + init(); + } + + public AssistClipListRecyclerView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + init(); + } + + public AssistClipListRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + + private void init() { + setLayoutManager(new LinearLayoutManager(getContext())); + setAdapter(new Adapter()); + setOnChildClickListener(new OnChildClickListener() { + @Override + public void onClick(View view, int position) { + if (mOnClipClickListener != null) { + String clip = (String) ((ChildViewHolder) getChildViewHolder(view)).mTextView.getText(); + mOnClipClickListener.onClick(clip, position); + } + } + }); + mAssistClipList.setOnClipChangedListener(new AssistClipList.OnClipChangedListener() { + @Override + public void onClipRemove(int position) { + getAdapter().notifyItemRemoved(position); + } + + @Override + public void onClipInsert(int position) { + getAdapter().notifyItemInserted(position); + } + + @Override + public void onChange() { + getAdapter().notifyDataSetChanged(); + } + }); + } + + public void setOnClipClickListener(OnClipClickListener onClipClickListener) { + mOnClipClickListener = onClipClickListener; + } + + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + //防止因mAssistClipList持有OnClipChangedListener引用从而导致这个RecyclerView及其Context被引用,内存泄漏 + mAssistClipList.setOnClipChangedListener(null); + } + + private class Adapter extends ExpandableRecyclerView.DefaultTitleAdapter { + + Adapter() { + setIcon(R.drawable.ic_robot_head_green); + setTitle(R.string.text_assist_clip); + } + + @Override + protected RecyclerView.ViewHolder onCreateChildViewHolder(ViewGroup parent, int viewType) { + return new ChildViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.assist_clip_list_recycler_view_item, parent, false)); + } + + @Override + protected void onBindChildViewHolder(RecyclerView.ViewHolder holder, int position) { + ChildViewHolder viewHolder = (ChildViewHolder) holder; + viewHolder.mTextView.setText(mAssistClipList.get(position)); + } + + @Override + protected int getChildItemCount() { + return mAssistClipList.size(); + } + + @Override + protected int getChildItemViewType(int position) { + return 0; + } + + } + + private class ChildViewHolder extends RecyclerView.ViewHolder { + + TextView mTextView; + + ChildViewHolder(View itemView) { + super(itemView); + mTextView = (TextView) itemView.findViewById(R.id.clip); + } + + } +} diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/AssistModeSwitchNotification.java b/app/src/main/java/com/stardust/scriptdroid/ui/AssistModeSwitchNotification.java index f1779e4e..b22512d9 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/AssistModeSwitchNotification.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/AssistModeSwitchNotification.java @@ -9,10 +9,9 @@ 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.runtime.action.ActionPerformService; +import com.stardust.scriptdroid.droid.assist.Assistant; import com.stardust.util.StateObserver; -import static com.stardust.scriptdroid.droid.runtime.action.ActionPerformService.KEY_ASSIST_MODE_ENABLE; /** * Created by Stardust on 2017/2/2. @@ -45,7 +44,7 @@ public class AssistModeSwitchNotification { } } }); - App.getStateObserver().register(KEY_ASSIST_MODE_ENABLE, new StateObserver.OnBooleanStateChangedListener() { + App.getStateObserver().register(Assistant.KEY_ASSIST_MODE_ENABLE, new StateObserver.OnBooleanStateChangedListener() { @Override public void onStateChanged(Boolean newState) { if (enable) { @@ -79,7 +78,7 @@ public class AssistModeSwitchNotification { .setAutoCancel(false) .setSmallIcon(R.drawable.ic_robot_head) .setDeleteIntent(AssistModeSwitchService.getDeletePendingIntent()) - .setContentText(ActionPerformService.isAssistModeEnable() ? + .setContentText(Assistant.isAssistModeEnable() ? App.getApp().getString(R.string.text_assist_mode_enabled) : App.getApp().getString(R.string.text_assist_mode_disabled)) .setContentIntent(AssistModeSwitchService.getStartIntent()) diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/EditSideMenuFragment.java b/app/src/main/java/com/stardust/scriptdroid/ui/EditSideMenuFragment.java index 24ba7a5e..be0e65e4 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/EditSideMenuFragment.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/EditSideMenuFragment.java @@ -1,20 +1,118 @@ package com.stardust.scriptdroid.ui; +import android.content.Intent; import android.os.Bundle; import android.support.annotation.Nullable; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.SwitchCompat; import android.view.LayoutInflater; import android.view.View; 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.view.ViewBinder; +import com.stardust.view.ViewBinding; + +import static com.stardust.scriptdroid.ui.AssistModeSwitchNotification.KEY_ASSIST_MODE_NOTIFICATION; + /** * Created by Stardust on 2017/2/4. */ public class EditSideMenuFragment extends com.stardust.app.Fragment { + + private FunctionListRecyclerView.OnFunctionClickListener mOnFunctionClickListener; + private AssistClipListRecyclerView.OnClipClickListener mOnClipClickListener; + + public static EditSideMenuFragment setFragment(AppCompatActivity activity, int viewId) { + EditSideMenuFragment fragment = new EditSideMenuFragment(); + activity.getSupportFragmentManager().beginTransaction().replace(viewId, fragment).commit(); + return fragment; + } + + private SwitchCompat mAssistServiceSwitch, mAssistServiceNotificationSwitch; + @Nullable @Override public View createView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - return null; + return inflater.inflate(R.layout.fragment_edit_side_menu, container, false); + } + + @Override + public void onStart() { + super.onStart(); + if (mAssistServiceSwitch == null) { + setUpUI(); + } + syncSwitchState(); + } + + private void setUpUI() { + setUpSwitchCompat(); + setUpFunctionList(); + setUpClipList(); + ViewBinder.bind(this); + } + + private void setUpClipList() { + AssistClipListRecyclerView assistClipListRecyclerView = $(R.id.assist_clip_list); + assistClipListRecyclerView.setOnClipClickListener(mOnClipClickListener); + } + + private void setUpFunctionList() { + FunctionListRecyclerView functionListRecyclerView = $(R.id.function_list); + functionListRecyclerView.setOnFunctionClickListener(mOnFunctionClickListener); + + } + + private void syncSwitchState() { + mAssistServiceSwitch.setChecked(Assistant.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(KEY_ASSIST_MODE_NOTIFICATION, mAssistServiceNotificationSwitch); + } + + @ViewBinding.Click(R.id.syntax_and_api) + private void startSyntaxHelpActivity() { + startActivity(new Intent(getContext(), DocumentActivity.class)); + } + + @ViewBinding.Check(R.id.sw_assist_service) + private void setAssistServiceEnable(boolean enable) { + Assistant.setAssistModeEnable(enable); + } + + @ViewBinding.Click(R.id.assist_service) + private void toggleAssistServiceSwitch() { + mAssistServiceSwitch.toggle(); + } + + @ViewBinding.Check(R.id.sw_assist_service_notification) + private void setAssistServiceNotificationEnable(boolean enable) { + AssistModeSwitchNotification.setEnable(enable); + } + + @ViewBinding.Click(R.id.assist_service_notification) + private void toggleAssistServiceNotificationSwitch() { + mAssistServiceNotificationSwitch.toggle(); + } + + public EditSideMenuFragment setOnFunctionClickListener(FunctionListRecyclerView.OnFunctionClickListener onFunctionClickListener) { + mOnFunctionClickListener = onFunctionClickListener; + return this; + } + + public EditSideMenuFragment setOnClipClickListener(AssistClipListRecyclerView.OnClipClickListener onClipClickListener) { + mOnClipClickListener = onClipClickListener; + return this; } } diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/FunctionListRecyclerView.java b/app/src/main/java/com/stardust/scriptdroid/ui/FunctionListRecyclerView.java new file mode 100644 index 00000000..4353fb6a --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/ui/FunctionListRecyclerView.java @@ -0,0 +1,141 @@ +package com.stardust.scriptdroid.ui; + +import android.content.Context; +import android.support.annotation.Nullable; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +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 java.util.ArrayList; +import java.util.List; + +/** + * Created by Stardust on 2017/2/4. + */ + +public class FunctionListRecyclerView extends ExpandableRecyclerView { + + public interface OnFunctionClickListener { + void onClick(Function function, int position); + } + + public static class Function { + public String name; + String description; + + public Function(String name, String description) { + this.description = description; + this.name = name; + } + + } + + + private static final List FUNCTION_LIST = new ArrayList<>(); + + static { + initFunctionList(); + } + + private List mFunctionList; + private OnFunctionClickListener mOnFunctionClickListener; + + public FunctionListRecyclerView(Context context) { + super(context); + init(); + } + + public FunctionListRecyclerView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + init(); + } + + public FunctionListRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + + private void init() { + setLayoutManager(new LinearLayoutManager(getContext())); + setAdapter(new Adapter()); + setFunctionList(FUNCTION_LIST); + setOnChildClickListener(new OnChildClickListener() { + @Override + public void onClick(View view, int position) { + if (mOnFunctionClickListener != null) { + mOnFunctionClickListener.onClick(mFunctionList.get(position), position); + } + } + }); + } + + public void setFunctionList(List functionList) { + mFunctionList = functionList; + } + + public void setOnFunctionClickListener(OnFunctionClickListener onFunctionClickListener) { + mOnFunctionClickListener = onFunctionClickListener; + } + + + private class Adapter extends ExpandableRecyclerView.DefaultTitleAdapter { + + Adapter() { + setIcon(R.drawable.ic_function_mathematical_green); + setTitle(R.string.text_function); + } + + @Override + protected RecyclerView.ViewHolder onCreateChildViewHolder(ViewGroup parent, int viewType) { + return new ChildViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.function_list_recycler_view_item, parent, false)); + } + + @Override + protected void onBindChildViewHolder(RecyclerView.ViewHolder holder, int position) { + ChildViewHolder viewHolder = (ChildViewHolder) holder; + Function function = mFunctionList.get(position); + viewHolder.mFunctionName.setText(function.name); + viewHolder.mDescription.setText(function.description); + } + + @Override + protected int getChildItemCount() { + return mFunctionList.size(); + } + + @Override + protected int getChildItemViewType(int position) { + return 0; + } + } + + public class ChildViewHolder extends RecyclerView.ViewHolder { + + TextView mFunctionName, mDescription; + + public ChildViewHolder(View itemView) { + super(itemView); + mFunctionName = (TextView) itemView.findViewById(R.id.function_name); + mDescription = (TextView) itemView.findViewById(R.id.description); + } + + } + + private static void initFunctionList() { + String[] functions = FileUtils.readString(App.getApp().getResources().openRawResource(R.raw.edit_side_menu_functions)).split("\n"); + for (String f : functions) { + String[] str = f.split(" "); + FUNCTION_LIST.add(new Function(str[0], str[1])); + } + + } +} diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/ScriptFileOperation.java b/app/src/main/java/com/stardust/scriptdroid/ui/ScriptFileOperation.java index c695cf65..87c9bc2e 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/ScriptFileOperation.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/ScriptFileOperation.java @@ -7,6 +7,7 @@ import android.support.annotation.NonNull; 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.R; import com.stardust.scriptdroid.ShortcutActivity; @@ -57,12 +58,12 @@ public abstract class ScriptFileOperation { public static class Run extends ScriptFileOperation { static { - addOperation("运行", R.drawable.ic_play_green, new Run()); + addOperation(App.getApp().getString(R.string.text_run), R.drawable.ic_play_green, new Run()); } @Override public void operate(ScriptListRecyclerView recyclerView, ScriptFileList scriptFileList, int position) { - Snackbar.make(recyclerView, "开始运行", Snackbar.LENGTH_SHORT).show(); + Snackbar.make(recyclerView, R.string.text_start_running, Snackbar.LENGTH_SHORT).show(); ScriptFile scriptFile = scriptFileList.get(position); scriptFile.run(); } @@ -71,7 +72,7 @@ public abstract class ScriptFileOperation { public static class Edit extends ScriptFileOperation { static { - //addOperation("编辑", R.drawable.ic_edit_green_48dp, new Edit()); + //addOperation(App.getApp().getString(R.string.text_edit)", R.drawable.ic_edit_green_48dp, new Edit()); } @Override @@ -85,7 +86,7 @@ public abstract class ScriptFileOperation { public static class OpenByOtherApp extends ScriptFileOperation { static { - addOperation("用其他应用打开", R.drawable.ic_open_in_new_green_48dp, new OpenByOtherApp()); + addOperation(App.getApp().getString(R.string.text_open_by_other_apps), R.drawable.ic_open_in_new_green_48dp, new OpenByOtherApp()); } @Override @@ -100,16 +101,16 @@ public abstract class ScriptFileOperation { public static class Rename extends ScriptFileOperation { static { - addOperation("重命名", R.drawable.ic_rename_green, new Rename()); + addOperation(App.getApp().getString(R.string.text_rename), R.drawable.ic_rename_green, new Rename()); } @Override public void operate(final ScriptListRecyclerView recyclerView, final ScriptFileList scriptFileList, final int position) { String oldName = scriptFileList.get(position).name; new MaterialDialog.Builder(recyclerView.getContext()) - .title("重命名") - .checkBoxPrompt("同时重命名原文件", false, null) - .input("输入新名称", oldName, new MaterialDialog.InputCallback() { + .title(R.string.text_rename) + .checkBoxPrompt(App.getApp().getString(R.string.text_rename_file_meanwhile), false, null) + .input(App.getApp().getString(R.string.text_please_input_new_name), oldName, new MaterialDialog.InputCallback() { @Override public void onInput(@NonNull MaterialDialog dialog, CharSequence input) { scriptFileList.rename(position, input.toString(), dialog.isPromptCheckBoxChecked()); @@ -123,7 +124,7 @@ public abstract class ScriptFileOperation { public static class CreateShortcut extends ScriptFileOperation { static { - addOperation("创建桌面快捷方式", R.drawable.ic_shortcut_green, new CreateShortcut()); + addOperation(App.getApp().getString(R.string.text_send_shortcut), R.drawable.ic_shortcut_green, new CreateShortcut()); } @@ -136,14 +137,14 @@ public abstract class ScriptFileOperation { .icon(R.drawable.script_droid) .extras(new Intent().putExtra("path", scriptFile.path)) .send(); - Snackbar.make(recyclerView, "已创建", Snackbar.LENGTH_SHORT).show(); + Snackbar.make(recyclerView, R.string.text_already_create, Snackbar.LENGTH_SHORT).show(); } } public static class Remove extends ScriptFileOperation { static { - addOperation("删除", R.drawable.ic_delete_green_48dp, new Remove()); + addOperation(App.getApp().getString(R.string.text_delete), R.drawable.ic_delete_green_48dp, new Remove()); } @Override @@ -156,13 +157,13 @@ public abstract class ScriptFileOperation { public static class Delete extends ScriptFileOperation { static { - addOperation("彻底删除", R.drawable.ic_delete_forever_green_48dp, new Delete()); + addOperation(App.getApp().getString(R.string.text_delete_absolutly), R.drawable.ic_delete_forever_green_48dp, new Delete()); } @Override public void operate(ScriptListRecyclerView recyclerView, ScriptFileList scriptFileList, int position) { boolean succeed = scriptFileList.deleteFromFileSystem(position); - Snackbar.make(recyclerView, succeed ? "已删除" : "文件删除失败", Snackbar.LENGTH_SHORT).show(); + Snackbar.make(recyclerView, succeed ? R.string.text_already_delete : R.string.text_delete_failed, Snackbar.LENGTH_SHORT).show(); recyclerView.getAdapter().notifyItemRemoved(position); } } diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/SlideMenuFragment.java b/app/src/main/java/com/stardust/scriptdroid/ui/SlideMenuFragment.java index 89b652d7..8d09933a 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/SlideMenuFragment.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/SlideMenuFragment.java @@ -15,12 +15,12 @@ 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.runtime.action.ActionPerformService; import com.stardust.view.ViewBinder; import com.stardust.view.ViewBinding; import com.stardust.view.accessibility.AccessibilityServiceUtils; -import static com.stardust.scriptdroid.droid.runtime.action.ActionPerformService.KEY_ASSIST_MODE_ENABLE; import static com.stardust.scriptdroid.ui.AssistModeSwitchNotification.KEY_ASSIST_MODE_NOTIFICATION; /** @@ -30,7 +30,7 @@ import static com.stardust.scriptdroid.ui.AssistModeSwitchNotification.KEY_ASSIS public class SlideMenuFragment extends Fragment { - public static void init(AppCompatActivity activity, int viewId) { + public static void setFragment(AppCompatActivity activity, int viewId) { SlideMenuFragment fragment = new SlideMenuFragment(); activity.getSupportFragmentManager().beginTransaction().replace(viewId, fragment).commit(); } @@ -60,7 +60,7 @@ public class SlideMenuFragment extends Fragment { mAutoOperateServiceSwitch.setChecked(ActionPerformService.isEnable()); } }, 450); - mAssistServiceSwitch.setChecked(ActionPerformService.isAssistModeEnable()); + mAssistServiceSwitch.setChecked(Assistant.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(KEY_ASSIST_MODE_ENABLE, mAssistServiceSwitch); + App.getStateObserver().register(Assistant.KEY_ASSIST_MODE_ENABLE, mAssistServiceSwitch); App.getStateObserver().register(KEY_ASSIST_MODE_NOTIFICATION, mAssistServiceNotificationSwitch); } @@ -93,7 +93,7 @@ public class SlideMenuFragment extends Fragment { @ViewBinding.Check(R.id.sw_assist_service) private void setAssistServiceEnable(boolean enable) { - ActionPerformService.setAssistModeEnable(enable); + Assistant.setAssistModeEnable(enable); } @ViewBinding.Click(R.id.assist_service) @@ -115,9 +115,9 @@ public class SlideMenuFragment extends Fragment { private void stopAllRunningScripts() { int n = Droid.getInstance().stopAll(); if (n > 0) - Snackbar.make(getActivityContentView(), "已停止" + n + "个正在运行的脚本", Snackbar.LENGTH_SHORT).show(); + Snackbar.make(getActivityContentView(), String.format(getString(R.string.text_already_stop_n_scripts), n), Snackbar.LENGTH_SHORT).show(); else - Snackbar.make(getActivityContentView(), "没有正在运行的脚本", Snackbar.LENGTH_SHORT).show(); + Snackbar.make(getActivityContentView(), R.string.text_no_running_script, Snackbar.LENGTH_SHORT).show(); } @Override diff --git a/app/src/main/java/com/stardust/scriptdroid/widget/ExpandableRecyclerView.java b/app/src/main/java/com/stardust/scriptdroid/widget/ExpandableRecyclerView.java new file mode 100644 index 00000000..ff65e3bd --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/widget/ExpandableRecyclerView.java @@ -0,0 +1,208 @@ +package com.stardust.scriptdroid.widget; + +import android.content.Context; +import android.support.annotation.Nullable; +import android.support.v7.widget.RecyclerView; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.stardust.scriptdroid.R; + +/** + * Created by Stardust on 2017/2/4. + */ + +public class ExpandableRecyclerView extends RecyclerView { + + public void setOnChildClickListener(OnChildClickListener onChildClickListener) { + mOnChildClickListener = onChildClickListener; + } + + public interface OnChildClickListener { + + void onClick(View view, int position); + } + + + private OnClickListener mOnTitleClickListener = new OnClickListener() { + @Override + public void onClick(View v) { + toggle(); + } + + }; + private OnClickListener mOnChildClickListenerWrapper = new OnClickListener() { + + @Override + public void onClick(View v) { + if (mOnChildClickListener != null) { + mOnChildClickListener.onClick(v, getChildViewHolder(v).getAdapterPosition() - 1); + } + } + }; + private boolean mExpanded; + private OnChildClickListener mOnChildClickListener; + + public ExpandableRecyclerView(Context context) { + super(context); + init(); + } + + public ExpandableRecyclerView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + init(); + } + + public ExpandableRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + + private void init() { + + } + + public void toggle() { + if (isExpanded()) { + collapse(); + } else { + expand(); + } + } + + + public boolean isExpanded() { + return mExpanded; + } + + public void expand() { + mExpanded = true; + ((Adapter) getAdapter()).notifyExpanded(); + } + + public void collapse() { + mExpanded = false; + ((Adapter) getAdapter()).notifyCollapsed(); + } + + public abstract class Adapter extends RecyclerView.Adapter { + + protected static final int VIEW_TYPE_TITLE = 1; + + public void notifyExpanded() { + notifyItemChanged(0); + int n = getItemCount(); + for (int i = 1; i < n; i++) { + notifyItemInserted(i); + } + } + + public void notifyCollapsed() { + int n = getChildItemCount(); + for (int i = 0; i < n; i++) { + notifyItemRemoved(1); + } + notifyItemChanged(0); + } + + @Override + public int getItemCount() { + return mExpanded ? getChildItemCount() + 1 : 1; + } + + protected abstract int getChildItemCount(); + + @Override + public int getItemViewType(int position) { + return position == 0 ? VIEW_TYPE_TITLE : getChildItemViewType(position - 1); + } + + protected abstract int getChildItemViewType(int position); + + @Override + public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + if (viewType == VIEW_TYPE_TITLE) { + ViewHolder holder = onCreateTitleViewHolder(parent); + holder.itemView.setOnClickListener(mOnTitleClickListener); + return holder; + } else { + ViewHolder holder = onCreateChildViewHolder(parent, viewType); + holder.itemView.setOnClickListener(mOnChildClickListenerWrapper); + return holder; + } + } + + protected abstract ViewHolder onCreateTitleViewHolder(ViewGroup parent); + + protected abstract ViewHolder onCreateChildViewHolder(ViewGroup parent, int viewType); + + @Override + public void onBindViewHolder(ViewHolder holder, int position) { + if (holder.getItemViewType() == VIEW_TYPE_TITLE) { + onBindTitleViewHolder(holder); + } else { + onBindChildViewHolder(holder, position - 1); + } + } + + protected abstract void onBindChildViewHolder(ViewHolder holder, int position); + + protected abstract void onBindTitleViewHolder(ViewHolder holder); + + } + + public abstract class DefaultTitleAdapter extends Adapter { + + private int mIconResId = -1; + private String mTitle; + + public void setIcon(int iconResId) { + mIconResId = iconResId; + } + + public void setTitle(int resId) { + mTitle = getContext().getString(resId); + } + + public void setTitle(String title) { + mTitle = title; + } + + @Override + protected RecyclerView.ViewHolder onCreateTitleViewHolder(ViewGroup parent) { + return new TitleViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.expanded_recycler_view_default_title, parent, false)); + } + + + @Override + protected void onBindTitleViewHolder(RecyclerView.ViewHolder holder) { + TitleViewHolder viewHolder = (TitleViewHolder) holder; + viewHolder.mExpandHint.setImageResource(isExpanded() ? R.drawable.ic_expanded : R.drawable.ic_collapsed); + } + + + private class TitleViewHolder extends RecyclerView.ViewHolder { + + ImageView mExpandHint; + + TitleViewHolder(View itemView) { + super(itemView); + mExpandHint = (ImageView) itemView.findViewById(R.id.expand_hint); + ((TextView) itemView.findViewById(R.id.title)).setText(mTitle); + if (mIconResId != -1) { + ((ImageView) itemView.findViewById(R.id.icon)).setImageResource(mIconResId); + } else { + itemView.findViewById(R.id.icon).setVisibility(GONE); + } + } + + } + + } + + +} diff --git a/app/src/main/java/com/stardust/util/CrashHandler.java b/app/src/main/java/com/stardust/util/CrashHandler.java index 3e513fe8..ce3274c7 100644 --- a/app/src/main/java/com/stardust/util/CrashHandler.java +++ b/app/src/main/java/com/stardust/util/CrashHandler.java @@ -9,6 +9,7 @@ import android.content.Intent; import android.util.Log; import com.stardust.scriptdroid.App; +import com.stardust.scriptdroid.R; import java.io.PrintWriter; import java.io.StringWriter; @@ -26,7 +27,7 @@ public class CrashHandler implements UncaughtExceptionHandler { try { Log.e("CrashHandler", "Uncaught Exception!!!"); ex.printStackTrace(); - String t = "很抱歉,程序遇到未知错误,即将停止运行\n错误代码:" + ex.toString(); + String t = App.getApp().getString(R.string.sorry_for_crash) + ex.toString(); Intent intent = new Intent(App.getApp(), this.mErrorReportClass); intent.putExtra("message", t); intent.putExtra("error", throwableToString(ex)); diff --git a/app/src/main/java/com/stardust/util/StateObserver.java b/app/src/main/java/com/stardust/util/StateObserver.java index 0517889e..553b9940 100644 --- a/app/src/main/java/com/stardust/util/StateObserver.java +++ b/app/src/main/java/com/stardust/util/StateObserver.java @@ -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. @@ -115,7 +115,7 @@ public class StateObserver { private List getListenerListOrCreateIfNotExists(String key) { List listeners = mKeyStateListenersMap.get(key); if (listeners == null) { - listeners = new ArrayList<>(); + listeners = new Vector<>(); mKeyStateListenersMap.put(key, listeners); } return listeners; diff --git a/app/src/main/res/drawable/ic_collapsed.png b/app/src/main/res/drawable/ic_collapsed.png new file mode 100644 index 00000000..7522b384 Binary files /dev/null and b/app/src/main/res/drawable/ic_collapsed.png differ diff --git a/app/src/main/res/drawable/ic_expanded.png b/app/src/main/res/drawable/ic_expanded.png new file mode 100644 index 00000000..cb6a422a Binary files /dev/null and b/app/src/main/res/drawable/ic_expanded.png differ diff --git a/app/src/main/res/drawable/ic_function_mathematical_green.png b/app/src/main/res/drawable/ic_function_mathematical_green.png new file mode 100644 index 00000000..ea641aa4 Binary files /dev/null and b/app/src/main/res/drawable/ic_function_mathematical_green.png differ diff --git a/app/src/main/res/layout/activity_edit.xml b/app/src/main/res/layout/activity_edit.xml index ad4ad5a0..3241a202 100644 --- a/app/src/main/res/layout/activity_edit.xml +++ b/app/src/main/res/layout/activity_edit.xml @@ -1,10 +1,11 @@ - - + - \ No newline at end of file + + + + + + diff --git a/app/src/main/res/layout/assist_clip_list_recycler_view_item.xml b/app/src/main/res/layout/assist_clip_list_recycler_view_item.xml new file mode 100644 index 00000000..2454e2ce --- /dev/null +++ b/app/src/main/res/layout/assist_clip_list_recycler_view_item.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/content_edit.xml b/app/src/main/res/layout/content_edit.xml index 0d4787fd..46e2554c 100644 --- a/app/src/main/res/layout/content_edit.xml +++ b/app/src/main/res/layout/content_edit.xml @@ -10,8 +10,7 @@ + android:layout_height="match_parent"> + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_edit_side_menu.xml b/app/src/main/res/layout/fragment_edit_side_menu.xml new file mode 100644 index 00000000..e4e1b2b6 --- /dev/null +++ b/app/src/main/res/layout/fragment_edit_side_menu.xml @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/function_list_recycler_view_item.xml b/app/src/main/res/layout/function_list_recycler_view_item.xml new file mode 100644 index 00000000..3821dc3d --- /dev/null +++ b/app/src/main/res/layout/function_list_recycler_view_item.xml @@ -0,0 +1,27 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/raw/edit_side_menu_functions.txt b/app/src/main/res/raw/edit_side_menu_functions.txt new file mode 100644 index 00000000..21dcfa65 --- /dev/null +++ b/app/src/main/res/raw/edit_side_menu_functions.txt @@ -0,0 +1,9 @@ +click 点击 +longClick 长按 +scrollUp 上滑 +toast 提示 +launch 运行 +launchApp 运行应用 +select 选择 +input 输入 +sleep 暂停运行 \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 17b030b1..3571a8ca 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -51,13 +51,38 @@ 邮箱 https://github.com/hyb1996/NoRootScriptDroid [免Root脚本机器人]下载地址:https://github.com/hyb1996/NoRootScriptDroid/releases - 脚本辅助服务 - 通知栏显示脚本辅助开关 - 通知栏显示脚本辅助开关 + 点击定位辅助服务 + 通知栏显示点击定位开关 + 通知栏显示点击定位开关 其他 - 脚本辅助已开启(点击关闭) - 脚本辅助已关闭(点击开启) + 点击定位辅助服务已开启(点击关闭) + 点击定位辅助服务已关闭(点击开启) 错误报告 大姐姐好 再按一次退出程序 + 函数 + \"很抱歉,程序遇到未知错误,即将停止运行\\n错误代码:\" + 没有正在运行的脚本 + 已停止%d个正在运行的脚本 + 开始运行 + 用其他应用打开 + 重命名 + 同时重命名原文件 + 请输入新名称 + 创建桌面快捷方式 + 已创建 + 删除 + 彻底删除 + 已删除 + 文件删除失败 + 选择一个文件 + /脚本/ + 错误 + 文档加载失败/(ㄒoㄒ)/~~ + 复制调试信息 + 这是软件开发者(。・・)ノ + 略略略 + 请选择邮件应用 + 点击定位剪贴板 + 脚本已停止 diff --git a/app20170205.apk b/app20170205.apk new file mode 100644 index 00000000..10da8c37 Binary files /dev/null and b/app20170205.apk differ diff --git a/build.gradle b/build.gradle index 74b2ab0d..b902c03c 100644 --- a/build.gradle +++ b/build.gradle @@ -15,6 +15,9 @@ buildscript { allprojects { repositories { jcenter() + maven { + url "https://jitpack.io" + } } }