mirror of
https://github.com/TonyJiangWJ/Auto.js.git
synced 2026-06-21 21:01:43 +08:00
Forgotten
This commit is contained in:
parent
40d6285bed
commit
676ca14aca
Binary file not shown.
@ -7,8 +7,8 @@ android {
|
||||
applicationId "com.stardust.scriptdroid"
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 23
|
||||
versionCode 29
|
||||
versionName "1.17.0216(1)"
|
||||
versionCode 30
|
||||
versionName "1.17.0217"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
buildTypes {
|
||||
|
||||
@ -41,8 +41,8 @@ public class App extends Application {
|
||||
return;
|
||||
}
|
||||
LeakCanary.install(this);
|
||||
// if (!BuildConfig.DEBUG)
|
||||
Thread.setDefaultUncaughtExceptionHandler(new CrashHandler(ErrorReportActivity.class));
|
||||
if (!BuildConfig.DEBUG)
|
||||
Thread.setDefaultUncaughtExceptionHandler(new CrashHandler(ErrorReportActivity.class));
|
||||
instance = new WeakReference<>(this);
|
||||
stateObserver = new StateObserver(PreferenceManager.getDefaultSharedPreferences(this));
|
||||
registerActivityLifecycleCallback();
|
||||
|
||||
@ -11,6 +11,7 @@ public class Pref {
|
||||
|
||||
private static final SharedPreferences DISPOSABLE_BOOLEAN = App.getApp().getSharedPreferences("DISPOSABLE_BOOLEAN", Context.MODE_PRIVATE);
|
||||
public static final String SAMPLE_SCRIPTS_COPIED = "SAMPLE_SCRIPTS_COPIED";
|
||||
private static final String KEY_MAX_TEXT_LENGTH_FOR_CODE_COMPLETION = "KEY_MAX_TEXT_LENGTH_FOR_CODE_COMPLETION";
|
||||
|
||||
public static SharedPreferences def() {
|
||||
return PreferenceManager.getDefaultSharedPreferences(App.getApp());
|
||||
@ -43,4 +44,12 @@ public class Pref {
|
||||
private static String getString(int id) {
|
||||
return App.getApp().getString(id);
|
||||
}
|
||||
|
||||
public static int MaxTextLengthForCodeCompletion() {
|
||||
try {
|
||||
return Integer.parseInt(def().getString(App.getApp().getString(R.string.key_max_length_for_code_completion), "2000"));
|
||||
} catch (NumberFormatException e) {
|
||||
return 2000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,7 +13,6 @@ import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.jraska.console.Console;
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.ui.console.ConsoleActivity;
|
||||
import com.stardust.scriptdroid.droid.runtime.action.Action;
|
||||
import com.stardust.scriptdroid.droid.runtime.action.ActionFactory;
|
||||
import com.stardust.scriptdroid.droid.runtime.action.ActionPerformAccessibilityDelegate;
|
||||
@ -22,8 +21,8 @@ import com.stardust.scriptdroid.droid.runtime.action.GetTextAction;
|
||||
import com.stardust.scriptdroid.droid.runtime.api.IDroidRuntime;
|
||||
import com.stardust.scriptdroid.service.AccessibilityWatchDogService;
|
||||
import com.stardust.scriptdroid.tool.Shell;
|
||||
import com.stardust.scriptdroid.ui.console.ConsoleActivity;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import timber.log.Timber;
|
||||
@ -40,7 +39,6 @@ public class DroidRuntime implements IDroidRuntime {
|
||||
private static DroidRuntime runtime = new DroidRuntime();
|
||||
|
||||
private final Object mActionPerformLock = new Object();
|
||||
private boolean mActionPerformResult;
|
||||
private Handler mUIHandler;
|
||||
|
||||
public static DroidRuntime getRuntime() {
|
||||
@ -168,7 +166,7 @@ public class DroidRuntime implements IDroidRuntime {
|
||||
Console.clear();
|
||||
}
|
||||
|
||||
private boolean performAction(Action action) {
|
||||
private <T> T performAction(Action action) {
|
||||
if (AccessibilityWatchDogService.getInstance() == null) {
|
||||
toast(App.getApp().getString(R.string.text_no_accessibility_permission));
|
||||
throw new ScriptStopException(App.getApp().getString(R.string.text_no_accessibility_permission));
|
||||
@ -182,25 +180,11 @@ public class DroidRuntime implements IDroidRuntime {
|
||||
throw new ScriptStopException(App.getApp().getString(R.string.text_script_stopped), e);
|
||||
}
|
||||
}
|
||||
return mActionPerformResult;
|
||||
return (T) action.getResult();
|
||||
}
|
||||
|
||||
public List<String> getTexts() {
|
||||
if (AccessibilityWatchDogService.getInstance() == null) {
|
||||
toast(App.getApp().getString(R.string.text_no_accessibility_permission));
|
||||
throw new ScriptStopException(App.getApp().getString(R.string.text_no_accessibility_permission));
|
||||
}
|
||||
GetTextAction.result = Collections.EMPTY_LIST;
|
||||
ActionPerformAccessibilityDelegate.setAction(new GetTextAction());
|
||||
synchronized (mActionPerformLock) {
|
||||
try {
|
||||
mActionPerformLock.wait();
|
||||
return GetTextAction.result;
|
||||
} catch (InterruptedException e) {
|
||||
ActionPerformAccessibilityDelegate.setAction(ActionPerformAccessibilityDelegate.NO_ACTION);
|
||||
throw new ScriptStopException(App.getApp().getString(R.string.text_script_stopped), e);
|
||||
}
|
||||
}
|
||||
return performAction(new GetTextAction());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -260,8 +244,7 @@ public class DroidRuntime implements IDroidRuntime {
|
||||
};
|
||||
}
|
||||
|
||||
public void notifyActionPerformed(boolean succeed) {
|
||||
mActionPerformResult = succeed;
|
||||
public void notifyActionPerformed() {
|
||||
synchronized (mActionPerformLock) {
|
||||
mActionPerformLock.notify();
|
||||
}
|
||||
|
||||
@ -8,8 +8,8 @@ import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
public abstract class Action {
|
||||
|
||||
|
||||
private boolean mPerformUtilSucceed = false;
|
||||
private Object mResult;
|
||||
|
||||
public Action(boolean performUtilSucceed) {
|
||||
mPerformUtilSucceed = performUtilSucceed;
|
||||
@ -30,5 +30,11 @@ public abstract class Action {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Object getResult() {
|
||||
return mResult;
|
||||
}
|
||||
|
||||
public void setResult(Object result) {
|
||||
mResult = result;
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,18 +37,20 @@ public class ActionPerformAccessibilityDelegate implements AccessibilityDelegate
|
||||
}
|
||||
Log.i(TAG, "perform action:" + action);
|
||||
if (action.perform(root)) {
|
||||
onActionPerformed(true);
|
||||
action.setResult(true);
|
||||
onActionPerformed();
|
||||
} else if (!action.performUtilSucceed()) {
|
||||
onActionPerformed(false);
|
||||
action.setResult(false);
|
||||
onActionPerformed();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private void onActionPerformed(boolean succeed) {
|
||||
private void onActionPerformed() {
|
||||
synchronized (ActionPerformAccessibilityDelegate.class) {
|
||||
action = NO_ACTION;
|
||||
DroidRuntime.getRuntime().notifyActionPerformed(succeed);
|
||||
DroidRuntime.getRuntime().notifyActionPerformed();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -11,13 +11,12 @@ import java.util.List;
|
||||
|
||||
public class GetTextAction extends Action {
|
||||
|
||||
public static List<String> result;
|
||||
|
||||
@Override
|
||||
public boolean perform(AccessibilityNodeInfo root) {
|
||||
List<String> texts = new ArrayList<>();
|
||||
getText(root, texts);
|
||||
result = texts;
|
||||
super.setResult(texts);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -34,4 +33,10 @@ public class GetTextAction extends Action {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResult(Object result) {
|
||||
if (result instanceof List)
|
||||
super.setResult(result);
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,6 +17,7 @@ import com.afollestad.materialdialogs.DialogAction;
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.jecelyin.editor.v2.common.Command;
|
||||
import com.jecelyin.editor.v2.common.SaveListener;
|
||||
import com.jecelyin.editor.v2.core.widget.TextView;
|
||||
import com.jecelyin.editor.v2.ui.EditorDelegate;
|
||||
import com.jecelyin.editor.v2.view.EditorView;
|
||||
import com.jecelyin.editor.v2.view.menu.MenuDef;
|
||||
@ -24,6 +25,7 @@ import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.Pref;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.droid.Droid;
|
||||
import com.stardust.scriptdroid.ui.edit.completion.InputMethodEnhanceBar;
|
||||
import com.stardust.scriptdroid.ui.edit.sidemenu.AssistClipListRecyclerView;
|
||||
import com.stardust.scriptdroid.ui.edit.sidemenu.EditSideMenuFragment;
|
||||
import com.stardust.scriptdroid.ui.edit.sidemenu.FunctionListRecyclerView;
|
||||
@ -156,8 +158,27 @@ public class EditActivity extends Editor920Activity {
|
||||
private void setUpEditor() {
|
||||
if (mFile != null) {
|
||||
mEditorDelegate = new EditorDelegate(0, mFile, 0, null);
|
||||
EditorView editorView = (EditorView) findViewById(R.id.editor);
|
||||
final EditorView editorView = (EditorView) findViewById(R.id.editor);
|
||||
mEditorDelegate.setEditorView(editorView);
|
||||
InputMethodEnhanceBar inputMethodEnhanceBar = (InputMethodEnhanceBar) findViewById(R.id.input_method_enhance_bar);
|
||||
inputMethodEnhanceBar.setEditTextBridge(new InputMethodEnhanceBar.EditTextBridge() {
|
||||
@Override
|
||||
public void appendText(CharSequence text) {
|
||||
insertText(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void backspace(int count) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextView getEditText() {
|
||||
return editorView.getEditText();
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,158 @@
|
||||
package com.stardust.scriptdroid.ui.edit.completion;
|
||||
|
||||
import android.text.Editable;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.Log;
|
||||
|
||||
import com.jecelyin.editor.v2.core.widget.TextView;
|
||||
import com.stardust.scriptdroid.Pref;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/2/17.
|
||||
*/
|
||||
|
||||
public class CodeCompletion implements TextWatcher {
|
||||
|
||||
|
||||
public static class CodeCompletionItem implements Comparable<CodeCompletionItem> {
|
||||
String mDisplayText, mAppendText;
|
||||
|
||||
CodeCompletionItem(String displayText, String appendText) {
|
||||
mDisplayText = displayText;
|
||||
mAppendText = appendText;
|
||||
}
|
||||
|
||||
CodeCompletionItem(String text) {
|
||||
this(text, text);
|
||||
}
|
||||
|
||||
public String getAppendText() {
|
||||
return mAppendText;
|
||||
}
|
||||
|
||||
public String getDisplayText() {
|
||||
return mDisplayText;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(CodeCompletionItem o) {
|
||||
return mDisplayText.compareTo(o.mDisplayText);
|
||||
}
|
||||
}
|
||||
|
||||
interface OnCodeCompletionChangeListener {
|
||||
void OnCodeCompletionChange(Collection<CodeCompletionItem> list);
|
||||
}
|
||||
|
||||
private static final String TAG = "CodeCompletion";
|
||||
|
||||
private OnCodeCompletionChangeListener mOnCodeCompletionChangeListener;
|
||||
private TextView mEditText;
|
||||
|
||||
public CodeCompletion(OnCodeCompletionChangeListener listener) {
|
||||
mOnCodeCompletionChangeListener = listener;
|
||||
}
|
||||
|
||||
public void setEditText(TextView editText) {
|
||||
mEditText = editText;
|
||||
mEditText.addTextChangedListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
Log.v(TAG, "beforeTextChanged: s=" + s + " start=" + start + " count=" + count + " after=" + after);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
Log.v(TAG, "onTextChanged: s=" + s + " start=" + start + " count=" + count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
int position = mEditText.getSelectionStart();
|
||||
String str = parseWordBefore(s, position);
|
||||
if (!TextUtils.isEmpty(str))
|
||||
searchCodeCompletion(str);
|
||||
else
|
||||
mOnCodeCompletionChangeListener.OnCodeCompletionChange(DEFAULT_CODE_COMPLETION_LIST);
|
||||
}
|
||||
|
||||
private String parseWordBefore(Editable s, int position) {
|
||||
int i;
|
||||
for (i = position - 1; i >= 0; i--) {
|
||||
if (position - i > KEY_WORD_LENGTH_MAX) {
|
||||
return null;
|
||||
}
|
||||
if (!Character.isLetter(s.charAt(i))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < position - 1) {
|
||||
return s.subSequence(i + 1, position).toString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private static final String[] KEYWORDS = {"arguments", "break", "case", "catch", "class", "continue", "default", "do", "else", "eval", "export", "false", "for", "function", "if", "import", "in", "int", "new", "null", "package", "return", "switch", "this", "throw", "throws", "true", "try", "typeof", "var", "volatile", "while", "with", "Array", "Date", "hasOwnProperty", "Infinity", "isFinite", "isNaN", "isPrototypeOf", "length", "Math", "NaN", "name", "Number", "Object", "prototype", "String", "toString", "undefined", "valueOf"};
|
||||
private static final int KEY_WORD_LENGTH_MAX = 15;
|
||||
private static final String[] FUNCTIONS = {"launchApp", "click", "longClick", "scrollUp", "scrollDown", "toast", "launch", "input", "notStopped", "shell", "importClass"};
|
||||
|
||||
private boolean searchCodeCompletion(String str) {
|
||||
Collection<CodeCompletionItem> c = searchWordCompletion(str);
|
||||
c.addAll(searchCodeCompletion(str, FUNCTIONS));
|
||||
c.addAll(searchKeyWordCompletion(str));
|
||||
if (c.size() > 0) {
|
||||
mOnCodeCompletionChangeListener.OnCodeCompletionChange(c);
|
||||
return true;
|
||||
} else {
|
||||
mOnCodeCompletionChangeListener.OnCodeCompletionChange(DEFAULT_CODE_COMPLETION_LIST);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private Collection<CodeCompletionItem> searchWordCompletion(String str) {
|
||||
if (mEditText.getEditableText().length() < Pref.MaxTextLengthForCodeCompletion()) {
|
||||
return searchCodeCompletion(str, splitWord(mEditText.getEditableText().toString()));
|
||||
}
|
||||
return new TreeSet<>();
|
||||
}
|
||||
|
||||
private Collection<CodeCompletionItem> searchCodeCompletion(String str, String[] words) {
|
||||
Set<CodeCompletionItem> set = new TreeSet<>();
|
||||
for (String word : words) {
|
||||
// TODO: 2017/2/18 优化 字典树
|
||||
if (word.startsWith(str) && str.length() < word.length()) {
|
||||
set.add(new CodeCompletionItem(word, word.substring(str.length())));
|
||||
}
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
private String[] splitWord(String s) {
|
||||
// TODO: 2017/2/18 优化。利用上次结果
|
||||
return s.split("[\\W]");
|
||||
}
|
||||
|
||||
private Collection<CodeCompletionItem> searchKeyWordCompletion(String str) {
|
||||
return searchCodeCompletion(str, KEYWORDS);
|
||||
}
|
||||
|
||||
|
||||
private static final String[] DEFAULT_CODE_COMPLETIONS = new String[]{"=", "(", ")", ";", "{", "}", "\"", "!", "[", "]", ".", ","};
|
||||
private static final List<CodeCompletionItem> DEFAULT_CODE_COMPLETION_LIST = new ArrayList<>();
|
||||
|
||||
static {
|
||||
for (String str : DEFAULT_CODE_COMPLETIONS) {
|
||||
DEFAULT_CODE_COMPLETION_LIST.add(new CodeCompletionItem(str));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,103 @@
|
||||
package com.stardust.scriptdroid.ui.edit.completion;
|
||||
|
||||
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 java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/2/17.
|
||||
*/
|
||||
|
||||
public class InputMethodEnhanceBar extends RecyclerView implements CodeCompletion.OnCodeCompletionChangeListener {
|
||||
|
||||
|
||||
public InputMethodEnhanceBar(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public InputMethodEnhanceBar(Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public InputMethodEnhanceBar(Context context, @Nullable AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
init();
|
||||
}
|
||||
|
||||
public interface EditTextBridge {
|
||||
void appendText(CharSequence text);
|
||||
|
||||
void backspace(int count);
|
||||
|
||||
com.jecelyin.editor.v2.core.widget.TextView getEditText();
|
||||
}
|
||||
|
||||
EditTextBridge mEditTextBridge;
|
||||
private CodeCompletion mCodeCompletion = new CodeCompletion(this);
|
||||
private List<CodeCompletion.CodeCompletionItem> mCodeCompletionList = new ArrayList<>();
|
||||
private OnClickListener mOnCodeCompletionItemClickListener = new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int position = getChildViewHolder(v).getAdapterPosition();
|
||||
mEditTextBridge.appendText(mCodeCompletionList.get(position).getAppendText());
|
||||
}
|
||||
};
|
||||
|
||||
private void init() {
|
||||
setAdapter(new CodeCompletionAdapter());
|
||||
setLayoutManager(new LinearLayoutManager(getContext(), HORIZONTAL, false));
|
||||
}
|
||||
|
||||
public void setEditTextBridge(EditTextBridge editTextBridge) {
|
||||
mEditTextBridge = editTextBridge;
|
||||
mCodeCompletion.setEditText(mEditTextBridge.getEditText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void OnCodeCompletionChange(Collection<CodeCompletion.CodeCompletionItem> list) {
|
||||
mCodeCompletionList.clear();
|
||||
mCodeCompletionList.addAll(list);
|
||||
getAdapter().notifyDataSetChanged();
|
||||
}
|
||||
|
||||
|
||||
private class CodeCompletionAdapter extends RecyclerView.Adapter<ViewHolder> {
|
||||
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
return new ViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.input_method_enhance_bar_item, parent, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||
((TextView) holder.itemView).setText(mCodeCompletionList.get(position).getDisplayText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mCodeCompletionList.size();
|
||||
}
|
||||
}
|
||||
|
||||
private class ViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
itemView.setOnClickListener(mOnCodeCompletionItemClickListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -10,7 +10,8 @@
|
||||
<com.jecelyin.editor.v2.view.EditorView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/editor"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
|
||||
|
||||
<com.jecelyin.editor.v2.core.widget.JecEditText
|
||||
@ -35,6 +36,13 @@
|
||||
android:indeterminate="true"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<com.stardust.scriptdroid.ui.edit.completion.InputMethodEnhanceBar
|
||||
android:id="@+id/input_method_enhance_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="35dp"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:background="#e7ebec"/>
|
||||
|
||||
</com.jecelyin.editor.v2.view.EditorView>
|
||||
|
||||
|
||||
|
||||
10
app/src/main/res/layout/input_method_enhance_bar_item.xml
Normal file
10
app/src/main/res/layout/input_method_enhance_bar_item.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/btn_selector"
|
||||
android:gravity="center"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:textColor="@android:color/secondary_text_light"
|
||||
android:textSize="16sp"/>
|
||||
@ -121,4 +121,7 @@
|
||||
<string name="summary_use_volume_control_record">开启后每次音量变化会开始或停止脚本录制</string>
|
||||
<string name="key_use_volume_control_record">key_use_volume_control_record</string>
|
||||
<string name="text_mobile_qq_not_installed">未安装手机QQ</string>
|
||||
<string name="text_edit">编辑</string>
|
||||
<string name="key_max_length_for_code_completion">key_max_length_for_code_completion</string>
|
||||
<string name="text_max_length_for_code_completion">代码补全最大文件长度</string>
|
||||
</resources>
|
||||
|
||||
@ -11,6 +11,15 @@
|
||||
android:title="@string/text_use_volume_control_record"/>
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
android:title="@string/text_edit">
|
||||
|
||||
<com.afollestad.materialdialogs.prefs.MaterialEditTextPreference
|
||||
android:defaultValue="2000"
|
||||
android:inputType="number"
|
||||
android:key="@string/key_max_length_for_code_completion"
|
||||
android:title="@string/text_max_length_for_code_completion"/>
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory
|
||||
android:title="@string/text_others">
|
||||
|
||||
|
||||
@ -8,9 +8,32 @@ import org.junit.Test;
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
public class ExampleUnitTest {
|
||||
|
||||
private int i = 0;
|
||||
|
||||
@Test
|
||||
public void testSync() throws Exception {
|
||||
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
while (true) {
|
||||
synchronized (this) {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
while (true) {
|
||||
synchronized (this) {
|
||||
System.out.println(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
|
||||
|
||||
BIN
znymtjbl.exe
Normal file
BIN
znymtjbl.exe
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user