增加 可选特性continuation
增加 协程示例
This commit is contained in:
1 parent
7e7a7556e8
commit
975940dced
23 files changed
+450
-261
No files matched your search
@@ -0,0 +1,24 @@
|
|||||||
|
"ui";
|
||||||
|
|
||||||
|
ui.layout(
|
||||||
|
<frame bg="#4fc3f7">
|
||||||
|
<text textColor="white" textSize="18sp" layout_gravity="center">
|
||||||
|
UI中使用协程
|
||||||
|
</text>
|
||||||
|
</frame>
|
||||||
|
);
|
||||||
|
|
||||||
|
continuation.delay(5000);
|
||||||
|
if (!requestScreenCapture()) {
|
||||||
|
dialogs.alert("请授予软件截图权限").await();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 退出应用对话框
|
||||||
|
ui.emitter.on("back_pressed", function (e) {
|
||||||
|
e.consumed = true;
|
||||||
|
let exit = dialogs.confirm("确定要退出程序").await();
|
||||||
|
if (exit) {
|
||||||
|
ui.finish();
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"name": "协程UI示例",
|
||||||
|
"main": "main.js",
|
||||||
|
"ignore": [
|
||||||
|
"build"
|
||||||
|
],
|
||||||
|
"packageName": "com.example.cont.ui",
|
||||||
|
"versionName": "1.0.0",
|
||||||
|
"versionCode": 1,
|
||||||
|
"useFeatures": ["continuation"]
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Nothing
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
// 注意,要使用协程这个特性,必须使用项目功能,并且在project.json配置好features属性
|
||||||
|
|
||||||
|
|
||||||
|
// delay不同于sleep,不会阻塞当前线程
|
||||||
|
function delay(millis) {
|
||||||
|
var cont = continuation.create();
|
||||||
|
setTimeout(()=>{
|
||||||
|
cont.resume();
|
||||||
|
}, millis);
|
||||||
|
cont.await();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 异步IO例子,在另一个线程读取文件,读取完成后返回当前线程继续执行
|
||||||
|
function read(path) {
|
||||||
|
var cont = continuation.create();
|
||||||
|
threads.start(function(){
|
||||||
|
try {
|
||||||
|
cont.resume(files.read(path));
|
||||||
|
}catch(err){
|
||||||
|
cont.resumeError(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return cont.await();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用Promise和协程的例子
|
||||||
|
function add(a, b) {
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
var sum = a + b;
|
||||||
|
resolve(sum);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
toastLog("Hello, Continuation!");
|
||||||
|
|
||||||
|
//3秒后发出提示
|
||||||
|
setTimeout(()=>{
|
||||||
|
toastLog("3秒后....");
|
||||||
|
}, 3000);
|
||||||
|
|
||||||
|
// 你可以尝试把delay更换成sleep,看会发生什么!
|
||||||
|
delay(6000);
|
||||||
|
toastLog("6秒后...");
|
||||||
|
|
||||||
|
try {
|
||||||
|
toastLog("读取文件hello.txt: " + read("./hello.txt"));
|
||||||
|
}catch(err){
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
var sum = add(1, 2).await();
|
||||||
|
toastLog("1 + 2 = " + sum);
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"name": "协程HelloWorld",
|
||||||
|
"main": "main.js",
|
||||||
|
"ignore": [
|
||||||
|
"build"
|
||||||
|
],
|
||||||
|
"packageName": "com.example.cont.helloworld",
|
||||||
|
"versionName": "1.0.0",
|
||||||
|
"versionCode": 1,
|
||||||
|
"useFeatures": ["continuation"]
|
||||||
|
}
|
||||||
@@ -16,16 +16,7 @@ runtime.init();
|
|||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
//内部函数
|
||||||
//初始化不依赖环境的模块
|
|
||||||
global.JSON = require('__json2__.js');
|
|
||||||
global.util = require('__util__.js');
|
|
||||||
global.device = runtime.device;
|
|
||||||
|
|
||||||
//设置JavaScriptBridges用于与Java层的交互和数据转换
|
|
||||||
runtime.bridges.setBridges(require('__bridges__.js'));
|
|
||||||
|
|
||||||
//一些内部函数
|
|
||||||
global.__asGlobal__ = function (obj, functions) {
|
global.__asGlobal__ = function (obj, functions) {
|
||||||
var len = functions.length;
|
var len = functions.length;
|
||||||
for (var i = 0; i < len; i++) {
|
for (var i = 0; i < len; i++) {
|
||||||
@@ -50,7 +41,6 @@ runtime.init();
|
|||||||
exit(err);
|
exit(err);
|
||||||
} else if (err instanceof Error) {
|
} else if (err instanceof Error) {
|
||||||
exit(new org.mozilla.javascript.EvaluatorException(err.name + ": " + err.message, err.fileName, err.lineNumber));
|
exit(new org.mozilla.javascript.EvaluatorException(err.name + ": " + err.message, err.fileName, err.lineNumber));
|
||||||
//new java.lang.RuntimeException(err.name + ": " + err.message + "\n" + err.stack));
|
|
||||||
} else {
|
} else {
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
@@ -58,12 +48,24 @@ runtime.init();
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 初始化基础模块
|
||||||
|
global.timers = require('__timers__.js')(runtime, global);
|
||||||
|
|
||||||
|
//初始化不依赖环境的模块
|
||||||
|
global.JSON = require('__json2__.js');
|
||||||
|
global.util = require('__util__.js');
|
||||||
|
global.device = runtime.device;
|
||||||
|
global.Promise = require('promise.js');
|
||||||
|
|
||||||
|
//设置JavaScriptBridges用于与Java层的交互和数据转换
|
||||||
|
runtime.bridges.setBridges(require('__bridges__.js'));
|
||||||
|
|
||||||
//初始化全局函数
|
//初始化全局函数
|
||||||
require("__globals__")(runtime, global);
|
require("__globals__")(runtime, global);
|
||||||
//初始化一般模块
|
//初始化一般模块
|
||||||
(function (scope) {
|
(function (scope) {
|
||||||
var modules = ['app', 'automator', 'console', 'dialogs', 'io', 'selector', 'shell', 'web', 'ui',
|
var modules = ['app', 'automator', 'console', 'dialogs', 'io', 'selector', 'shell', 'web', 'ui',
|
||||||
"images", "timers", "threads", "events", "engines", "RootAutomator", "http", "storages", "floaty",
|
"images", "threads", "events", "engines", "RootAutomator", "http", "storages", "floaty",
|
||||||
"sensors", "media", "plugins", "continuation"];
|
"sensors", "media", "plugins", "continuation"];
|
||||||
var len = modules.length;
|
var len = modules.length;
|
||||||
for (var i = 0; i < len; i++) {
|
for (var i = 0; i < len; i++) {
|
||||||
@@ -72,11 +74,6 @@ runtime.init();
|
|||||||
}
|
}
|
||||||
})(global);
|
})(global);
|
||||||
|
|
||||||
global.Promise = require('promise.js');
|
|
||||||
global.Promise.prototype.await = function () {
|
|
||||||
return continuation.await(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
importClass(android.view.KeyEvent);
|
importClass(android.view.KeyEvent);
|
||||||
importClass(com.stardust.autojs.core.util.Shell);
|
importClass(com.stardust.autojs.core.util.Shell);
|
||||||
importClass(android.graphics.Paint);
|
importClass(android.graphics.Paint);
|
||||||
|
|||||||
@@ -44,5 +44,21 @@ module.exports = function (runtime, global) {
|
|||||||
throw new TypeError('cannot await ' + any);
|
throw new TypeError('cannot await ' + any);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
continuation.delay = function (millis) {
|
||||||
|
var cont = continuation.create();
|
||||||
|
setTimeout(()=>{
|
||||||
|
cont.resume();
|
||||||
|
}, millis);
|
||||||
|
cont.await();
|
||||||
|
}
|
||||||
|
|
||||||
|
continuation.__defineGetter__('enabled', function () {
|
||||||
|
return engines.myEngine().hasFeature("continuation");
|
||||||
|
});
|
||||||
|
|
||||||
|
global.Promise.prototype.await = function () {
|
||||||
|
return continuation.await(this);
|
||||||
|
}
|
||||||
|
|
||||||
return continuation;
|
return continuation;
|
||||||
}
|
}
|
||||||
@@ -41,7 +41,7 @@ module.exports = function (runtime, scope) {
|
|||||||
|
|
||||||
http.request = function (url, options, callback) {
|
http.request = function (url, options, callback) {
|
||||||
var cont = null;
|
var cont = null;
|
||||||
if (!callback && ui.isUiThread()) {
|
if (!callback && ui.isUiThread() && continuation.enabled) {
|
||||||
cont = continuation.create();
|
cont = continuation.create();
|
||||||
}
|
}
|
||||||
var call = http.client().newCall(http.buildRequest(url, options));
|
var call = http.client().newCall(http.buildRequest(url, options));
|
||||||
@@ -59,7 +59,7 @@ module.exports = function (runtime, scope) {
|
|||||||
callback && callback(null, ex);
|
callback && callback(null, ex);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
if(cont) {
|
if (cont) {
|
||||||
return cont.await();
|
return cont.await();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ module.exports = function (runtime, scope) {
|
|||||||
if(landscape === false){
|
if(landscape === false){
|
||||||
orientation = ScreenCapturer.ORIENTATION_PORTRAIT;
|
orientation = ScreenCapturer.ORIENTATION_PORTRAIT;
|
||||||
}
|
}
|
||||||
return ResultAdapter.promise(javaImages.requestScreenCapture(orientation)).await();
|
return ResultAdapter.wait(javaImages.requestScreenCapture(orientation));
|
||||||
}
|
}
|
||||||
|
|
||||||
images.save = function (img, path, format, quality) {
|
images.save = function (img, path, format, quality) {
|
||||||
|
|||||||
@@ -1,12 +1,26 @@
|
|||||||
|
|
||||||
module.exports = function(__runtime__, scope){
|
module.exports = function (__runtime__, scope) {
|
||||||
var threads = Object.create(__runtime__.threads);
|
var threads = Object.create(__runtime__.threads);
|
||||||
|
|
||||||
|
|
||||||
scope.sync = function(func, lock){
|
scope.sync = function (func, lock) {
|
||||||
lock = lock || null;
|
lock = lock || null;
|
||||||
return new org.mozilla.javascript.Synchronizer(func, lock);
|
return new org.mozilla.javascript.Synchronizer(func, lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
return threads;
|
global.Promise.prototype.wait = function () {
|
||||||
|
var disposable = threads.disposable();
|
||||||
|
promise.then(result => {
|
||||||
|
disposable.setAndNotify({ result: result });
|
||||||
|
}).catch(error => {
|
||||||
|
cont.resumeError({ error: error });
|
||||||
|
});
|
||||||
|
var r = cont.blockedGet();
|
||||||
|
if (r.error) {
|
||||||
|
throw r.error;
|
||||||
|
}
|
||||||
|
return r.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return threads;
|
||||||
}
|
}
|
||||||
@@ -47,7 +47,7 @@ ResultAdapter.prototype.setError = function (error) {
|
|||||||
ResultAdapter.prototype.callback = function () {
|
ResultAdapter.prototype.callback = function () {
|
||||||
var that = this;
|
var that = this;
|
||||||
return function (result, error) {
|
return function (result, error) {
|
||||||
if(that.result !== undefined){
|
if (that.result !== undefined) {
|
||||||
that.result = {
|
that.result = {
|
||||||
result: result,
|
result: result,
|
||||||
error: error
|
error: error
|
||||||
@@ -63,21 +63,33 @@ ResultAdapter.prototype.callback = function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ResultAdapter.prototype.get = function () {
|
ResultAdapter.prototype.get = function () {
|
||||||
if(this.result){
|
if (this.result) {
|
||||||
return getOrThrow(this.result);
|
return getOrThrow(this.result);
|
||||||
}
|
}
|
||||||
this.result = null;
|
this.result = null;
|
||||||
return this.impl.get();
|
return this.impl.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultAdapter.promise = function(promiseAdapter) {
|
ResultAdapter.promise = function (promiseAdapter) {
|
||||||
return new Promise(function(resolve, reject){
|
return new Promise(function (resolve, reject) {
|
||||||
promiseAdapter.onResolve(function(result) {
|
promiseAdapter.onResolve(function (result) {
|
||||||
resolve(result);
|
resolve(result);
|
||||||
}).onReject(function(error){
|
}).onReject(function (error) {
|
||||||
reject(error);
|
reject(error);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ResultAdapter.wait = function (promise) {
|
||||||
|
var proto = Object.getPrototypeOf(promise);
|
||||||
|
if (!proto || proto.constructor !== Promise) {
|
||||||
|
promise = ResultAdapter.promise(promise);
|
||||||
|
}
|
||||||
|
if (continuation.enabled) {
|
||||||
|
return promise.await();
|
||||||
|
} else {
|
||||||
|
return promise.wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = ResultAdapter;
|
module.exports = ResultAdapter;
|
||||||
@@ -63,7 +63,6 @@ public class BlockedMaterialDialog extends MaterialDialog {
|
|||||||
private VolatileDispose<Object> mResultBox;
|
private VolatileDispose<Object> mResultBox;
|
||||||
private UiHandler mUiHandler;
|
private UiHandler mUiHandler;
|
||||||
private Object mCallback;
|
private Object mCallback;
|
||||||
private Continuation mContinuation;
|
|
||||||
private ScriptBridges mScriptBridges;
|
private ScriptBridges mScriptBridges;
|
||||||
private boolean mNotified = false;
|
private boolean mNotified = false;
|
||||||
|
|
||||||
@@ -75,10 +74,6 @@ public class BlockedMaterialDialog extends MaterialDialog {
|
|||||||
mCallback = callback;
|
mCallback = callback;
|
||||||
if (Looper.getMainLooper() != Looper.myLooper()) {
|
if (Looper.getMainLooper() != Looper.myLooper()) {
|
||||||
mResultBox = new VolatileDispose<>();
|
mResultBox = new VolatileDispose<>();
|
||||||
} else {
|
|
||||||
if (mCallback == null) {
|
|
||||||
mContinuation = runtime.createContinuation();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,9 +91,6 @@ public class BlockedMaterialDialog extends MaterialDialog {
|
|||||||
if (mCallback != null) {
|
if (mCallback != null) {
|
||||||
mScriptBridges.callFunction(mCallback, null, new Object[]{r});
|
mScriptBridges.callFunction(mCallback, null, new Object[]{r});
|
||||||
}
|
}
|
||||||
if (mContinuation != null) {
|
|
||||||
mContinuation.resumeWith(Continuation.Result.Companion.success(r));
|
|
||||||
}
|
|
||||||
if (mResultBox != null) {
|
if (mResultBox != null) {
|
||||||
mResultBox.setAndNotify(r);
|
mResultBox.setAndNotify(r);
|
||||||
}
|
}
|
||||||
@@ -179,9 +171,6 @@ public class BlockedMaterialDialog extends MaterialDialog {
|
|||||||
} else {
|
} else {
|
||||||
mUiHandler.post(Builder.super::show);
|
mUiHandler.post(Builder.super::show);
|
||||||
}
|
}
|
||||||
if (mContinuation != null) {
|
|
||||||
mContinuation.suspend();
|
|
||||||
}
|
|
||||||
if (mResultBox != null) {
|
if (mResultBox != null) {
|
||||||
return mResultBox.blockedGetOrThrow(ScriptInterruptedException.class);
|
return mResultBox.blockedGetOrThrow(ScriptInterruptedException.class);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -46,8 +46,7 @@ public class LoopBasedJavaScriptEngine extends RhinoJavaScriptEngine {
|
|||||||
Object o = LoopBasedJavaScriptEngine.super.execute((JavaScriptSource) source);
|
Object o = LoopBasedJavaScriptEngine.super.execute((JavaScriptSource) source);
|
||||||
if (callback != null)
|
if (callback != null)
|
||||||
callback.onResult(o);
|
callback.onResult(o);
|
||||||
} catch (ContinuationPending pending) {
|
} catch (ContinuationPending ignored) {
|
||||||
pending.printStackTrace();
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (callback == null) {
|
if (callback == null) {
|
||||||
throw e;
|
throw e;
|
||||||
@@ -61,8 +60,17 @@ public class LoopBasedJavaScriptEngine extends RhinoJavaScriptEngine {
|
|||||||
mHandler.post(r);
|
mHandler.post(r);
|
||||||
if (!mLooping && Looper.myLooper() != Looper.getMainLooper()) {
|
if (!mLooping && Looper.myLooper() != Looper.getMainLooper()) {
|
||||||
mLooping = true;
|
mLooping = true;
|
||||||
Looper.loop();
|
while (true) {
|
||||||
mLooping = false;
|
try {
|
||||||
|
Looper.loop();
|
||||||
|
} catch (ContinuationPending ignored) {
|
||||||
|
continue;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
mLooping = false;
|
||||||
|
throw t;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,8 +87,7 @@ public class LoopBasedJavaScriptEngine extends RhinoJavaScriptEngine {
|
|||||||
@Override
|
@Override
|
||||||
public synchronized void destroy() {
|
public synchronized void destroy() {
|
||||||
Thread thread = getThread();
|
Thread thread = getThread();
|
||||||
if (thread != null)
|
LooperHelper.quitForThread(thread);
|
||||||
LooperHelper.quitForThread(thread);
|
|
||||||
super.destroy();
|
super.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,197 +0,0 @@
|
|||||||
package com.stardust.autojs.engine;
|
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.View;
|
|
||||||
|
|
||||||
import com.stardust.autojs.BuildConfig;
|
|
||||||
import com.stardust.autojs.core.ui.ViewExtras;
|
|
||||||
import com.stardust.autojs.engine.module.AssetAndUrlModuleSourceProvider;
|
|
||||||
import com.stardust.autojs.rhino.RhinoAndroidHelper;
|
|
||||||
import com.stardust.autojs.rhino.TopLevelScope;
|
|
||||||
import com.stardust.autojs.runtime.ScriptRuntime;
|
|
||||||
import com.stardust.autojs.script.JavaScriptSource;
|
|
||||||
import com.stardust.automator.UiObjectCollection;
|
|
||||||
import com.stardust.pio.UncheckedIOException;
|
|
||||||
|
|
||||||
import org.mozilla.javascript.Context;
|
|
||||||
import org.mozilla.javascript.Script;
|
|
||||||
import org.mozilla.javascript.Scriptable;
|
|
||||||
import org.mozilla.javascript.ScriptableObject;
|
|
||||||
import org.mozilla.javascript.commonjs.module.RequireBuilder;
|
|
||||||
import org.mozilla.javascript.commonjs.module.provider.SoftCachingModuleScriptProvider;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.Reader;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by Stardust on 2017/4/2.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class RhinoJavaScriptEngine extends JavaScriptEngine {
|
|
||||||
|
|
||||||
public static final String SOURCE_NAME_INIT = "<init>";
|
|
||||||
|
|
||||||
private static final String LOG_TAG = "RhinoJavaScriptEngine";
|
|
||||||
|
|
||||||
private static final String MODULES_PATH = "modules";
|
|
||||||
private static Script sInitScript;
|
|
||||||
private static final ConcurrentHashMap<Context, RhinoJavaScriptEngine> sContextEngineMap = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
private Context mContext;
|
|
||||||
private TopLevelScope mScriptable;
|
|
||||||
private Thread mThread;
|
|
||||||
private android.content.Context mAndroidContext;
|
|
||||||
|
|
||||||
public RhinoJavaScriptEngine(android.content.Context context) {
|
|
||||||
mAndroidContext = context;
|
|
||||||
mContext = enterContext();
|
|
||||||
mScriptable = createScope(mContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void put(String name, Object value) {
|
|
||||||
ScriptableObject.putProperty(mScriptable, name, Context.javaToJS(value, mScriptable));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setRuntime(ScriptRuntime runtime) {
|
|
||||||
super.setRuntime(runtime);
|
|
||||||
runtime.setTopLevelScope(mScriptable);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object doExecution(JavaScriptSource source) {
|
|
||||||
Reader reader = source.getNonNullScriptReader();
|
|
||||||
try {
|
|
||||||
reader = preprocess(reader);
|
|
||||||
Script script = mContext.compileReader(reader, source.toString(), 1, null);
|
|
||||||
return mContext.executeScriptWithContinuations(script, mScriptable);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new UncheckedIOException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Reader preprocess(Reader script) throws IOException {
|
|
||||||
return script;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void forceStop() {
|
|
||||||
Log.d(LOG_TAG, "forceStop: interrupt Thread: " + mThread);
|
|
||||||
mThread.interrupt();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void destroy() {
|
|
||||||
super.destroy();
|
|
||||||
Log.d(LOG_TAG, "on destroy");
|
|
||||||
sContextEngineMap.remove(getContext());
|
|
||||||
Context.exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Thread getThread() {
|
|
||||||
return mThread;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Override
|
|
||||||
public void init() {
|
|
||||||
mThread = Thread.currentThread();
|
|
||||||
ScriptableObject.putProperty(mScriptable, "__engine__", this);
|
|
||||||
initRequireBuilder(mContext, mScriptable);
|
|
||||||
mContext.executeScriptWithContinuations(getInitScript(), mScriptable);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Script getInitScript() {
|
|
||||||
if (sInitScript == null || BuildConfig.DEBUG) {
|
|
||||||
try {
|
|
||||||
Reader reader = new InputStreamReader(mAndroidContext.getAssets().open("init.js"));
|
|
||||||
sInitScript = mContext.compileReader(reader, SOURCE_NAME_INIT, 1, null);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new UncheckedIOException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sInitScript;
|
|
||||||
}
|
|
||||||
|
|
||||||
void initRequireBuilder(Context context, Scriptable scope) {
|
|
||||||
AssetAndUrlModuleSourceProvider provider = new AssetAndUrlModuleSourceProvider(mAndroidContext, MODULES_PATH,
|
|
||||||
Collections.singletonList(new File("/").toURI()));
|
|
||||||
new RequireBuilder()
|
|
||||||
.setModuleScriptProvider(new SoftCachingModuleScriptProvider(provider))
|
|
||||||
.setSandboxed(true)
|
|
||||||
.createRequire(context, scope)
|
|
||||||
.install(scope);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public Context getContext() {
|
|
||||||
return mContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Scriptable getScriptable() {
|
|
||||||
return mScriptable;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected TopLevelScope createScope(Context context) {
|
|
||||||
TopLevelScope topLevelScope = new TopLevelScope();
|
|
||||||
topLevelScope.initStandardObjects(context, false);
|
|
||||||
return topLevelScope;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Context enterContext() {
|
|
||||||
Context context = new RhinoAndroidHelper(mAndroidContext).enterContext();
|
|
||||||
setupContext(context);
|
|
||||||
sContextEngineMap.put(context, this);
|
|
||||||
return context;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setupContext(Context context) {
|
|
||||||
context.setOptimizationLevel(-1);
|
|
||||||
context.setLanguageVersion(Context.VERSION_ES6);
|
|
||||||
context.setLocale(Locale.getDefault());
|
|
||||||
context.setWrapFactory(new WrapFactory());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static RhinoJavaScriptEngine getEngineOfContext(Context context) {
|
|
||||||
return sContextEngineMap.get(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class WrapFactory extends org.mozilla.javascript.WrapFactory {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object wrap(Context cx, Scriptable scope, Object obj, Class<?> staticType) {
|
|
||||||
Object result;
|
|
||||||
if (obj instanceof String) {
|
|
||||||
result = getRuntime().bridges.toString(obj.toString());
|
|
||||||
} else if (staticType == UiObjectCollection.class) {
|
|
||||||
result = getRuntime().bridges.asArray(obj);
|
|
||||||
} else {
|
|
||||||
result = super.wrap(cx, scope, obj, staticType);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Scriptable wrapAsJavaObject(Context cx, Scriptable scope, Object javaObject, Class<?> staticType) {
|
|
||||||
Scriptable result;
|
|
||||||
if (javaObject instanceof View) {
|
|
||||||
result = ViewExtras.getNativeView(scope, (View) javaObject, staticType, getRuntime());
|
|
||||||
} else {
|
|
||||||
result = super.wrapAsJavaObject(cx, scope, javaObject, staticType);
|
|
||||||
}
|
|
||||||
//Log.d(LOG_TAG, "wrapAsJavaObject: java = " + javaObject + ", result = " + result + ", scope = " + scope);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,191 @@
|
|||||||
|
package com.stardust.autojs.engine
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.View
|
||||||
|
|
||||||
|
import com.stardust.autojs.BuildConfig
|
||||||
|
import com.stardust.autojs.core.ui.ViewExtras
|
||||||
|
import com.stardust.autojs.engine.module.AssetAndUrlModuleSourceProvider
|
||||||
|
import com.stardust.autojs.execution.ExecutionConfig
|
||||||
|
import com.stardust.autojs.project.ScriptConfig
|
||||||
|
import com.stardust.autojs.rhino.RhinoAndroidHelper
|
||||||
|
import com.stardust.autojs.rhino.TopLevelScope
|
||||||
|
import com.stardust.autojs.runtime.ScriptRuntime
|
||||||
|
import com.stardust.autojs.script.JavaScriptSource
|
||||||
|
import com.stardust.automator.UiObjectCollection
|
||||||
|
import com.stardust.pio.UncheckedIOException
|
||||||
|
|
||||||
|
import org.mozilla.javascript.Context
|
||||||
|
import org.mozilla.javascript.Script
|
||||||
|
import org.mozilla.javascript.Scriptable
|
||||||
|
import org.mozilla.javascript.ScriptableObject
|
||||||
|
import org.mozilla.javascript.commonjs.module.RequireBuilder
|
||||||
|
import org.mozilla.javascript.commonjs.module.provider.SoftCachingModuleScriptProvider
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
import java.io.IOException
|
||||||
|
import java.io.InputStreamReader
|
||||||
|
import java.io.Reader
|
||||||
|
import java.net.URI
|
||||||
|
import java.util.Locale
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Stardust on 2017/4/2.
|
||||||
|
*/
|
||||||
|
|
||||||
|
open class RhinoJavaScriptEngine(private val mAndroidContext: android.content.Context) : JavaScriptEngine() {
|
||||||
|
|
||||||
|
val context: Context
|
||||||
|
private val mScriptable: TopLevelScope
|
||||||
|
lateinit var thread: Thread
|
||||||
|
private set
|
||||||
|
|
||||||
|
private val initScript: Script
|
||||||
|
get() {
|
||||||
|
return sInitScript ?: {
|
||||||
|
try {
|
||||||
|
val reader = InputStreamReader(mAndroidContext.assets.open("init.js"))
|
||||||
|
val script = context.compileReader(reader, SOURCE_NAME_INIT, 1, null)
|
||||||
|
sInitScript = script
|
||||||
|
script
|
||||||
|
} catch (e: IOException) {
|
||||||
|
throw UncheckedIOException(e)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
val scriptable: Scriptable
|
||||||
|
get() = mScriptable
|
||||||
|
|
||||||
|
init {
|
||||||
|
this.context = enterContext()
|
||||||
|
mScriptable = createScope(this.context)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun put(name: String, value: Any?) {
|
||||||
|
ScriptableObject.putProperty(mScriptable, name, Context.javaToJS(value, mScriptable))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setRuntime(runtime: ScriptRuntime) {
|
||||||
|
super.setRuntime(runtime)
|
||||||
|
runtime.topLevelScope = mScriptable
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun doExecution(source: JavaScriptSource): Any {
|
||||||
|
var reader = source.nonNullScriptReader
|
||||||
|
try {
|
||||||
|
reader = preprocess(reader)
|
||||||
|
val script = context.compileReader(reader, source.toString(), 1, null)
|
||||||
|
return if (hasFeature(ScriptConfig.FEATURE_CONTINUATION)) {
|
||||||
|
context.executeScriptWithContinuations(script, mScriptable)
|
||||||
|
} else {
|
||||||
|
script.exec(context, mScriptable)
|
||||||
|
}
|
||||||
|
} catch (e: IOException) {
|
||||||
|
throw UncheckedIOException(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun hasFeature(feature: String): Boolean {
|
||||||
|
val config = getTag(ExecutionConfig.tag) as ExecutionConfig?
|
||||||
|
return config != null && config.scriptConfig.hasFeature(feature)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(IOException::class)
|
||||||
|
protected fun preprocess(script: Reader): Reader {
|
||||||
|
return script
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun forceStop() {
|
||||||
|
Log.d(LOG_TAG, "forceStop: interrupt Thread: $thread")
|
||||||
|
thread.interrupt()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
override fun destroy() {
|
||||||
|
super.destroy()
|
||||||
|
Log.d(LOG_TAG, "on destroy")
|
||||||
|
sContextEngineMap.remove(context)
|
||||||
|
Context.exit()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun init() {
|
||||||
|
thread = Thread.currentThread()
|
||||||
|
ScriptableObject.putProperty(mScriptable, "__engine__", this)
|
||||||
|
initRequireBuilder(context, mScriptable)
|
||||||
|
context.executeScriptWithContinuations(initScript, mScriptable)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun initRequireBuilder(context: Context, scope: Scriptable) {
|
||||||
|
val provider = AssetAndUrlModuleSourceProvider(mAndroidContext, MODULES_PATH,
|
||||||
|
listOf<URI>(File("/").toURI()))
|
||||||
|
RequireBuilder()
|
||||||
|
.setModuleScriptProvider(SoftCachingModuleScriptProvider(provider))
|
||||||
|
.setSandboxed(true)
|
||||||
|
.createRequire(context, scope)
|
||||||
|
.install(scope)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun createScope(context: Context): TopLevelScope {
|
||||||
|
val topLevelScope = TopLevelScope()
|
||||||
|
topLevelScope.initStandardObjects(context, false)
|
||||||
|
return topLevelScope
|
||||||
|
}
|
||||||
|
|
||||||
|
fun enterContext(): Context {
|
||||||
|
val context = RhinoAndroidHelper(mAndroidContext).enterContext()
|
||||||
|
setupContext(context)
|
||||||
|
sContextEngineMap[context] = this
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun setupContext(context: Context) {
|
||||||
|
context.optimizationLevel = -1
|
||||||
|
context.languageVersion = Context.VERSION_ES6
|
||||||
|
context.locale = Locale.getDefault()
|
||||||
|
context.wrapFactory = WrapFactory()
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class WrapFactory : org.mozilla.javascript.WrapFactory() {
|
||||||
|
|
||||||
|
override fun wrap(cx: Context, scope: Scriptable, obj: Any?, staticType: Class<*>?): Any? {
|
||||||
|
return when {
|
||||||
|
obj is String -> runtime.bridges.toString(obj.toString())
|
||||||
|
staticType == UiObjectCollection::class.java -> runtime.bridges.asArray(obj)
|
||||||
|
else -> super.wrap(cx, scope, obj, staticType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun wrapAsJavaObject(cx: Context?, scope: Scriptable, javaObject: Any?, staticType: Class<*>?): Scriptable? {
|
||||||
|
//Log.d(LOG_TAG, "wrapAsJavaObject: java = " + javaObject + ", result = " + result + ", scope = " + scope);
|
||||||
|
return if (javaObject is View) {
|
||||||
|
ViewExtras.getNativeView(scope, javaObject, staticType, runtime)
|
||||||
|
} else {
|
||||||
|
super.wrapAsJavaObject(cx, scope, javaObject, staticType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
val SOURCE_NAME_INIT = "<init>"
|
||||||
|
|
||||||
|
private val LOG_TAG = "RhinoJavaScriptEngine"
|
||||||
|
|
||||||
|
private val MODULES_PATH = "modules"
|
||||||
|
private var sInitScript: Script? = null
|
||||||
|
private val sContextEngineMap = ConcurrentHashMap<Context, RhinoJavaScriptEngine>()
|
||||||
|
|
||||||
|
|
||||||
|
fun getEngineOfContext(context: Context): RhinoJavaScriptEngine? {
|
||||||
|
return sContextEngineMap[context]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package com.stardust.autojs.execution
|
|||||||
|
|
||||||
import android.os.Parcel
|
import android.os.Parcel
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
import com.stardust.autojs.project.ScriptConfig
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -13,8 +14,7 @@ data class ExecutionConfig(var workingDirectory: String = "",
|
|||||||
var delay: Long = 0,
|
var delay: Long = 0,
|
||||||
var interval: Long = 0,
|
var interval: Long = 0,
|
||||||
var loopTimes: Int = 1,
|
var loopTimes: Int = 1,
|
||||||
var uiMode: Boolean = false,
|
var scriptConfig: ScriptConfig = ScriptConfig()) : Parcelable {
|
||||||
var features: Int = 0) : Parcelable {
|
|
||||||
|
|
||||||
|
|
||||||
private val mArguments = HashMap<String, Any>()
|
private val mArguments = HashMap<String, Any>()
|
||||||
@@ -88,9 +88,6 @@ data class ExecutionConfig(var workingDirectory: String = "",
|
|||||||
val default: ExecutionConfig
|
val default: ExecutionConfig
|
||||||
get() = ExecutionConfig()
|
get() = ExecutionConfig()
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
val featureContinuation = 1
|
|
||||||
|
|
||||||
override fun createFromParcel(parcel: Parcel): ExecutionConfig {
|
override fun createFromParcel(parcel: Parcel): ExecutionConfig {
|
||||||
return ExecutionConfig(parcel)
|
return ExecutionConfig(parcel)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,13 +8,14 @@ import com.stardust.autojs.runtime.exception.ScriptInterruptedException;
|
|||||||
import com.stardust.autojs.script.ScriptSource;
|
import com.stardust.autojs.script.ScriptSource;
|
||||||
import com.stardust.lang.ThreadCompat;
|
import com.stardust.lang.ThreadCompat;
|
||||||
|
|
||||||
|
import org.mozilla.javascript.ContinuationPending;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Stardust on 2017/5/1.
|
* Created by Stardust on 2017/5/1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class RunnableScriptExecution extends ScriptExecution.AbstractScriptExecution implements Runnable {
|
public class RunnableScriptExecution extends ScriptExecution.AbstractScriptExecution implements Runnable {
|
||||||
|
|
||||||
|
|
||||||
private static final String TAG = "RunnableJSExecution";
|
private static final String TAG = "RunnableJSExecution";
|
||||||
private ScriptEngine mScriptEngine;
|
private ScriptEngine mScriptEngine;
|
||||||
private ScriptEngineManager mScriptEngineManager;
|
private ScriptEngineManager mScriptEngineManager;
|
||||||
|
|||||||
@@ -18,4 +18,5 @@ public class LaunchConfig {
|
|||||||
public void setHideLogs(boolean hideLogs) {
|
public void setHideLogs(boolean hideLogs) {
|
||||||
mHideLogs = hideLogs;
|
mHideLogs = hideLogs;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
package com.stardust.autojs.project;
|
package com.stardust.autojs.project;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
@@ -12,7 +11,9 @@ import com.stardust.pio.PFiles;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Stardust on 2018/1/24.
|
* Created by Stardust on 2018/1/24.
|
||||||
@@ -51,31 +52,38 @@ public class ProjectConfig {
|
|||||||
@SerializedName("icon")
|
@SerializedName("icon")
|
||||||
private String mIcon;
|
private String mIcon;
|
||||||
|
|
||||||
|
@SerializedName("scripts")
|
||||||
|
private Map<String, ScriptConfig> mScriptConfigs = new HashMap<>();
|
||||||
|
|
||||||
|
@SerializedName("useFeatures")
|
||||||
|
private List<String> mFeatures = new ArrayList<>();
|
||||||
|
|
||||||
|
|
||||||
public static ProjectConfig fromJson(String json) {
|
public static ProjectConfig fromJson(String json) {
|
||||||
if (json == null) {
|
if (json == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
ProjectConfig config = GSON.fromJson(json, ProjectConfig.class);
|
ProjectConfig config = GSON.fromJson(json, ProjectConfig.class);
|
||||||
if(!isValid(config)){
|
if (!isValid(config)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isValid(ProjectConfig config) {
|
private static boolean isValid(ProjectConfig config) {
|
||||||
if(TextUtils.isEmpty(config.getName())){
|
if (TextUtils.isEmpty(config.getName())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(TextUtils.isEmpty(config.getPackageName())){
|
if (TextUtils.isEmpty(config.getPackageName())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(TextUtils.isEmpty(config.getVersionName())){
|
if (TextUtils.isEmpty(config.getVersionName())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(TextUtils.isEmpty(config.getMainScriptFile())){
|
if (TextUtils.isEmpty(config.getMainScriptFile())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(config.getVersionCode() == -1){
|
if (config.getVersionCode() == -1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -160,6 +168,10 @@ public class ProjectConfig {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<String, ScriptConfig> getScriptConfigs() {
|
||||||
|
return mScriptConfigs;
|
||||||
|
}
|
||||||
|
|
||||||
public List<String> getAssets() {
|
public List<String> getAssets() {
|
||||||
if (mAssets == null) {
|
if (mAssets == null) {
|
||||||
mAssets = Collections.emptyList();
|
mAssets = Collections.emptyList();
|
||||||
@@ -210,4 +222,30 @@ public class ProjectConfig {
|
|||||||
public String getBuildDir() {
|
public String getBuildDir() {
|
||||||
return "build";
|
return "build";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<String> getFeatures() {
|
||||||
|
return mFeatures;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFeatures(List<String> features) {
|
||||||
|
mFeatures = features;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScriptConfig getScriptConfig(String path) {
|
||||||
|
ScriptConfig config = mScriptConfigs.get(path);
|
||||||
|
if (config == null) {
|
||||||
|
config = new ScriptConfig();
|
||||||
|
}
|
||||||
|
if(mFeatures.isEmpty()){
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
ArrayList<String> features = new ArrayList<>(config.getFeatures());
|
||||||
|
for (String feature : mFeatures) {
|
||||||
|
if (!features.contains(feature)) {
|
||||||
|
features.add(feature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
config.setFeatures(features);
|
||||||
|
return config;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -18,9 +18,10 @@ public class ProjectLauncher {
|
|||||||
mMainScriptFile = new File(mProjectDir, mProjectConfig.getMainScriptFile());
|
mMainScriptFile = new File(mProjectDir, mProjectConfig.getMainScriptFile());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void launch(ScriptEngineService service){
|
public void launch(ScriptEngineService service) {
|
||||||
ExecutionConfig config = new ExecutionConfig();
|
ExecutionConfig config = new ExecutionConfig();
|
||||||
config.setWorkingDirectory(mProjectDir);
|
config.setWorkingDirectory(mProjectDir);
|
||||||
|
config.getScriptConfig().setFeatures(mProjectConfig.getFeatures());
|
||||||
service.execute(new JavaScriptFileSource(mMainScriptFile), config);
|
service.execute(new JavaScriptFileSource(mMainScriptFile), config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.stardust.autojs.project
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class ScriptConfig(
|
||||||
|
@SerializedName("useFeatures") var features: List<String>,
|
||||||
|
@SerializedName("uiMode") var uiMode: Boolean
|
||||||
|
) {
|
||||||
|
constructor() : this(emptyList(), false)
|
||||||
|
|
||||||
|
fun hasFeature(feature: String): Boolean {
|
||||||
|
return features.contains(feature)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val FEATURE_CONTINUATION = "continuation"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -65,7 +65,7 @@ public class Dialogs {
|
|||||||
builder.content(content);
|
builder.content(content);
|
||||||
}
|
}
|
||||||
return ((BlockedMaterialDialog.Builder) builder).showAndGet();
|
return ((BlockedMaterialDialog.Builder) builder).showAndGet();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Context getContext() {
|
private Context getContext() {
|
||||||
if (mThemeWrapper != null)
|
if (mThemeWrapper != null)
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ public class VMBridge_custom extends VMBridge_jdk15 {
|
|||||||
protected Object newInterfaceProxy(Object proxyHelper, ContextFactory cf, InterfaceAdapter adapter, Object target, Scriptable topScope) {
|
protected Object newInterfaceProxy(Object proxyHelper, ContextFactory cf, InterfaceAdapter adapter, Object target, Scriptable topScope) {
|
||||||
Context context = Context.getCurrentContext();
|
Context context = Context.getCurrentContext();
|
||||||
InterfaceAdapterWrapper adapterWrapper = new InterfaceAdapterWrapper(adapter, context);
|
InterfaceAdapterWrapper adapterWrapper = new InterfaceAdapterWrapper(adapter, context);
|
||||||
RhinoJavaScriptEngine engine = RhinoJavaScriptEngine.getEngineOfContext(context);
|
RhinoJavaScriptEngine engine = RhinoJavaScriptEngine.Companion.getEngineOfContext(context);
|
||||||
// --- The following code is copied from super class --
|
// --- The following code is copied from super class --
|
||||||
Constructor<?> c = (Constructor) proxyHelper;
|
Constructor<?> c = (Constructor) proxyHelper;
|
||||||
InvocationHandler handler = (proxy, method, args) -> {
|
InvocationHandler handler = (proxy, method, args) -> {
|
||||||
@@ -50,6 +50,8 @@ public class VMBridge_custom extends VMBridge_jdk15 {
|
|||||||
try {
|
try {
|
||||||
Object result = adapterWrapper.invoke(cf, target, topScope, proxy, method, args);
|
Object result = adapterWrapper.invoke(cf, target, topScope, proxy, method, args);
|
||||||
return castReturnValue(method, result);
|
return castReturnValue(method, result);
|
||||||
|
} catch (ContinuationPending pending) {
|
||||||
|
return defaultValue(method.getReturnType());
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
// notify the script thread to exit
|
// notify the script thread to exit
|
||||||
@@ -143,6 +145,7 @@ public class VMBridge_custom extends VMBridge_jdk15 {
|
|||||||
|
|
||||||
|
|
||||||
public Object invokeImpl(Context cx, Object target, Scriptable topScope, Object thisObject, Method method, Object[] args) {
|
public Object invokeImpl(Context cx, Object target, Scriptable topScope, Object thisObject, Method method, Object[] args) {
|
||||||
|
cx.isContinuationsTopCall = true;
|
||||||
return mInterfaceAdapter.invokeImpl(cx, target, topScope, thisObject, method, args);
|
return mInterfaceAdapter.invokeImpl(cx, target, topScope, thisObject, method, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user