add: assist clip on edit side menu, alipay to donate

This commit is contained in:
hyb1996
2017-02-05 11:02:50 +08:00
parent 3fb16518e4
commit 407066027e
46 changed files with 1173 additions and 555 deletions

View File

@@ -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) {

View File

@@ -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));
}

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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<ToolbarMenuItem> 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);
}
}

View File

@@ -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) {

View File

@@ -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();

View File

@@ -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");

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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<String> mAssistClipList = new LinkedList<>();
public SharedPrefAssistClipList(Context context) {
mSharedPreferences = context.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE);
readFromSharedPref();
}
private void readFromSharedPref() {
Type type = new TypeToken<List<String>>() {
}.getType();
List<String> 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();
}
}

View File

@@ -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) {

View File

@@ -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<Action> actions = new ArrayList<>();
private static int state = STATE_INACTIVE;
private static boolean assistModeEnable = false;
public static void setActions(Collection<Action> 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();

View File

@@ -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<Pair<DuktapeEngine, Thread>> mDuktapeEngineList = new ArrayList<>();
private final Map<Thread, DuktapeEngine> mThreadDuktapeEngineMap = new Hashtable<>();
private static final String INIT_SCRIPT;
private Map<String, Object> 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<Pair<DuktapeEngine, Thread>> iterator = mDuktapeEngineList.iterator();
while (iterator.hasNext()) {
Pair<DuktapeEngine, Thread> 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<DuktapeEngine, Thread> pair : mDuktapeEngineList) {
stop(pair.first, pair.second);
synchronized (mThreadDuktapeEngineMap) {
for (Map.Entry<Thread, DuktapeEngine> 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));
}
}
}

View File

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

View File

@@ -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;

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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<PackageInfo> 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<PackageInfo> 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数据库<br/>
* 优先级:".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<PackageInfo> packs = context.getPackageManager().getInstalledPackages(
PackageManager.GET_PROVIDERS);
List<String> authorityList = new ArrayList<String>();
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;
}
}

View File

@@ -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();
}

View File

@@ -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) {

View File

@@ -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);
}
}
}

View File

@@ -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())

View File

@@ -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;
}
}

View File

@@ -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> FUNCTION_LIST = new ArrayList<>();
static {
initFunctionList();
}
private List<Function> 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<Function> 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]));
}
}
}

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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<ViewHolder> {
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);
}
}
}
}
}

View File

@@ -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));

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.
@@ -115,7 +115,7 @@ public class StateObserver {
private List<OnStateChangedListener> getListenerListOrCreateIfNotExists(String key) {
List<OnStateChangedListener> listeners = mKeyStateListenersMap.get(key);
if (listeners == null) {
listeners = new ArrayList<>();
listeners = new Vector<>();
mKeyStateListenersMap.put(key, listeners);
}
return listeners;