just to save works
This commit is contained in:
@@ -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 {
|
||||
|
||||
24
app/src/main/assets/sample/画图/函数图像.js
Normal file
24
app/src/main/assets/sample/画图/函数图像.js
Normal file
@@ -0,0 +1,24 @@
|
||||
"ui";
|
||||
ui.layout(
|
||||
<frame>
|
||||
<canvas id="graphic" w="*" h="*"/>
|
||||
</frame>
|
||||
);
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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<Path> 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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -3,14 +3,7 @@
|
||||
android:layout_width="600dp"
|
||||
android:layout_height="600dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:padding="200dp"
|
||||
android:src="@drawable/ic_android_eat_js"/>
|
||||
|
||||
<com.stardust.scriptdroid.ui.settings.PaintView
|
||||
<com.stardust.scriptdroid.ui.settings.TestSurfaceView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
>
|
||||
<activity
|
||||
android:name=".execution.ScriptExecuteActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
android:theme="@style/AppTheme"/>
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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
|
||||
* <p>
|
||||
* Licensed under the MIT License:
|
||||
* <p>
|
||||
* 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:
|
||||
* <p>
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
* <p>
|
||||
* 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";
|
||||
|
||||
|
||||
@@ -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<ScriptCanvasView> {
|
||||
|
||||
private ScriptRuntime mScriptRuntime;
|
||||
|
||||
public CanvasViewAttrSetter(ValueParser valueParser, ScriptRuntime runtime) {
|
||||
super(valueParser);
|
||||
mScriptRuntime = runtime;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ViewCreator<ScriptCanvasView> getCreator() {
|
||||
return (context, attrs) -> new ScriptCanvasView(context, new EventEmitter(mScriptRuntime.bridges));
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,13 @@ public interface ScriptEngine<S extends ScriptSource> {
|
||||
|
||||
Object getTag(String key);
|
||||
|
||||
String cwd();
|
||||
|
||||
void uncaughtException(Exception throwable);
|
||||
|
||||
Exception getUncaughtException();
|
||||
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@@ -60,11 +67,12 @@ public interface ScriptEngine<S extends ScriptSource> {
|
||||
private Map<String, Object> 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<S extends ScriptSource> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<S extends ScriptSource> implements ScriptEngine<S> {
|
||||
|
||||
private final ScriptEngine<S> mScriptEngine;
|
||||
|
||||
public ScriptEngineProxy(ScriptEngine<S> 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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
//}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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<Map<String, Object>> 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<String, Object> map = extraStore.get(id);
|
||||
if (map == null) {
|
||||
return null;
|
||||
}
|
||||
extraStore.remove(id);
|
||||
return new IntentExtras(id, map);
|
||||
}
|
||||
|
||||
private Map<String, Object> mMap;
|
||||
@@ -41,15 +51,14 @@ public class IntentExtras implements Serializable {
|
||||
}
|
||||
|
||||
|
||||
private IntentExtras(int id) {
|
||||
private IntentExtras(int id, Map<String, Object> 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> 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user