feat(ui): supports debugging

This commit is contained in:
hyb1996 2018-09-07 22:26:03 +08:00
parent e5e1b567e7
commit 32805aad34
28 changed files with 2027 additions and 57 deletions

View File

@ -8,8 +8,8 @@ android {
applicationId "org.autojs.autojs"
minSdkVersion 17
targetSdkVersion 23
versionCode 406
versionName "4.0.2 Alpha2"
versionCode 408
versionName "4.0.2 Alpha3"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
multiDexEnabled true
ndk {

View File

@ -5,9 +5,11 @@
"editor.background": "#1E1E1E",
"editor.foreground": "#D4D4D4",
"editorLineNumber.foreground": "#404040",
"editorBreakpoint.foreground": "#1976D2",
"imeBar.background": "#dd1e1e1e",
"imeBar.foreground": "#f1f1f1",
"editor.lineHighlightBackground": "#2e2e35"
"editor.lineHighlightBackground": "#2e2e35",
"editor.debuggingLineBackground": "#40c4ff"
},
"tokenColors": [
{

View File

@ -499,6 +499,8 @@
"editor.background": "#F5F5F5",
"editor.foreground": "#000000",
"editor.lineHighlightBackground": "#E4F6D4",
"editor.debuggingLineBackground": "#40c4ff",
"editorBreakpoint.foreground": "#03A9F4",
"focusBorder": "#A6B39B",
"pickerGroup.foreground": "#A6B39B",
"pickerGroup.border": "#749351",

View File

@ -22,6 +22,10 @@ public class EditorColors {
private String mImeForegroundColor;
@SerializedName("editor.lineHighlightBackground")
private String mLineHighlightBackground;
@SerializedName("editorBreakpoint.foreground")
private String mBreakpointForeground;
@SerializedName("editor.debuggingLineBackground")
private String mDebuggingLineBackground;
public String getLineHighlightBackground() {
return mLineHighlightBackground;
@ -86,4 +90,20 @@ public class EditorColors {
public void setImeForegroundColor(String imeForegroundColor) {
mImeForegroundColor = imeForegroundColor;
}
public String getBreakpointForeground() {
return mBreakpointForeground;
}
public void setBreakpointForeground(String breakpointForeground) {
mBreakpointForeground = breakpointForeground;
}
public String getDebuggingLineBackground() {
return mDebuggingLineBackground;
}
public void setDebuggingLineBackground(String debuggingLineBackground) {
mDebuggingLineBackground = debuggingLineBackground;
}
}

View File

@ -6,12 +6,14 @@ import android.text.InputType;
import android.view.MenuItem;
import com.stardust.pio.PFiles;
import org.autojs.autojs.R;
import org.autojs.autojs.ui.build.BuildActivity;
import org.autojs.autojs.ui.build.BuildActivity_;
import org.autojs.autojs.ui.edit.editor.CodeEditor;
import org.autojs.autojs.ui.log.LogActivity_;
import org.autojs.autojs.theme.dialog.ThemeColorMaterialDialogBuilder;
import com.stardust.util.ClipboardUtil;
import java.util.Locale;
@ -53,6 +55,21 @@ public class EditorMenu {
if (onMoreOptionsSelected(item)) {
return true;
}
if(onDebugOptionsSelected(item)){
return true;
}
}
return false;
}
private boolean onDebugOptionsSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_breakpoint:
mEditor.addOrRemoveBreakpointAtCurrentLine();
return true;
case R.id.action_launch_debugger:
mEditorView.launchDebugger();
return true;
}
return false;
}

View File

@ -11,10 +11,13 @@ import android.os.Bundle;
import android.os.Parcelable;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.widget.DrawerLayout;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.SparseBooleanArray;
import android.view.Gravity;
import android.view.View;
import android.widget.FrameLayout;
@ -50,6 +53,8 @@ import org.autojs.autojs.ui.edit.keyboard.FunctionsKeyboardHelper;
import org.autojs.autojs.ui.edit.keyboard.FunctionsKeyboardView;
import org.autojs.autojs.ui.edit.theme.Theme;
import org.autojs.autojs.ui.edit.theme.Themes;
import org.autojs.autojs.ui.edit.toolbar.DebugToolbarFragment;
import org.autojs.autojs.ui.edit.toolbar.DebugToolbarFragment_;
import org.autojs.autojs.ui.edit.toolbar.NormalToolbarFragment;
import org.autojs.autojs.ui.edit.toolbar.NormalToolbarFragment_;
import org.autojs.autojs.ui.edit.toolbar.SearchToolbarFragment;
@ -117,6 +122,9 @@ public class EditorView extends FrameLayout implements CodeCompletionBar.OnHintC
public void onReceive(Context context, Intent intent) {
if (ACTION_ON_EXECUTION_FINISHED.equals(intent.getAction())) {
mScriptExecutionId = ScriptExecution.NO_ID;
if (mDebugging) {
exitDebugging();
}
setMenuItemStatus(R.id.run, true);
String msg = intent.getStringExtra(Scripts.EXTRA_EXCEPTION_MESSAGE);
int line = intent.getIntExtra(Scripts.EXTRA_EXCEPTION_LINE_NUMBER, -1);
@ -130,8 +138,11 @@ public class EditorView extends FrameLayout implements CodeCompletionBar.OnHintC
}
}
};
private SparseBooleanArray mMenuItemStatus = new SparseBooleanArray();
private String mRestoredText;
private NormalToolbarFragment mNormalToolbar = new NormalToolbarFragment_();
private boolean mDebugging = false;
public EditorView(Context context) {
super(context);
@ -231,6 +242,7 @@ public class EditorView extends FrameLayout implements CodeCompletionBar.OnHintC
private void setMenuItemStatus(int id, boolean enabled) {
mMenuItemStatus.put(id, enabled);
ToolbarFragment fragment = (ToolbarFragment) getActivity().getSupportFragmentManager()
.findFragmentById(R.id.toolbar_menu);
if (fragment == null) {
@ -240,6 +252,9 @@ public class EditorView extends FrameLayout implements CodeCompletionBar.OnHintC
}
}
public boolean getMenuItemStatus(int id, boolean defValue) {
return mMenuItemStatus.get(id, defValue);
}
@AfterViews
void init() {
@ -347,6 +362,7 @@ public class EditorView extends FrameLayout implements CodeCompletionBar.OnHintC
}
}
@SuppressLint("CheckResult")
public void runAndSaveFileIfNeeded() {
save().observeOn(AndroidSchedulers.mainThread())
.subscribe(s -> run());
@ -515,6 +531,26 @@ public class EditorView extends FrameLayout implements CodeCompletionBar.OnHintC
}
public void launchDebugger() {
DebugToolbarFragment debugToolbarFragment = DebugToolbarFragment_.builder()
.build();
getActivity().getSupportFragmentManager().beginTransaction()
.replace(R.id.toolbar_menu, debugToolbarFragment)
.commit();
mDebugging = true;
}
public void exitDebugging() {
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
Fragment fragment = fragmentManager.findFragmentById(R.id.toolbar_menu);
if (fragment instanceof DebugToolbarFragment) {
((DebugToolbarFragment) fragment).detachDebugger();
}
showNormalToolbar();
mEditor.setDebuggingLine(-1);
mDebugging = false;
}
private void showErrorMessage(String msg) {
Snackbar.make(EditorView.this, getResources().getString(R.string.text_error) + ": " + msg, Snackbar.LENGTH_LONG)
.setAction(R.string.text_detail, v -> LogActivity_.intent(getContext()).start())

View File

@ -22,7 +22,6 @@ import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.os.Parcelable;
import android.support.v7.widget.AppCompatEditText;
import android.text.Editable;
import android.text.Layout;
@ -31,14 +30,16 @@ import android.util.Log;
import android.util.TimingLogger;
import android.view.Gravity;
import org.autojs.autojs.BuildConfig;
import org.autojs.autojs.ui.edit.theme.Theme;
import org.autojs.autojs.ui.edit.theme.TokenMapping;
import com.stardust.util.ClipboardUtil;
import com.stardust.util.TextUtils;
import org.mozilla.javascript.Token;
import java.util.LinkedHashMap;
import static org.autojs.autojs.ui.edit.editor.BracketMatching.UNMATCHED_BRACKET;
/**
@ -62,6 +63,8 @@ public class CodeEditText extends AppCompatEditText {
private int mFirstLineForDraw = -1, mLastLineForDraw;
private int[] mMatchingBrackets = {-1, -1};
private int mUnmatchedBracket = -1;
private LinkedHashMap<Integer, CodeEditor.Breakpoint> mBreakpoints = new LinkedHashMap<>();
private int mDebuggingLine = -1;
public CodeEditText(Context context) {
@ -87,6 +90,10 @@ public class CodeEditText extends AppCompatEditText {
mLineHighlightPaint.setStyle(Paint.Style.FILL);
}
public LinkedHashMap<Integer, CodeEditor.Breakpoint> getBreakpoints() {
return mBreakpoints;
}
public void setTheme(Theme theme) {
mTheme = theme;
invalidate();
@ -101,8 +108,8 @@ public class CodeEditText extends AppCompatEditText {
updatePaddingForGutter();
updateLineRangeForDraw(canvas);
//绘制当前行高亮需要在绘制光标之前
drawLineHighlight(canvas, mLineHighlightPaint, getCurrentLine());
//绘制行高亮需要在绘制光标之前
drawLineHighlights(canvas);
//调用super.onDraw绘制光标和选择高亮因为字体颜色被设置为透明因此super.onDraw()绘制的字体不显示
// TODO: 2018/2/24 优化效率不绘制透明字体
@ -118,6 +125,30 @@ public class CodeEditText extends AppCompatEditText {
mLogger.dumpToLog();
}
public int getDebuggingLine() {
return mDebuggingLine;
}
public void setDebuggingLine(int debuggingLine) {
mDebuggingLine = debuggingLine;
invalidate();
}
private void drawLineHighlights(Canvas canvas) {
int currentLine = getCurrentLine();
int debugHighlightLine = mDebuggingLine;
if(debugHighlightLine != currentLine){
//绘制当前行高亮
mLineHighlightPaint.setColor(mTheme.getLineHighlightBackgroundColor());
drawLineHighlight(canvas, mLineHighlightPaint, getCurrentLine());
}
if(debugHighlightLine != -1){
mLineHighlightPaint.setColor(mTheme.getDebuggingLineBackgroundColor());
drawLineHighlight(canvas, mLineHighlightPaint, debugHighlightLine);
}
}
private void updateLineRangeForDraw(Canvas canvas) {
Layout layout = getLayout();
if (layout == null)
@ -159,15 +190,22 @@ public class CodeEditText extends AppCompatEditText {
int scrollX = Math.max(getRealScrollX() - paddingLeft, 0);
Paint paint = getPaint();
int lineNumberColor = mTheme.getLineNumberColor();
int breakPointColor = mTheme.getBreakpointColor();
if (DEBUG)
Log.d(LOG_TAG, "draw line: " + (mLastLineForDraw - mFirstLineForDraw + 1));
mLogger.addSplit("before draw line");
for (int line = mFirstLineForDraw; line <= mLastLineForDraw && line < lineCount; line++) {
int lineBottom = layout.getLineTop(line + 1);
int lineTop = layout.getLineTop(line);
int lineBaseline = lineBottom - layout.getLineDescent(line);
//drawLineNumber
String lineNumberText = Integer.toString(line + 1);
// if there is a breakpoint at this line, draw highlight background for line number
if (mBreakpoints.containsKey(line)) {
paint.setColor(breakPointColor);
canvas.drawRect(0, lineTop, paddingLeft - 10, lineBottom, paint);
}
paint.setColor(lineNumberColor);
canvas.drawText(lineNumberText, 0, lineNumberText.length(), 10,
lineBaseline, paint);
@ -225,7 +263,6 @@ public class CodeEditText extends AppCompatEditText {
}
int lineTop = getLayout().getLineTop(line);
int lineBottom = getLayout().getLineTop(line + 1);
paint.setColor(mTheme.getLineHighlightBackgroundColor());
canvas.drawRect(0, lineTop, canvas.getWidth(), lineBottom, paint);
}

View File

@ -7,13 +7,15 @@ import android.util.AttributeSet;
import android.widget.Toast;
import com.afollestad.materialdialogs.MaterialDialog;
import com.android.dx.util.IntList;
import com.stardust.autojs.script.JsBeautifier;
import org.autojs.autojs.R;
import org.autojs.autojs.ui.edit.theme.Theme;
import com.stardust.util.ClipboardUtil;
import com.stardust.util.TextUtils;
import java.util.LinkedHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -53,7 +55,6 @@ public class CodeEditor extends HVScrollView {
private JsBeautifier mJsBeautifier;
private MaterialDialog mProcessDialog;
private CharSequence mReplacement = "";
private String mKeywords;
private Matcher mMatcher;
@ -73,7 +74,7 @@ public class CodeEditor extends HVScrollView {
private void init() {
//setFillViewport(true);
inflate(getContext(), R.layout.code_editor, this);
mCodeEditText = (CodeEditText) findViewById(R.id.code_edit_text);
mCodeEditText = findViewById(R.id.code_edit_text);
mCodeEditText.addTextChangedListener(new AutoIndent(mCodeEditText));
mTextViewRedoUndo = new TextViewRedoUndo(mCodeEditText);
mJavaScriptHighlighter = new JavaScriptHighlighter(mTheme, mCodeEditText);
@ -260,7 +261,7 @@ public class CodeEditor extends HVScrollView {
}
public void findPrev() {
if (mMatcher != null){
if (mMatcher != null) {
Toast.makeText(getContext(), R.string.error_regex_find_prev, Toast.LENGTH_SHORT).show();
return;
}
@ -329,6 +330,30 @@ public class CodeEditor extends HVScrollView {
mTextViewRedoUndo.markTextAsUnchanged();
}
public LinkedHashMap<Integer, Breakpoint> getBreakpoints() {
return mCodeEditText.getBreakpoints();
}
public void setDebuggingLine(int line){
mCodeEditText.setDebuggingLine(line);
}
public void addOrRemoveBreakpoint(int line) {
LinkedHashMap<Integer, Breakpoint> breakpoints = mCodeEditText.getBreakpoints();
if(breakpoints.remove(line) == null){
breakpoints.put(line, new Breakpoint(line));
}
mCodeEditText.invalidate();
}
public void addOrRemoveBreakpointAtCurrentLine() {
int line = LayoutHelper.getLineOfChar(mCodeEditText.getLayout(), mCodeEditText.getSelectionStart());
if (line < 0 || line >= mCodeEditText.getLayout().getLineCount())
return;
addOrRemoveBreakpoint(line);
}
@Override
protected void onDraw(Canvas canvas) {
int codeWidth = getWidth() - getPaddingLeft() - getPaddingRight();
@ -340,4 +365,14 @@ public class CodeEditor extends HVScrollView {
}
super.onDraw(canvas);
}
public static class Breakpoint {
public int line;
public boolean enabled = true;
public Breakpoint(int line) {
this.line = line;
}
}
}

View File

@ -25,6 +25,8 @@ public class Theme {
private int mImeBarForegroundColor = Color.WHITE;
private EditorTheme mEditorTheme;
private int mLineHighlightBackground;
private int mBreakpointColor;
private int mDebuggingLineBackground;
public Theme(EditorTheme theme) {
mEditorTheme = theme;
@ -34,6 +36,8 @@ public class Theme {
mImeBarBackgroundColor = parseColor(theme.getEditorColors().getImeBackgroundColor(), mImeBarBackgroundColor);
mImeBarForegroundColor = parseColor(theme.getEditorColors().getImeForegroundColor(), mImeBarForegroundColor);
mLineHighlightBackground = parseColor(theme.getEditorColors().getLineHighlightBackground(), mLineHighlightBackground);
mDebuggingLineBackground = parseColor(theme.getEditorColors().getDebuggingLineBackground(), mDebuggingLineBackground);
mBreakpointColor = parseColor(theme.getEditorColors().getBreakpointForeground(), mBackgroundColor);
for (TokenColor tokenColor : theme.getTokenColors()) {
String foregroundStr = tokenColor.getSettings().getForeground();
@ -141,4 +145,11 @@ public class Theme {
}
public int getBreakpointColor() {
return mBreakpointColor;
}
public int getDebuggingLineBackgroundColor() {
return mDebuggingLineBackground;
}
}

View File

@ -1,35 +1,116 @@
package org.autojs.autojs.ui.edit.toolbar;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.View;
import com.stardust.autojs.engine.RhinoJavaScriptEngine;
import com.stardust.autojs.execution.ScriptExecution;
import com.stardust.autojs.rhino.debug.Dim;
import com.stardust.autojs.rhino.debug.DebugCallback;
import org.androidannotations.annotations.Click;
import org.androidannotations.annotations.EFragment;
import org.autojs.autojs.R;
import org.autojs.autojs.autojs.AutoJs;
import org.autojs.autojs.ui.edit.EditorView;
import org.autojs.autojs.ui.edit.editor.CodeEditor;
import org.mozilla.javascript.ContextFactory;
import org.mozilla.javascript.tools.debugger.Dim;
import org.mozilla.javascript.tools.debugger.GuiCallback;
public class DebugToolbarFragment implements GuiCallback {
import java.util.Arrays;
import java.util.List;
private Dim mDim;
@EFragment(R.layout.fragment_debug_toolbar)
public class DebugToolbarFragment extends ToolbarFragment implements DebugCallback {
public void attachDebugger(){
mDim.attachTo(ContextFactory.getGlobal());
private static final String LOG_TAG = "DebugToolbarFragment";
private Dim mDim = new Dim();
private EditorView mEditorView;
private Handler mHandler;
public DebugToolbarFragment() {
mDim.setGuiCallback(this);
mDim.setBreak();
mDim.attachTo(AutoJs.getInstance().getScriptEngineService(), ContextFactory.getGlobal());
Log.d(LOG_TAG, "DebugToolbarFragment()");
}
public void deattchDebugger(){
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new Handler();
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mEditorView = findEditorView(view);
mEditorView.run();
Log.d(LOG_TAG, "onViewCreated");
}
public void detachDebugger() {
mDim.detach();
}
public void breakpoint(){
mDim.setGuiCallback(this);
@Click(R.id.step_over)
void stepOver() {
mEditorView.getEditor().setDebuggingLine(-1);
mDim.setReturnValue(Dim.STEP_OVER);
}
@Click(R.id.step_into)
void stepInto() {
mEditorView.getEditor().setDebuggingLine(-1);
mDim.setReturnValue(Dim.STEP_INTO);
}
@Click(R.id.stop_out)
void stepOut() {
mEditorView.getEditor().setDebuggingLine(-1);
mDim.setReturnValue(Dim.STEP_OUT);
}
@Click(R.id.stop_script)
void stopScript() {
mEditorView.forceStop();
}
@Click(R.id.resume_script)
void resumeScript() {
mEditorView.getEditor().setDebuggingLine(-1);
mDim.setReturnValue(Dim.GO);
}
@Override
public void updateSourceText(Dim.SourceInfo sourceInfo) {
Log.d(LOG_TAG, "updateSourceText: url = " + sourceInfo.url() + ", source = " + sourceInfo.source());
if (!sourceInfo.url().equals(mEditorView.getFile().toString())) {
return;
}
sourceInfo.removeAllBreakpoints();
for (CodeEditor.Breakpoint breakpoint : mEditorView.getEditor().getBreakpoints().values()) {
int line = breakpoint.line + 1;
if (sourceInfo.breakableLine(line)) {
sourceInfo.breakpoint(line, breakpoint.enabled);
Log.d(LOG_TAG, "not breakable: " + line);
}
}
}
@Override
public void enterInterrupt(Dim.StackFrame stackFrame, String s, String s1) {
public void enterInterrupt(Dim.StackFrame stackFrame, String threadName, String s1) {
Log.d(LOG_TAG, "enterInterrupt: threadName = " + threadName + ", url = " + stackFrame.getUrl() + ", line = " + stackFrame.getLineNumber());
if (stackFrame.getUrl().equals(mEditorView.getFile().toString())) {
mEditorView.getEditor().setDebuggingLine(stackFrame.getLineNumber() - 1);
} else {
mHandler.post(this::resumeScript);
}
}
@Override
@ -38,7 +119,26 @@ public class DebugToolbarFragment implements GuiCallback {
}
@Override
public void dispatchNextGuiEvent() throws InterruptedException {
public void dispatchNextGuiEvent() {
Log.d(LOG_TAG, "dispatchNextGuiEvent");
}
@Override
public boolean shouldAttachDebugger(RhinoJavaScriptEngine engine) {
ScriptExecution execution = AutoJs.getInstance().getScriptEngineService().getScriptExecution(mEditorView.getScriptExecutionId());
return execution != null && execution.getId() == engine.getId();
}
@Override
public List<Integer> getMenuItemIds() {
return Arrays.asList(R.id.step_over, R.id.step_into, R.id.stop_out, R.id.resume_script, R.id.stop_script);
}
@Override
public void onDestroy() {
super.onDestroy();
mDim.detach();
}
}

View File

@ -1,11 +1,14 @@
package org.autojs.autojs.ui.edit.toolbar;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.SparseBooleanArray;
import android.view.View;
import org.autojs.autojs.ui.edit.EditorView;
import java.util.List;
public abstract class ToolbarFragment extends Fragment implements View.OnClickListener {
@ -16,7 +19,6 @@ public abstract class ToolbarFragment extends Fragment implements View.OnClickLi
private OnMenuItemClickListener mOnMenuItemClickListener;
private List<Integer> mMenuItemIds;
private SparseBooleanArray mMenuItemStatus = new SparseBooleanArray();
public void setOnMenuItemClickListener(OnMenuItemClickListener listener) {
mOnMenuItemClickListener = listener;
@ -27,21 +29,32 @@ public abstract class ToolbarFragment extends Fragment implements View.OnClickLi
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
updateMenuItemStatus();
updateMenuItemStatus(view);
}
private void updateMenuItemStatus() {
View rootView = getView();
protected EditorView findEditorView(View view) {
while (!(view instanceof EditorView) && view.getParent() != null) {
view = (View) view.getParent();
}
if (!(view instanceof EditorView)) {
throw new IllegalStateException("cannot find EditorView from child: " + view);
}
return (EditorView) view;
}
private void updateMenuItemStatus(View rootView) {
if (rootView == null) {
return;
}
EditorView editorView = findEditorView(rootView);
if (mMenuItemIds == null) {
mMenuItemIds = getMenuItemIds();
}
for (int id : mMenuItemIds) {
View view = rootView.findViewById(id);
view.setOnClickListener(this);
view.setEnabled(mMenuItemStatus.get(id, view.isEnabled()));
view.setEnabled(editorView.getMenuItemStatus(id, view.isEnabled()));
}
}
@ -60,7 +73,6 @@ public abstract class ToolbarFragment extends Fragment implements View.OnClickLi
if (!mMenuItemIds.contains(id)) {
return;
}
mMenuItemStatus.put(id, enabled);
View rootView = getView();
if (rootView == null) {
return;

View File

@ -64,7 +64,7 @@ public class TaskListRecyclerView extends ThemeColorRecyclerView {
private ScriptExecutionListener mScriptExecutionListener = new SimpleScriptExecutionListener() {
@Override
public void onStart(final ScriptExecution execution) {
mAdapter.notifyChildInserted(0, mRunningTaskGroup.addTask(execution));
post(()-> mAdapter.notifyChildInserted(0, mRunningTaskGroup.addTask(execution)));
}
@Override
@ -78,12 +78,14 @@ public class TaskListRecyclerView extends ThemeColorRecyclerView {
}
private void onFinish(ScriptExecution execution){
final int i = mRunningTaskGroup.removeTask(execution);
if (i >= 0) {
mAdapter.notifyChildRemoved(0, i);
} else {
refresh();
}
post(()->{
final int i = mRunningTaskGroup.removeTask(execution);
if (i >= 0) {
mAdapter.notifyChildRemoved(0, i);
} else {
refresh();
}
});
}
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="right"
android:orientation="horizontal">
<org.autojs.autojs.ui.widget.ToolbarMenuItem
android:id="@+id/step_over"
android:layout_width="40dp"
android:layout_height="match_parent"
app:icon="@drawable/ic_debug_step_over"
app:text="@string/text_debug_step_over"/>
<org.autojs.autojs.ui.widget.ToolbarMenuItem
android:id="@+id/step_into"
android:layout_width="40dp"
android:layout_height="match_parent"
app:icon="@drawable/ic_debug_step_into"
app:text="@string/text_debug_step_into"/>
<org.autojs.autojs.ui.widget.ToolbarMenuItem
android:id="@+id/stop_out"
android:layout_width="40dp"
android:layout_height="match_parent"
app:icon="@drawable/ic_debug_step_out"
app:text="@string/text_debug_step_out"/>
<org.autojs.autojs.ui.widget.ToolbarMenuItem
android:id="@+id/resume_script"
android:layout_width="40dp"
android:layout_height="match_parent"
app:icon="@drawable/ic_play_arrow_white_48dp"
app:text="@string/text_debug_resume_script"/>
<org.autojs.autojs.ui.widget.ToolbarMenuItem
android:id="@+id/stop_script"
android:layout_width="40dp"
android:layout_height="match_parent"
app:icon="@drawable/ic_close_white_48dp"
app:text="@string/text_stop"/>
</LinearLayout>

View File

@ -79,6 +79,24 @@
</item>
<item
android:title="@string/text_debug"
app:showAsAction="never">
<menu>
<item
android:id="@+id/action_breakpoint"
android:title="@string/text_set_breakpoint"
app:showAsAction="never"/>
<item
android:id="@+id/action_launch_debugger"
android:title="@string/text_launch_debugger"
app:showAsAction="never"/>
</menu>
</item>
<item
android:id="@+id/action_build_apk"

View File

@ -359,4 +359,12 @@
<string name="key_script_dir_path">key_script_dir_path</string>
<string name="default_value_script_dir_path">/脚本/</string>
<string name="text_error_copy_file" formatted="true">发生错误: %s</string>
<string name="text_debug">调试</string>
<string name="text_set_breakpoint">断点</string>
<string name="text_launch_debugger">启动调试</string>
<string name="text_debug_step_out">跳出</string>
<string name="text_debug_step_into">进入</string>
<string name="text_debug_step_over">单步</string>
<string name="text_debug_resume_script">继续</string>
<string name="text_stop">停止</string>
</resources>

View File

@ -101,6 +101,7 @@ public abstract class AutoJs {
engine.setRuntime(createRuntime());
return engine;
});
LoopBasedJavaScriptEngine.initEngine();
mScriptEngineManager.registerEngine(AutoFileSource.ENGINE, () -> new RootAutomatorEngine(mContext));
}

View File

@ -86,5 +86,9 @@ public class LoopBasedJavaScriptEngine extends RhinoJavaScriptEngine {
super.init();
}
public static void initEngine(){
RhinoJavaScriptEngine.initEngine();
}
}

View File

@ -3,6 +3,7 @@ package com.stardust.autojs.engine;
import android.os.Looper;
import android.util.Log;
import com.stardust.app.GlobalAppContext;
import com.stardust.autojs.BuildConfig;
import com.stardust.autojs.rhino.AndroidContextFactory;
import com.stardust.autojs.rhino.NativeJavaClassWithPrototype;
@ -33,6 +34,7 @@ import java.io.Reader;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.ConcurrentHashMap;
@ -43,10 +45,13 @@ import java.util.concurrent.ConcurrentHashMap;
public class RhinoJavaScriptEngine extends JavaScriptEngine {
public static final String SOURCE_NAME_INIT = "<init>";
private static final String LOG_TAG = "RhinoJavaScriptEngine";
private static int contextCount = 0;
private static StringScriptSource sInitScript;
private static final ConcurrentHashMap<Context, RhinoJavaScriptEngine> sContextEngineMap = new ConcurrentHashMap<>();
private Context mContext;
private Scriptable mScriptable;
@ -69,7 +74,7 @@ public class RhinoJavaScriptEngine extends JavaScriptEngine {
Reader reader = source.getNonNullScriptReader();
try {
reader = preprocess(reader);
return mContext.evaluateReader(mScriptable, reader, "<" + source.getName() + ">", 1, null);
return mContext.evaluateReader(mScriptable, reader, source.toString(), 1, null);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
@ -90,6 +95,7 @@ public class RhinoJavaScriptEngine extends JavaScriptEngine {
public synchronized void destroy() {
super.destroy();
Log.d(LOG_TAG, "on destroy");
sContextEngineMap.remove(getContext());
Context.exit();
contextCount--;
Log.d(LOG_TAG, "contextCount = " + contextCount);
@ -105,7 +111,7 @@ public class RhinoJavaScriptEngine extends JavaScriptEngine {
mThread = Thread.currentThread();
ScriptableObject.putProperty(mScriptable, "__engine__", this);
initRequireBuilder(mContext, mScriptable);
mContext.evaluateString(mScriptable, getInitScript().getScript(), "<init>", 1, null);
mContext.evaluateString(mScriptable, getInitScript().getScript(), SOURCE_NAME_INIT, 1, null);
}
private JavaScriptSource getInitScript() {
@ -148,12 +154,10 @@ public class RhinoJavaScriptEngine extends JavaScriptEngine {
}
public Context createContext() {
if (!ContextFactory.hasExplicitGlobal()) {
ContextFactory.initGlobal(new InterruptibleAndroidContextFactory(new File(mAndroidContext.getCacheDir(), "classes")));
}
Context context = new RhinoAndroidHelper(mAndroidContext).enterContext();
contextCount++;
setupContext(context);
sContextEngineMap.put(context, this);
return context;
}
@ -164,6 +168,17 @@ public class RhinoJavaScriptEngine extends JavaScriptEngine {
context.setWrapFactory(new WrapFactory());
}
public static void initEngine() {
if (!ContextFactory.hasExplicitGlobal()) {
android.content.Context context = GlobalAppContext.get();
ContextFactory.initGlobal(new InterruptibleAndroidContextFactory(new File(context.getCacheDir(), "classes")));
}
}
public static RhinoJavaScriptEngine getEngineOfContext(Context context) {
return sContextEngineMap.get(context);
}
private class WrapFactory extends org.mozilla.javascript.WrapFactory {

View File

@ -3,7 +3,6 @@ package com.stardust.autojs.engine;
import android.support.annotation.CallSuper;
import com.stardust.autojs.execution.ScriptExecution;
import com.stardust.autojs.runtime.exception.ScriptException;
import com.stardust.autojs.script.ScriptSource;
import java.util.Map;
@ -14,7 +13,7 @@ import java.util.concurrent.atomic.AtomicInteger;
* Created by Stardust on 2017/4/2.
* <p>
* <p>
* A ScriptEngine is created by {@link ScriptEngineManager#createEngine(String)} ()}, and then can be
* A ScriptEngine is created by {@link ScriptEngineManager#createEngine(String, int)} ()}, and then can be
* used to execute script with {@link ScriptEngine#execute(ScriptSource)} in the **same** thread.
* When the execution finish successfully, the engine should be destroy in the thread that created it.
* <p>

View File

@ -4,6 +4,7 @@ import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.stardust.autojs.execution.ScriptExecution;
import com.stardust.autojs.script.ScriptSource;
import com.stardust.util.Supplier;
@ -96,37 +97,34 @@ public class ScriptEngineManager {
@Nullable
public ScriptEngine createEngine(String name) {
public ScriptEngine createEngine(String name, int id) {
Supplier<ScriptEngine> s = mEngineSuppliers.get(name);
if (s == null) {
return null;
}
ScriptEngine engine = s.get();
engine.setId(id);
putProperties(engine);
addEngine(engine);
return engine;
}
@Nullable
public ScriptEngine createEngineOfSource(ScriptSource source) {
return createEngine(source.getEngineName());
public ScriptEngine createEngineOfSource(ScriptSource source, int id) {
return createEngine(source.getEngineName(), id);
}
@NonNull
public ScriptEngine createEngineByNameOrThrow(String name) {
ScriptEngine engine = createEngine(name);
public ScriptEngine createEngineOfSourceOrThrow(ScriptSource source, int id) {
ScriptEngine engine = createEngineOfSource(source, id);
if (engine == null)
throw new ScriptEngineFactory.EngineNotFoundException("name: " + name);
throw new ScriptEngineFactory.EngineNotFoundException("source: " + source.toString());
return engine;
}
@NonNull
public ScriptEngine createEngineOfSourceOrThrow(ScriptSource source) {
ScriptEngine engine = createEngineOfSource(source);
if (engine == null)
throw new ScriptEngineFactory.EngineNotFoundException("source: " + source.toString());
return engine;
return createEngineOfSourceOrThrow(source, ScriptExecution.NO_ID);
}
public void registerEngine(String name, Supplier<ScriptEngine> supplier) {

View File

@ -28,8 +28,7 @@ public class RunnableScriptExecution extends ScriptExecution.AbstractScriptExecu
}
public Object execute() {
mScriptEngine = mScriptEngineManager.createEngineOfSourceOrThrow(getSource());
mScriptEngine.setId(getId());
mScriptEngine = mScriptEngineManager.createEngineOfSourceOrThrow(getSource(), getId());
return execute(mScriptEngine);
}

View File

@ -0,0 +1,50 @@
package com.stardust.autojs.rhino.debug;
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import com.stardust.autojs.engine.RhinoJavaScriptEngine;
import com.stardust.autojs.engine.ScriptEngine;
import org.mozilla.javascript.Context;
/**
* Interface for communication between the debugger and its GUI. This
* should be implemented by the GUI.
*/
public interface DebugCallback {
/**
* Called when the source text of some script has been changed.
*/
void updateSourceText(Dim.SourceInfo sourceInfo);
/**
* Called when the interrupt loop has been entered.
*/
void enterInterrupt(Dim.StackFrame lastFrame,
String threadTitle,
String alertMessage);
/**
* Returns whether the current thread is the GUI's event thread.
* This information is required to avoid blocking the event thread
* from the debugger.
*/
boolean isGuiEventThread();
/**
* Processes the next GUI event. This manual pumping of GUI events
* is necessary when the GUI event thread itself has been stopped.
*/
void dispatchNextGuiEvent() throws InterruptedException;
/**
*
* Returns whether the debugger should attach to this engine or not.
*/
boolean shouldAttachDebugger(RhinoJavaScriptEngine engine);
}

File diff suppressed because it is too large Load Diff