diff --git a/app/build.gradle b/app/build.gradle index 7cd3eb9f..e99537be 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,8 +8,8 @@ android { applicationId "com.stardust.scriptdroid" minSdkVersion 17 targetSdkVersion 23 - versionCode 256 - versionName "3.1.0 Beta" + versionCode 257 + versionName "3.1.1 Alpha" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" multiDexEnabled true ndk { diff --git a/app/src/main/assets/sample/画图/函数图像.js b/app/src/main/assets/sample/画图/函数图像.js new file mode 100644 index 00000000..32082284 --- /dev/null +++ b/app/src/main/assets/sample/画图/函数图像.js @@ -0,0 +1,24 @@ +"ui"; +ui.layout( + + + +); + +var f = function(x){ + return x * x + 3 * x - 4; +} + +var paint = new Paint(); +paint.setStrokeWidth(2); +var start = -5; +var end = 5; + +ui.graphic.on("draw", function(canvas){ + var w = canvas.getWidth(); + for (var i = 0; i < w; i++) { + var x = (end - start) / w * i + start; + var y = f(x); + canvas.drawPoint(x, y, paint); + } +}); \ No newline at end of file diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/edit/editor/JavaScriptHighlighter.java b/app/src/main/java/com/stardust/scriptdroid/ui/edit/editor/JavaScriptHighlighter.java index 1d585219..d622a46a 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/edit/editor/JavaScriptHighlighter.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/edit/editor/JavaScriptHighlighter.java @@ -96,14 +96,15 @@ public class JavaScriptHighlighter implements SimpleTextWatcher.AfterTextChanged TokenStream ts = new TokenStream(null, sourceString, 0); HighlightTokens highlightTokens = new HighlightTokens(sourceString); int token; + int color = mTheme.getColorForToken(Token.NAME); while ((token = ts.getToken()) != Token.EOF) { if (mRunningHighlighterId.get() != id) return; - int color = mTheme.getColorForToken(token); + color = mTheme.getColorForToken(token); highlightTokens.addToken(ts.getTokenBeg(), ts.getTokenEnd(), color); } if (highlightTokens.getCharCount() < sourceString.length()) { - highlightTokens.addToken(highlightTokens.getCharCount(), sourceString.length(), mTheme.getColorForToken(Token.NAME)); + highlightTokens.addToken(highlightTokens.getCharCount(), sourceString.length(), color); } mCodeEditText.updateHighlightTokens(highlightTokens); } diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/settings/AboutActivity.java b/app/src/main/java/com/stardust/scriptdroid/ui/settings/AboutActivity.java index 691e79c8..997e7108 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/settings/AboutActivity.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/settings/AboutActivity.java @@ -76,9 +76,10 @@ public class AboutActivity extends BaseActivity { @Click(R.id.icon) void lol() { mLolClickCount++; - Toast.makeText(this, R.string.text_lll, Toast.LENGTH_LONG).show(); + //Toast.makeText(this, R.string.text_lll, Toast.LENGTH_LONG).show(); if (mLolClickCount >= 5) { - crashTest(); + //crashTest(); + showEasterEgg(); } } @@ -92,11 +93,8 @@ public class AboutActivity extends BaseActivity { new ThemeColorMaterialDialogBuilder(this) .title("Crash Test") .positiveText("Crash") - .onPositive(new MaterialDialog.SingleButtonCallback() { - @Override - public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) { - throw new RuntimeException("Crash Test"); - } + .onPositive((dialog, which) -> { + throw new RuntimeException("Crash Test"); }).show(); } diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/settings/PaintView.java b/app/src/main/java/com/stardust/scriptdroid/ui/settings/PaintView.java deleted file mode 100644 index eeea6a93..00000000 --- a/app/src/main/java/com/stardust/scriptdroid/ui/settings/PaintView.java +++ /dev/null @@ -1,106 +0,0 @@ -package com.stardust.scriptdroid.ui.settings; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Path; -import android.os.Build; -import android.support.annotation.Nullable; -import android.support.annotation.RequiresApi; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.View; - -import com.stardust.theme.ThemeColorManagerCompat; - -import java.util.ArrayList; -import java.util.List; - -/** - * Created by Stardust on 2017/5/10. - */ - -public class PaintView extends View { - - private List mPaths = new ArrayList<>(); - private Path mCurrentPath; - private Paint mPaint; - - public PaintView(Context context) { - super(context); - init(); - } - - public PaintView(Context context, @Nullable AttributeSet attrs) { - super(context, attrs); - init(); - } - - public PaintView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - init(); - } - - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - public PaintView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - init(); - } - - private void init() { - mPaint = new Paint(); - mPaint.setColor(ThemeColorManagerCompat.getColorPrimary()); - mPaint.setAntiAlias(true); - mPaint.setStrokeWidth(5); - setWillNotDraw(false); - setClickable(true); - setBackgroundColor(Color.TRANSPARENT); - } - - @Override - protected void onDraw(Canvas canvas) { - for (Path path : mPaths) { - canvas.drawPath(path, mPaint); - } - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - float x = event.getY(); - float y = event.getY(); - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: - onTouchDown(x, y); - return true; - case MotionEvent.ACTION_MOVE: - onTouchMove(x, y); - return true; - case MotionEvent.ACTION_UP: - onTouchUp(x, y); - return true; - } - return super.onTouchEvent(event); - } - - private void onTouchDown(float x, float y) { - if (mCurrentPath != null) { - mCurrentPath.close(); - mPaths.add(mCurrentPath); - invalidate(); - } - mCurrentPath = new Path(); - mCurrentPath.moveTo(x, y); - } - - private void onTouchMove(float x, float y) { - mCurrentPath.moveTo(x, y); - } - - private void onTouchUp(float x, float y) { - mCurrentPath.close(); - mPaths.add(mCurrentPath); - mCurrentPath = null; - invalidate(); - } -} diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/settings/TestSurfaceView.java b/app/src/main/java/com/stardust/scriptdroid/ui/settings/TestSurfaceView.java new file mode 100644 index 00000000..d926d56a --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/ui/settings/TestSurfaceView.java @@ -0,0 +1,88 @@ +package com.stardust.scriptdroid.ui.settings; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.util.AttributeSet; +import android.util.Log; +import android.view.SurfaceHolder; +import android.view.SurfaceView; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * Created by Stardust on 2018/3/16. + */ + +public class TestSurfaceView extends SurfaceView implements SurfaceHolder.Callback { + + private volatile boolean mDrawing = true; + private static final String LOG_TAG = "TestSurfaceView"; + private ExecutorService mDrawingThreadPool; + + public TestSurfaceView(Context context) { + super(context); + init(); + } + + public TestSurfaceView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public TestSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + private void init() { + getHolder().addCallback(this); + } + + @Override + public void surfaceCreated(SurfaceHolder holder) { + performDraw(); + } + + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + + } + + private void performDraw() { + if (mDrawingThreadPool == null) + mDrawingThreadPool = Executors.newCachedThreadPool(); + mDrawingThreadPool.execute(() -> { + SurfaceHolder holder = getHolder(); + while (mDrawing) { + Canvas canvas = holder.lockCanvas(); + canvas.drawColor(Color.RED); + holder.unlockCanvasAndPost(canvas); + } + Log.d(LOG_TAG, "drawing thread: mRunning = false"); + }); + } + + @Override + protected void onWindowVisibilityChanged(int visibility) { + if (visibility == VISIBLE) { + if (mDrawingThreadPool != null) { + mDrawing = true; + performDraw(); + } + } else { + mDrawing = false; + } + super.onWindowVisibilityChanged(visibility); + } + + @Override + public void surfaceDestroyed(SurfaceHolder holder) { + Log.d(LOG_TAG, "surfaceDestroyed: mRunning = true"); + mDrawing = false; + Log.d(LOG_TAG, "surfaceDestroyed: mRunning = false"); + mDrawingThreadPool.shutdown(); + mDrawingThreadPool = null; + } +} diff --git a/app/src/main/res/layout/paint_layout.xml b/app/src/main/res/layout/paint_layout.xml index de6ce787..b64b4f46 100644 --- a/app/src/main/res/layout/paint_layout.xml +++ b/app/src/main/res/layout/paint_layout.xml @@ -3,14 +3,7 @@ android:layout_width="600dp" android:layout_height="600dp"> - - - diff --git a/autojs/src/main/AndroidManifest.xml b/autojs/src/main/AndroidManifest.xml index 4089509f..3a3ba863 100644 --- a/autojs/src/main/AndroidManifest.xml +++ b/autojs/src/main/AndroidManifest.xml @@ -13,6 +13,7 @@ > diff --git a/autojs/src/main/assets/init.js b/autojs/src/main/assets/init.js index 33e59f94..7f76ccb3 100644 --- a/autojs/src/main/assets/init.js +++ b/autojs/src/main/assets/init.js @@ -96,12 +96,15 @@ runtime.init(); importClass(android.view.KeyEvent); importClass(com.stardust.autojs.core.util.Shell); + importClass(android.graphics.Paint); //重定向require以便支持相对路径 (function(){ var __require__ = require; global.require = function(path){ - path = files.path(path); + if(!path.startsWith("http://") && !path.startsWith("https://")){ + path = files.path(path); + } return __require__(path); }; })(); diff --git a/autojs/src/main/java/com/stardust/autojs/core/eventloop/EventEmitter.java b/autojs/src/main/java/com/stardust/autojs/core/eventloop/EventEmitter.java index 7d6262e0..35d9a385 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/eventloop/EventEmitter.java +++ b/autojs/src/main/java/com/stardust/autojs/core/eventloop/EventEmitter.java @@ -110,6 +110,10 @@ public class EventEmitter { mBridges = bridges; } + protected void setTimer(Timer timer) { + mTimer = timer; + } + public EventEmitter once(String eventName, Object listener) { getListeners(eventName).add(listener, true); return this; diff --git a/autojs/src/main/java/com/stardust/autojs/core/graphics/ScriptCanvasView.java b/autojs/src/main/java/com/stardust/autojs/core/graphics/ScriptCanvasView.java new file mode 100644 index 00000000..42b80112 --- /dev/null +++ b/autojs/src/main/java/com/stardust/autojs/core/graphics/ScriptCanvasView.java @@ -0,0 +1,148 @@ +package com.stardust.autojs.core.graphics; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.util.Log; +import android.view.SurfaceHolder; +import android.view.SurfaceView; + +import com.stardust.autojs.core.eventloop.EventEmitter; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * Created by Stardust on 2018/3/16. + */ + +@SuppressLint("ViewConstructor") +public class ScriptCanvasView extends SurfaceView implements SurfaceHolder.Callback { + + private static final String LOG_TAG = "ScriptCanvasView"; + private volatile boolean mDrawing = true; + private EventEmitter mEventEmitter; + private final SurfaceHolder mHolder; + private ExecutorService mDrawingThreadPool; + + + public ScriptCanvasView(Context context, EventEmitter eventEmitter) { + super(context); + mEventEmitter = eventEmitter; + mHolder = getHolder(); + init(); + } + + private void init() { + mHolder.addCallback(this); + } + + @Override + public void surfaceCreated(SurfaceHolder holder) { + performDraw(); + } + + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + + } + + private void performDraw() { + if (mDrawingThreadPool == null) + mDrawingThreadPool = Executors.newCachedThreadPool(); + mDrawingThreadPool.execute(() -> { + SurfaceHolder holder = getHolder(); + while (mDrawing) { + Canvas canvas = holder.lockCanvas(); + canvas.drawColor(Color.WHITE); + emit("draw", canvas, this); + holder.unlockCanvasAndPost(canvas); + } + Log.d(LOG_TAG, "drawing thread: mRunning = false"); + }); + } + + @Override + protected void onWindowVisibilityChanged(int visibility) { + if (visibility == VISIBLE) { + if (mDrawingThreadPool != null) { + mDrawing = true; + performDraw(); + } + } else { + mDrawing = false; + } + super.onWindowVisibilityChanged(visibility); + } + + @Override + public void surfaceDestroyed(SurfaceHolder holder) { + Log.d(LOG_TAG, "surfaceDestroyed: mRunning = true"); + mDrawing = false; + Log.d(LOG_TAG, "surfaceDestroyed: mRunning = false"); + mDrawingThreadPool.shutdown(); + mDrawingThreadPool = null; + } + + public EventEmitter once(String eventName, Object listener) { + return mEventEmitter.once(eventName, listener); + } + + public EventEmitter on(String eventName, Object listener) { + return mEventEmitter.on(eventName, listener); + } + + public EventEmitter addListener(String eventName, Object listener) { + return mEventEmitter.addListener(eventName, listener); + } + + public boolean emit(String eventName, Object... args) { + return mEventEmitter.emit(eventName, args); + } + + public String[] eventNames() { + return mEventEmitter.eventNames(); + } + + public int listenerCount(String eventName) { + return mEventEmitter.listenerCount(eventName); + } + + public Object[] listeners(String eventName) { + return mEventEmitter.listeners(eventName); + } + + public EventEmitter prependListener(String eventName, Object listener) { + return mEventEmitter.prependListener(eventName, listener); + } + + public EventEmitter prependOnceListener(String eventName, Object listener) { + return mEventEmitter.prependOnceListener(eventName, listener); + } + + public EventEmitter removeAllListeners() { + return mEventEmitter.removeAllListeners(); + } + + public EventEmitter removeAllListeners(String eventName) { + return mEventEmitter.removeAllListeners(eventName); + } + + public EventEmitter removeListener(String eventName, Object listener) { + return mEventEmitter.removeListener(eventName, listener); + } + + public EventEmitter setMaxListeners(int n) { + return mEventEmitter.setMaxListeners(n); + } + + public int getMaxListeners() { + return mEventEmitter.getMaxListeners(); + } + + public static int defaultMaxListeners() { + return EventEmitter.defaultMaxListeners(); + } + +} diff --git a/autojs/src/main/java/com/stardust/autojs/core/looper/LooperHelper.java b/autojs/src/main/java/com/stardust/autojs/core/looper/LooperHelper.java index 5bb2857a..40e329e6 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/looper/LooperHelper.java +++ b/autojs/src/main/java/com/stardust/autojs/core/looper/LooperHelper.java @@ -24,7 +24,7 @@ public class LooperHelper { public static void quitForThread(Thread thread) { Looper looper = sLoopers.remove(thread); - if (looper != null) + if (looper != null && looper != Looper.getMainLooper()) looper.quit(); } } diff --git a/autojs/src/main/java/com/stardust/autojs/core/looper/TimerThread.java b/autojs/src/main/java/com/stardust/autojs/core/looper/TimerThread.java index 7fe88314..71a75086 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/looper/TimerThread.java +++ b/autojs/src/main/java/com/stardust/autojs/core/looper/TimerThread.java @@ -87,7 +87,7 @@ public class TimerThread extends ThreadCompat { return getTimer().setTimeout(callback, delay, args); } - private Timer getTimer() { + public Timer getTimer() { if (mTimer == null) { throw new IllegalStateException("thread is not alive"); } diff --git a/autojs/src/main/java/com/stardust/autojs/core/ui/inflater/DynamicLayoutInflater.java b/autojs/src/main/java/com/stardust/autojs/core/ui/inflater/DynamicLayoutInflater.java index 749ca140..6e5bad88 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/ui/inflater/DynamicLayoutInflater.java +++ b/autojs/src/main/java/com/stardust/autojs/core/ui/inflater/DynamicLayoutInflater.java @@ -49,30 +49,7 @@ import java.util.Map; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; -/** - * Copyright Nicholas White 2015. - * Source: https://github.com/nickwah/DynamicLayoutInflator - *

- * Licensed under the MIT License: - *

- * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - *

- * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - *

- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ + public class DynamicLayoutInflater { private static final String LOG_TAG = "DynamicLayoutInflater"; diff --git a/autojs/src/main/java/com/stardust/autojs/core/ui/inflater/attrsetter/CanvasViewAttrSetter.java b/autojs/src/main/java/com/stardust/autojs/core/ui/inflater/attrsetter/CanvasViewAttrSetter.java new file mode 100644 index 00000000..bfe27d58 --- /dev/null +++ b/autojs/src/main/java/com/stardust/autojs/core/ui/inflater/attrsetter/CanvasViewAttrSetter.java @@ -0,0 +1,32 @@ +package com.stardust.autojs.core.ui.inflater.attrsetter; + +import android.content.Context; +import android.support.annotation.Nullable; + +import com.stardust.autojs.core.eventloop.EventEmitter; +import com.stardust.autojs.core.graphics.ScriptCanvasView; +import com.stardust.autojs.core.ui.inflater.ValueParser; +import com.stardust.autojs.core.ui.inflater.ViewCreator; +import com.stardust.autojs.runtime.ScriptRuntime; + +import java.util.Map; + +/** + * Created by Stardust on 2018/3/16. + */ + +public class CanvasViewAttrSetter extends BaseViewAttrSetter { + + private ScriptRuntime mScriptRuntime; + + public CanvasViewAttrSetter(ValueParser valueParser, ScriptRuntime runtime) { + super(valueParser); + mScriptRuntime = runtime; + } + + @Nullable + @Override + public ViewCreator getCreator() { + return (context, attrs) -> new ScriptCanvasView(context, new EventEmitter(mScriptRuntime.bridges)); + } +} diff --git a/autojs/src/main/java/com/stardust/autojs/core/ui/xml/XmlConverter.java b/autojs/src/main/java/com/stardust/autojs/core/ui/xml/XmlConverter.java index 4094810b..609386e2 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/ui/xml/XmlConverter.java +++ b/autojs/src/main/java/com/stardust/autojs/core/ui/xml/XmlConverter.java @@ -12,6 +12,7 @@ import android.widget.SeekBar; import android.widget.Spinner; import android.widget.TimePicker; +import com.stardust.autojs.core.graphics.ScriptCanvasView; import com.stardust.autojs.core.ui.widget.JsButton; import com.stardust.autojs.core.ui.widget.JsEditText; import com.stardust.autojs.core.ui.widget.JsFrameLayout; @@ -64,6 +65,7 @@ public class XmlConverter { .map("checkbox", CheckBox.class.getName()) .map("scroll", ScrollView.class.getName()) .map("toolbar", Toolbar.class.getName()) + .map("canvas", ScriptCanvasView.class.getName()) ); private static final AttributeHandler ATTRIBUTE_HANDLER = new AttributeHandler.AttrNameRouter() diff --git a/autojs/src/main/java/com/stardust/autojs/engine/RhinoJavaScriptEngine.java b/autojs/src/main/java/com/stardust/autojs/engine/RhinoJavaScriptEngine.java index d7bea965..c8033020 100644 --- a/autojs/src/main/java/com/stardust/autojs/engine/RhinoJavaScriptEngine.java +++ b/autojs/src/main/java/com/stardust/autojs/engine/RhinoJavaScriptEngine.java @@ -44,7 +44,6 @@ public class RhinoJavaScriptEngine extends JavaScriptEngine { private Scriptable mScriptable; private Thread mThread; private android.content.Context mAndroidContext; - private Thread.UncaughtExceptionHandler mUncaughtExceptionHandler; public RhinoJavaScriptEngine(android.content.Context context) { mAndroidContext = context; @@ -157,14 +156,6 @@ public class RhinoJavaScriptEngine extends JavaScriptEngine { context.setWrapFactory(new WrapFactory()); } - public void setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler uiThreadExceptionHandler) { - mUncaughtExceptionHandler = uiThreadExceptionHandler; - } - - public Thread.UncaughtExceptionHandler getUncaughtExceptionHandler() { - return mUncaughtExceptionHandler; - } - private class WrapFactory extends org.mozilla.javascript.WrapFactory { @Override @@ -208,7 +199,7 @@ public class RhinoJavaScriptEngine extends JavaScriptEngine { try { return super.doTopCall(callable, cx, scope, thisObj, args); } catch (Exception e) { - mUncaughtExceptionHandler.uncaughtException(Thread.currentThread(), e); + getRuntime().exit(e); return null; } } diff --git a/autojs/src/main/java/com/stardust/autojs/engine/ScriptEngine.java b/autojs/src/main/java/com/stardust/autojs/engine/ScriptEngine.java index f40688d7..010a304e 100644 --- a/autojs/src/main/java/com/stardust/autojs/engine/ScriptEngine.java +++ b/autojs/src/main/java/com/stardust/autojs/engine/ScriptEngine.java @@ -40,6 +40,13 @@ public interface ScriptEngine { Object getTag(String key); + String cwd(); + + void uncaughtException(Exception throwable); + + Exception getUncaughtException(); + + /** * @hide */ @@ -60,11 +67,12 @@ public interface ScriptEngine { private Map mTags = new ConcurrentHashMap<>(); private OnDestroyListener mOnDestroyListener; private boolean mDestroyed = false; + private Exception mUncaughtException; @Override public synchronized void setTag(String key, Object value) { - if(value == null) + if (value == null) return; mTags.put(key, value); } @@ -97,5 +105,16 @@ public interface ScriptEngine { throw new SecurityException("setOnDestroyListener can be called only once"); mOnDestroyListener = onDestroyListener; } + + @Override + public void uncaughtException(Exception throwable) { + mUncaughtException = throwable; + forceStop(); + } + + @Override + public Exception getUncaughtException() { + return mUncaughtException; + } } } diff --git a/autojs/src/main/java/com/stardust/autojs/engine/ScriptEngineProxy.java b/autojs/src/main/java/com/stardust/autojs/engine/ScriptEngineProxy.java new file mode 100644 index 00000000..a295662b --- /dev/null +++ b/autojs/src/main/java/com/stardust/autojs/engine/ScriptEngineProxy.java @@ -0,0 +1,76 @@ +package com.stardust.autojs.engine; + +import com.stardust.autojs.script.ScriptSource; + +/** + * Created by Stardust on 2018/3/17. + */ + +public class ScriptEngineProxy implements ScriptEngine { + + private final ScriptEngine mScriptEngine; + + public ScriptEngineProxy(ScriptEngine scriptEngine) { + mScriptEngine = scriptEngine; + } + + @Override + public void put(String name, Object value) { + mScriptEngine.put(name, value); + } + + @Override + public Object execute(S scriptSource) { + return mScriptEngine.execute(scriptSource); + } + + @Override + public void forceStop() { + mScriptEngine.forceStop(); + } + + @Override + public void destroy() { + mScriptEngine.destroy(); + } + + @Override + public boolean isDestroyed() { + return mScriptEngine.isDestroyed(); + } + + @Override + public void setTag(String key, Object value) { + mScriptEngine.setTag(key, value); + } + + @Override + public Object getTag(String key) { + return mScriptEngine.getTag(key); + } + + @Override + public String cwd() { + return mScriptEngine.cwd(); + } + + @Override + public void uncaughtException(Exception throwable) { + mScriptEngine.uncaughtException(throwable); + } + + @Override + public Exception getUncaughtException() { + return mScriptEngine.getUncaughtException(); + } + + @Override + public void setOnDestroyListener(OnDestroyListener listener) { + mScriptEngine.setOnDestroyListener(listener); + } + + @Override + public void init() { + mScriptEngine.init(); + } +} diff --git a/autojs/src/main/java/com/stardust/autojs/execution/LoopedBasedJavaScriptExecution.java b/autojs/src/main/java/com/stardust/autojs/execution/LoopedBasedJavaScriptExecution.java index 4e643022..dc8f4894 100644 --- a/autojs/src/main/java/com/stardust/autojs/execution/LoopedBasedJavaScriptExecution.java +++ b/autojs/src/main/java/com/stardust/autojs/execution/LoopedBasedJavaScriptExecution.java @@ -23,10 +23,6 @@ public class LoopedBasedJavaScriptExecution extends RunnableScriptExecution { long delay = getConfig().delay; sleep(delay); final LoopBasedJavaScriptEngine javaScriptEngine = (LoopBasedJavaScriptEngine) engine; - javaScriptEngine.setUncaughtExceptionHandler((t, e) -> { - javaScriptEngine.forceStop(); - getListener().onException(this, (Exception) e); - }); final long interval = getConfig().interval; javaScriptEngine.getRuntime().loopers.setMainLooperQuitHandler(new Loopers.LooperQuitHandler() { long times = getConfig().loopTimes == 0 ? Integer.MAX_VALUE : getConfig().loopTimes; diff --git a/autojs/src/main/java/com/stardust/autojs/execution/ScriptExecuteActivity.java b/autojs/src/main/java/com/stardust/autojs/execution/ScriptExecuteActivity.java index 9e8e43e7..ca5187e2 100644 --- a/autojs/src/main/java/com/stardust/autojs/execution/ScriptExecuteActivity.java +++ b/autojs/src/main/java/com/stardust/autojs/execution/ScriptExecuteActivity.java @@ -1,5 +1,6 @@ package com.stardust.autojs.execution; +import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; @@ -9,6 +10,7 @@ import com.stardust.autojs.engine.LoopBasedJavaScriptEngine; import com.stardust.autojs.engine.RhinoJavaScriptEngine; import com.stardust.autojs.engine.ScriptEngine; import com.stardust.autojs.engine.ScriptEngineManager; +import com.stardust.autojs.engine.ScriptEngineProxy; import com.stardust.autojs.script.ScriptSource; import com.stardust.util.IntentExtras; @@ -16,7 +18,7 @@ import com.stardust.util.IntentExtras; * Created by Stardust on 2017/2/5. */ -public class ScriptExecuteActivity extends AppCompatActivity implements Thread.UncaughtExceptionHandler { +public class ScriptExecuteActivity extends AppCompatActivity { private static final String EXTRA_EXECUTION = ScriptExecuteActivity.class.getName() + ".execution"; @@ -24,7 +26,8 @@ public class ScriptExecuteActivity extends AppCompatActivity implements Thread.U private ScriptEngine mScriptEngine; private ScriptExecutionListener mExecutionListener; private ScriptSource mScriptSource; - private ScriptExecution mScriptExecution; + private ActivityScriptExecution mScriptExecution; + private IntentExtras mIntentExtras; public static ActivityScriptExecution execute(Context context, ScriptEngineManager manager, ScriptExecutionTask task) { ActivityScriptExecution execution = new ActivityScriptExecution(manager, task); @@ -37,22 +40,34 @@ public class ScriptExecuteActivity extends AppCompatActivity implements Thread.U return execution; } + // FIXME: 2018/3/16 如果Activity被回收则得不到改进 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - IntentExtras extras = IntentExtras.fromIntent(getIntent()); - if (extras.get(EXTRA_EXECUTION) == null) { + mIntentExtras = readIntentExtras(savedInstanceState); + if (mIntentExtras == null || mIntentExtras.get(EXTRA_EXECUTION) == null) { finish(); return; } - mScriptExecution = extras.get(EXTRA_EXECUTION); + mScriptExecution = mIntentExtras.get(EXTRA_EXECUTION); mScriptSource = mScriptExecution.getSource(); - mScriptEngine = mScriptExecution.getEngine(); + mScriptEngine = mScriptExecution.createEngine(this); mExecutionListener = mScriptExecution.getListener(); - ((RhinoJavaScriptEngine) mScriptEngine).setUncaughtExceptionHandler((t, e) -> onException((Exception) e)); runScript(); } + private IntentExtras readIntentExtras(Bundle savedInstanceState) { + IntentExtras extras = IntentExtras.fromIntent(getIntent()); + if (extras == null && savedInstanceState != null) { + int id = savedInstanceState.getInt(IntentExtras.EXTRA_ID, -1); + if (id == -1) { + return null; + } + extras = IntentExtras.fromId(id); + } + return extras; + } + private void runScript() { try { prepare(); @@ -93,7 +108,12 @@ public class ScriptExecuteActivity extends AppCompatActivity implements Thread.U @Override public void finish() { - mExecutionListener.onSuccess(mScriptExecution, mResult); + Exception exception = mScriptEngine.getUncaughtException(); + if (exception != null) { + onException(exception); + } else { + mExecutionListener.onSuccess(mScriptExecution, mResult); + } super.finish(); } @@ -106,8 +126,12 @@ public class ScriptExecuteActivity extends AppCompatActivity implements Thread.U } @Override - public void uncaughtException(Thread t, Throwable e) { - onException((Exception) e); + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + if (mIntentExtras == null) + return; + IntentExtras extras = IntentExtras.newExtras().putAll(mIntentExtras); + outState.putInt(IntentExtras.EXTRA_ID, extras.getId()); } private static class ActivityScriptExecution extends ScriptExecution.AbstractScriptExecution { @@ -120,12 +144,23 @@ public class ScriptExecuteActivity extends AppCompatActivity implements Thread.U mScriptEngineManager = manager; } + @SuppressWarnings("unchecked") + public ScriptEngine createEngine(Activity activity) { + if (mScriptEngine != null) { + mScriptEngine.forceStop(); + } + mScriptEngine = new ScriptEngineProxy(mScriptEngineManager.createEngineOfSourceOrThrow(getSource())) { + @Override + public void forceStop() { + super.forceStop(); + activity.finish(); + } + }; + return mScriptEngine; + } @Override public ScriptEngine getEngine() { - if (mScriptEngine == null) { - mScriptEngine = mScriptEngineManager.createEngineOfSourceOrThrow(getSource()); - } return mScriptEngine; } diff --git a/autojs/src/main/java/com/stardust/autojs/runtime/ScriptRuntime.java b/autojs/src/main/java/com/stardust/autojs/runtime/ScriptRuntime.java index f70a3ed3..9dadf40f 100644 --- a/autojs/src/main/java/com/stardust/autojs/runtime/ScriptRuntime.java +++ b/autojs/src/main/java/com/stardust/autojs/runtime/ScriptRuntime.java @@ -9,6 +9,7 @@ import com.stardust.autojs.ScriptEngineService; import com.stardust.autojs.annotation.ScriptVariable; import com.stardust.autojs.core.accessibility.AccessibilityBridge; import com.stardust.autojs.core.image.Colors; +import com.stardust.autojs.engine.JavaScriptEngine; import com.stardust.autojs.engine.RhinoJavaScriptEngine; import com.stardust.autojs.engine.ScriptEngine; import com.stardust.autojs.rhino.AndroidClassLoader; @@ -321,22 +322,10 @@ public class ScriptRuntime { } } - public void exit(Object obj) throws Throwable { - mThread.interrupt(); - if (!(obj instanceof Throwable)) { - console.error(obj); - return; - } - Throwable e = (Exception) obj; + public void exit(Exception e) { + engines.myEngine().uncaughtException(e); if (Looper.myLooper() != Looper.getMainLooper()) { - throw e; - } else { - Thread.UncaughtExceptionHandler handler = ((RhinoJavaScriptEngine) engines.myEngine()).getUncaughtExceptionHandler(); - if (handler != null) { - handler.uncaughtException(Thread.currentThread(), e); - } else { - console.error(e); - } + throw new ScriptException(e); } } diff --git a/autojs/src/main/java/com/stardust/autojs/runtime/api/Files.java b/autojs/src/main/java/com/stardust/autojs/runtime/api/Files.java index 0f71e23e..0cf659d5 100644 --- a/autojs/src/main/java/com/stardust/autojs/runtime/api/Files.java +++ b/autojs/src/main/java/com/stardust/autojs/runtime/api/Files.java @@ -39,7 +39,7 @@ public class Files { } public String cwd() { - return ((ScriptEngine.AbstractScriptEngine) mRuntime.engines.myEngine()).cwd(); + return mRuntime.engines.myEngine().cwd(); } public PFileInterface open(String path, String mode, String encoding, int bufferSize) { diff --git a/autojs/src/main/java/com/stardust/autojs/runtime/api/UI.java b/autojs/src/main/java/com/stardust/autojs/runtime/api/UI.java index eb937e78..06dfaaff 100644 --- a/autojs/src/main/java/com/stardust/autojs/runtime/api/UI.java +++ b/autojs/src/main/java/com/stardust/autojs/runtime/api/UI.java @@ -3,10 +3,12 @@ package com.stardust.autojs.runtime.api; import android.content.Context; import android.graphics.drawable.Drawable; +import com.stardust.autojs.core.graphics.ScriptCanvasView; import com.stardust.autojs.core.ui.ConvertLayoutInflater; import com.stardust.autojs.core.ui.JsLayoutInflater; import com.stardust.autojs.core.ui.inflater.DynamicLayoutInflater; import com.stardust.autojs.core.ui.inflater.ValueParser; +import com.stardust.autojs.core.ui.inflater.attrsetter.CanvasViewAttrSetter; import com.stardust.autojs.core.ui.inflater.attrsetter.JsImageViewAttrSetter; import com.stardust.autojs.core.ui.widget.JsImageView; import com.stardust.autojs.rhino.ProxyObject; @@ -38,6 +40,8 @@ public class UI extends ProxyObject { DynamicLayoutInflater inflater = new DynamicLayoutInflater(mValueParser); inflater.registerViewAttrSetter(JsImageView.class.getName(), new JsImageViewAttrSetter(mValueParser)); + inflater.registerViewAttrSetter(ScriptCanvasView.class.getName(), + new CanvasViewAttrSetter(mValueParser, runtime)); mJsLayoutInflater = new ConvertLayoutInflater(inflater); mProperties.put("layoutInflater", mJsLayoutInflater); } diff --git a/common/src/main/java/com/stardust/util/DeveloperUtils.java b/common/src/main/java/com/stardust/util/DeveloperUtils.java index 2b62cf85..e9267caa 100644 --- a/common/src/main/java/com/stardust/util/DeveloperUtils.java +++ b/common/src/main/java/com/stardust/util/DeveloperUtils.java @@ -167,10 +167,10 @@ public class DeveloperUtils { a.finish(); return; } - long[] crc = readCrc(a.getString(crcRes)); - if (!checkDexFile(a, crc)) { - a.finish(); - } + //long[] crc = readCrc(a.getString(crcRes)); + //if (!checkDexFile(a, crc)) { + //a.finish(); + //} } }); diff --git a/common/src/main/java/com/stardust/util/IntentExtras.java b/common/src/main/java/com/stardust/util/IntentExtras.java index 7f987804..5c680857 100644 --- a/common/src/main/java/com/stardust/util/IntentExtras.java +++ b/common/src/main/java/com/stardust/util/IntentExtras.java @@ -14,8 +14,9 @@ import java.util.concurrent.atomic.AtomicInteger; public class IntentExtras implements Serializable { + public static final String EXTRA_ID = "com.stardust.util.IntentExtras.id"; + private static AtomicInteger mMaxId = new AtomicInteger(-1); - private static final String EXTRA_ID = "com.stardust.util.IntentExtras.id"; private static SparseArray> extraStore = new SparseArray<>(); @@ -26,9 +27,18 @@ public class IntentExtras implements Serializable { public static IntentExtras fromIntent(Intent intent) { int id = intent.getIntExtra(EXTRA_ID, -1); if (id < 0) { - throw new IllegalArgumentException(); + return null; } - return new IntentExtras(id); + return fromId(id); + } + + public static IntentExtras fromId(int id) { + Map map = extraStore.get(id); + if (map == null) { + return null; + } + extraStore.remove(id); + return new IntentExtras(id, map); } private Map mMap; @@ -41,15 +51,14 @@ public class IntentExtras implements Serializable { } - private IntentExtras(int id) { + private IntentExtras(int id, Map map) { mId = id; - mMap = extraStore.get(id); - if (mMap == null) { - mMap = new HashMap<>(); - } - extraStore.remove(id); + mMap = map; } + public int getId() { + return mId; + } @SuppressWarnings("unchecked") public T get(String key) { @@ -61,8 +70,15 @@ public class IntentExtras implements Serializable { return this; } + public IntentExtras putAll(IntentExtras extras) { + mMap.putAll(extras.mMap); + return this; + } + public Intent putInIntent(Intent intent) { intent.putExtra(EXTRA_ID, mId); return intent; } + + }